おそらく、すべてのプログラマーは遅かれ早かれ自分のコードの品質について考え始めます。そして、おそらく、開発者のかなりの半分が常に彼らに不満を持っていると言っても、私は誤解されないでしょう。私も自分のコードが好きになることはめったにありませんでした。関数を短くすることができたようです。不要なネストも削除するとよいでしょう。テストやドキュメントを書くのは素晴らしいことですが、それらのための時間はほとんどありませんでした。
当然のことながら、私は自分のコードをより良くする方法を見つけようとして、本やあらゆる種類の記事を読むことに多くの時間を費やしました。しかし、絵は足し合わなかった。本や記事の推奨事項が一般的すぎて矛盾することもあったか、それとも私の中にありましたが、努力にもかかわらず、ほとんど結果がありませんでした。
HowToCodeコースを受講した後、状況は根本的に変わりました[モデレーターによってリンクが削除されました。ルールを破る]。このコースでは、体系的で、すべての優れたものと同様に、分析、設計、文書化、テスト、およびコード開発をまとめた、開発へのシンプルで美しいアプローチについて説明します。コース全体は、機能パラダイムとScheme言語(Lisp方言)の使用に基づいて構築されていますが、推奨事項は他の言語にも非常に適用可能であり、私がそれらを適応させようとしたJavaScriptとTypeScriptには、一般的に適用されます。結構です。
私は本当に結果が好きでした:
最初に、ついに私のコードが読みやすくなり、明確なドキュメントとテストが登場しました。
第二に、TDDアプローチは機能し、私はいくつかのアプローチを取りましたが、どのような方法でもそれに従うことを開始できませんでした
-, : , , ,
: - , , -
, , , - , , . - .
, .
, , - .
, , .
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 .
その素晴らしい瞬間が到来したら、アプリケーションを起動して、それがどのように機能するかを楽しむだけです。エラーを見逃したり、シナリオを忘れて実現しなかったりしてもクラッシュしませんが、機能します。
これは、一般的に、全体的なアプローチです。難しいことではありませんが、習慣と規律が必要です。他のトリッキーなビジネスと同様に、最大の課題は、最初のカップルで始めて、やめたいという衝動に抵抗することです。これが成功した場合、しばらくすると、テストやドキュメントがなく、長く理解できない関数を使用して、昔ながらの方法でコードを作成する方法について考えたくなくなるでしょう。がんばろう!