Wahrscheinlich beginnt jeder Programmierer früher oder später, über die Qualität seines Codes nachzudenken. Und höchstwahrscheinlich werde ich mich nicht irren, wenn ich sage, dass eine gute Hälfte der Entwickler immer mit ihnen unzufrieden ist. Ich mochte meinen Code auch selten: Die Funktionen konnten anscheinend kürzer gemacht werden, es wäre schön, auch unnötige Verschachtelungen zu entfernen. Es wäre toll, Tests und Dokumentationen zu schreiben, hatte aber fast nie Zeit dafür.
Natürlich habe ich viel Zeit damit verbracht, Bücher und Artikel aller Art zu lesen und herauszufinden, wie ich meinen Code verbessern kann. Aber das Bild stimmte nicht. Entweder waren die Empfehlungen in Büchern oder Artikeln zu allgemein und manchmal widersprüchlich, oder es war in mir, aber trotz der Bemühungen gab es wenig Ergebnis.
Die Situation hat sich radikal geändert, nachdem ich den HowToCode-Kurs besucht habe [Link vom Moderator entfernt, seitdem bricht die Regeln] . Der Kurs beschreibt einen systematischen und wie alles Geniale einen einfachen und schönen Entwicklungsansatz, der Analyse, Design, Dokumentation, Test und Codeentwicklung zusammenbringt. Der gesamte Kurs basiert auf der Verwendung des Funktionsparadigmas und der Schemasprache (ein Lisp-Dialekt). Die Empfehlungen gelten jedoch durchaus für andere Sprachen und für JavaScript und TypeScript, an die ich sie anpassen wollte, im Allgemeinen fein.
Die Ergebnisse haben mir sehr gut gefallen:
Zuerst, endlich wurde mein Code lesbar, klare Dokumentation und Tests erschienen.
Zweitens hat der TDD-Ansatz funktioniert, zu dem ich mehrere Ansätze gewählt habe, den ich jedoch in keiner Weise verfolgen konnte
-, : , , ,
: - , , -
, , , - , , . - .
, .
, , - .
, , .
3 :
, , , , .
. : , Jira . .
, 2 : . , - . , - , , .
, , . .
:
1.
2. , .
1.
, :
: , , - -
, . - , , , , - , .
, : " web- , , . ."
, , . , , , ( ).
, , - . :
, , , . :
, , , . , - :
, , - .
2. ,
: 3 , : , .
- , . , , :
: , , , , ..
, , ,
: , ..
, . :
,
,
-
, , :
- . , - , . :
, ..
: ? , , , , , - .
:
:
, , , , ,
, , ,
, , .
, :
, - , . , , .
:
: , , , ..
:
-
..
, , :
, .
:
-,
-, ,
-, , , . , , , .
, . , , , .
- .
, , , .
?
-, . , , . , , .
-, TypeScript, .
-, , , unit-.
:
- , .
- .
. TypeScript JSDoc, - . - React JS, , (props) (state), React. , , , .
: HowToCode , - , . , , .
, .
, , Redux, .
. . , AppState - :
export interface AppState {}
. , , , . :
|
|
|
|
|
|
|
title |
|
|
+ |
|
|
backendAddress |
|
|
+ |
|
|
isLoading |
|
|
+ |
true - false - |
|
group |
|
Group |
- |
|
|
loadData |
|
|
+ |
|
:
export interface AppState {
title: string;
backendAddress: string;
isLoading: boolean;
group?: Group;
loadData: Function;
}
TypeScript , , , . , , . JavaScript - JSDoc.
/**
*
* @prop title -
* @prop backendAddress -
* @prop isLoading - (true - , false - )
* @prop group - . group
* @method loadData -
*/
export interface AppState {
title: string;
backendAddress: string;
isLoading: boolean;
group?: Group;
loadData: Function;
}
AppState Group. , AppState , - , , . . , . .
, , TODO - IDE TODO
/**
*
* @prop title -
* @prop backendAddress -
* @prop isLoading - (true - , false - )
* @prop group - . group
* @method loadData -
*/
export interface AppState {
title: string;
backendAddress: string;
isLoading: boolean;
group?: Group;
loadData: Function;
}
/**
*
*/
//TODO
export interface Group {
}
, .
, , - . , unit-, , - . , group - , . - :
/**
*
* @prop title -
* @prop backendAddress -
* @prop isLoading - (true - , false - )
* @prop group - . group
* @method loadData -
*/
export interface AppState {
title: string;
backendAddress: string;
isLoading: boolean;
group?: Group;
loadData: Function;
}
// 1
const appState1: AppState = {
title: " 1",
backendAddress: "/view_doc.html",
isLoading: true,
group: undefined,
loadData: () => {}
}
// 2
const appState2: AppState = {
title: " 2",
backendAddress: "/view_doc_2.html",
isLoading: false,
group: group1, //
loadData: () => {}
}
/**
*
*/
//TODO
export interface Group {
}
//TODO
const group1 = {}
, , , - . , , , - , "".
TODO , , , , .
. , , , , - :
export default abstract class AbstractService {
/**
*
* @fires get_group_data - ,
* @returns
*/
abstract getGroupData(): Promise<Group>;
}
, - , , .
, .
, , .
, - :
. - , :
,
,
. .
.
, :
(TODO),
,
React - , .
, , - , .
1 -
- , :
,
, , .
TypeScript - :
export const getWorkDuration = (worktimeFrom: string, worktimeTo: string): string => {
return "6 18";
}
:
getWorkDuration - , ,
worktimeFrom: string, worktimeTo: string - .
: string -
return "6 18" - ,
, , - unit - , .
2 : - . :
:
const componentName = (props: PropsType) => { return <h1>componentName</h1> }
:
class componentName extends React.Component<PropsType, StateType>{
state = {
//
}
render() {
return <h1>componentName</h1>
}
}
:
PropsType -
StateType -
- , , .
, App. , , , -. :
interface AppProps {}
export default class App extends Component<AppProps, AppState> {
state = {
title: " ",
backendAddress: "",
isLoading: true,
loadData: this.loadData.bind(this)
}
/**
*
*/
//TODO
loadData() {
}
render() {
return <h1>App</h1>
}
}
:
App "", AppProps
AppState , ,
loadData, , TODO,
2 -
, , , . JSDoc, , , .
, , , , , , . , :
/**
*
* , , -
* @param worktimeFrom - : ( 00:00 23:59)
* @param worktimeTo - : ( 00:00 23:59)
* @return Y?, 6 18 5,
*/
//TODO
export const getWorkDuration = (worktimeFrom: string, worktimeTo: string): string => {
return "6 18";
}
TODO, , .
- , , , , . , , , , - , - .
3.
, , . - unit-. , :
unit- , , - ,
unit- , . ,
, .
. , .
" " - , .
, , . "" enum. :
type TrafficLights = "" | "" | "";
, , TrafficLights : , , - :
function trafficLightsFunction (trafficLights: TrafficLights) {
switch (trafficLights) {
case "":
...
case "":
...
case "":
...
}
}
. , TrafficLights - , , "..." , .
, . , , , , 3 . .
, - , .
, - . , - , - . " " . , , , , . .
:
№ |
|
|
|
|
1 |
|
, . |
|
1 - 2 (true / false) - 1 , 0 |
2 |
|
, . |
.. |
, , , . , 100- , , 4 : 1 - 25, 26 - 50, 51 - 75, 76 - 100 4 . |
3 |
|
|
(0 - 300]
.. |
:
|
4 |
|
, , |
? , - , , . , . . " " - . - , , . |
, , -, . 2 :
- , . |
5 |
() |
, |
"" : id
.. |
2 . |
6 |
|
, |
, |
, : , , , , 2 |
, .
/**
*
* , , -
* @param worktimeFrom - : ( 00:00 23:59)
* @param worktimeTo - : ( 00:00 23:59)
* @return Y?, 6 18 5,
*/
//TODO
export const getWorkDuration = (worktimeFrom: string, worktimeTo: string): string => {
return "6 18";
}
, . string , - , :, , 00:00 23:59. , . , . 3 -:
,
, -
-
, . -, , 3 , , , 5
№ |
|
worktimeFrom |
worktimeTo |
|
1 |
worktimeFrom |
, , "24:00" |
, "18:00" |
|
2 |
worktimeFrom |
, "18:00" |
, , "24:00" |
|
3 |
, worktimeFrom < worktimeTo |
, worktimeTo, "00:00" |
, worktimeFrom, , "23:59" |
23 59 |
4 |
, worktimeFrom > worktimeTo |
, worktimeTo, "18:49" |
, worktimeFrom, , "10:49" |
16 |
5 |
worktimeFrom = worktimeTo |
, , "01:32" |
, , "01:32" |
0 |
- , : . . Jest Enzyme - React JS. , :
describe(' ', () => {
it(' , 0', ()=>{
const result = getWorkDuration("01:32", "01:32");
expect(result).toBe("0");
});
//
...
});
- : , , . -, , , - enzyme.
App. :
interface AppProps {}
export default class App extends Component<AppProps, AppState> {
state = {
title: " ",
backendAddress: "",
isLoading: true,
loadData: this.loadData.bind(this)
}
/**
*
*/
//TODO
loadData() {
}
render() {
return <h1>App</h1>
}
}
, , :
/**
*
* @prop title -
* @prop backendAddress -
* @prop isLoading - (true - , false - )
* @prop group - . group
* @method loadData -
*/
export interface AppState {
title: string;
backendAddress: string;
isLoading: boolean;
group?: Group;
loadData: Function;
}
, :
-, , .
-, . , group , , - . , "".
, , :
() 2 ,
, . , : .
, 4 :
2 - , , "" , ,
2 - , ,
, , 2 .
loadData - , , - , - . , , , , , .
- loadData :
import React from 'react';
import Enzyme, { mount, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
import App from './App';
describe('App', () => {
test(' App , loadData', () => {
// loadData
const loadData = jest.spyOn(App.prototype, 'loadData');
//
const wrapper = mount(<App></App>);
// loadData
expect(loadData.mock.calls.length).toBe(1);
});
}
enzyme , . :
loadData ,
( )
,
- .
test(' , ', () => {
//
const wrapper = mount(<App></App>);
//
wrapper.setState({
title: " 1",
backendAddress: "/view_doc.html",
isLoading: true,
group: undefined,
loadData: () => {}
})
//
//
expect(wrapper.find('h1').length).toBe(1);
expect(wrapper.find('h1').text()).toBe(" 1");
//,
expect(wrapper.find(Spinner).length).toBe(1);
//,
expect(wrapper.find(Group).length).toBe(0);
});
:
. , . ,
, , 2 , :
-
. , , .
, , .
:
test(' , . ', () => {
const wrapper = mount(<App></App>);
wrapper.setState({
title: " 2",
backendAddress: "/view_doc_2.html",
isLoading: false,
group: {
id: "1",
name: " 1",
listOfCollaborators: []
},
loadData: () => {}
})
expect(wrapper.find('h1').length).toBe(1);
expect(wrapper.find('h1').text()).toBe(" 2");
expect(wrapper.find(Spinner).length).toBe(0);
expect(wrapper.find(Group).length).toBe(1);
});
, , , , . , , , .
, , . , .
4 5.
, . , , , . , :
-, ,
-, , Knowledge Shift ( ).
. , , , . , , - .
, . :
/**
*
* , , -
* @param worktimeFrom - : ( 00:00 23:59)
* @param worktimeTo - : ( 00:00 23:59)
* @return Y?, 6 18 5,
*/
//TODO
export const getWorkDuration = (worktimeFrom: string, worktimeTo: string): string => {
return "6 18";
}
, , , ":", , :
, , , 00:00
, ,
X Y?,
:
":", ..
.
:
/**
*
* , , -
* @param worktimeFrom - : ( 00:00 23:59)
* @param worktimeTo - : ( 00:00 23:59)
* @return Y?, 6 18 5,
*/
export const getWorkDuration = (worktimeFrom: string, worktimeTo: string): string => {
const worktimeFromInMinutes = getWorktimeToMinutes(worktimeFrom);
const worktimeToInMinutes = getWorktimeToMinutes(worktimeTo);
const minutesDiff = calcDiffBetweenWorktime(worktimeFromInMinutes, worktimeToInMinutes);
return convertDiffToString(minutesDiff);
}
/**
* c ,
* @param worktimeFrom - : ( 00:00 23:59)
* @returns , 00 00
*/
//TODO
export const getWorktimeToMinutes = (worktime: string): number => {
return 0;
}
/**
*
* @param worktimeFrom - ,
* @param worktimeTo - ,
* @returns
*/
//TODO
export const calcDiffBetweenWorktime = (worktimeFrom: number, worktimeTo: number): number => {
return 0;
}
/**
* Y?
* @param minutes -
* @returns Y?, 6 18 5
*/
//TODO
export const convertDiffToString = (minutes: number): string => {
return "6 18";
}
, , , . . , TODO, . . , , .
, . , , , , - , .
Knowledge Shift
, , Knowledge Shift.
, , , , , , - () . , , , .
, , - , , . Knowledge Domain Shift Knowledge Shift.
, , , , .
, , - App:
export default class App extends Component<AppProps, AppState> {
state = {
title: " ",
backendAddress: "",
isLoading: true,
group: undefined,
loadData: this.loadData.bind(this)
}
/**
*
*/
//TODO
loadData() {}
componentDidMount() {
// loadData
this.loadData();
}
render() {
const {isLoading, group, title} = this.state;
return (
<div className="container">
<h1>{title}</h1>
{
isLoading ?
<Spinner/>
// Group
: <Group group={group}></Group>
}
</div>
);
}
}
componentDidMount, . render. , , - , Group.
, , c . group , , App - , . , , , , , , .
, , . , , TODO : + . , TODO .
Wenn dieser wundervolle Moment eintrifft, starten Sie einfach die Anwendung und genießen, wie sie einfach funktioniert. Es stürzt nicht aufgrund verpasster Fehler oder vergessener und nicht realisierter Szenarien ab, sondern funktioniert einfach.
Dies ist im Allgemeinen der gesamte Ansatz. Es ist nicht schwierig, aber es erfordert Gewohnheit und Disziplin. Wie bei jedem kniffligen Geschäft besteht die größte Herausforderung darin, loszulegen und dem Drang zu widerstehen, bei den ersten Paaren aufzuhören. Wenn dies gelingt, werden Sie nach einer Weile nicht einmal mehr darüber nachdenken wollen, wie man Code auf altmodische Weise schreibt: ohne Tests, Dokumentation und mit langen unverständlichen Funktionen. Viel Glück!