HowToCode - Mengadaptasi pendekatan sistem untuk pengembangan React dan TypeScript

Mungkin setiap programmer cepat atau lambat mulai memikirkan kualitas kodenya. Dan, kemungkinan besar, saya tidak akan salah jika saya mengatakan bahwa sebagian besar pengembang selalu tidak senang dengan mereka. Saya juga jarang menyukai kode saya: fungsinya, tampaknya, dapat dipersingkat, akan menyenangkan juga untuk menghapus penumpukan yang tidak perlu. Akan sangat bagus untuk menulis tes dan dokumentasi, tetapi hampir tidak pernah punya waktu untuk itu.





Biasanya, saya menghabiskan banyak waktu untuk membaca buku dan semua jenis artikel, mencoba mencari cara untuk membuat kode saya lebih baik. Tapi gambar itu tidak sesuai. Entah rekomendasi dalam buku atau artikel terlalu umum dan terkadang kontradiktif, atau memang ada dalam diri saya, tetapi, terlepas dari upaya itu, hasilnya kecil.





Situasi berubah drastis setelah saya mengikuti kursus HowToCode [tautan dihapus oleh moderator, sejak itu melanggar aturan] . Kursus ini menjelaskan pendekatan pengembangan yang sistematis dan, seperti semua yang brilian, yang sederhana dan indah, yang menyatukan analisis, desain, dokumentasi, pengujian, dan pengembangan kode. Seluruh kursus dibangun di atas penggunaan paradigma fungsional dan bahasa Skema (dialek Lisp), namun, rekomendasinya cukup berlaku untuk bahasa lain, dan untuk JavaScript dan TypeScript, yang saya coba untuk mengadaptasinya, mereka umumnya baik.





Saya sangat menyukai hasilnya:





  • Pertama, akhirnya kode saya dapat dibaca, dokumentasi dan tes yang jelas muncul.





  • Kedua, pendekatan TDD berhasil, yang mana saya mengambil beberapa pendekatan, tetapi tidak dapat mulai mengikutinya dengan cara apa pun





  • -, : , , ,





  • : - , , -





  • , , , - , , . - .





, .





, , - .





, , .





3 :

















, , , , .





. : , Jira . .





, 2 : . , - . , - , , .





, , . .





:





1.





2. , .





1.

, :









  • : , , - -









, . - , , , , - , .





, :  " web- , , . ."





, , . , , , ( ).









, , - . :









, , , . :





, , , . , - :





, , - . 





2. ,

: 3 , : , .









- , .  , , :





  • : , , , , ..





  • , , ,





  • : , ..









, . :





  • ,





  • ,









, , :









- . , - , . :













  • , ..









: ? , , , , , - .





:





  • :





  • , , , , ,





  • , , ,





  • , , .





, :









, - , . , , .





:





  • : , , , ..





  • :









  • ..





, , :













, .





:





  1. -,





  2. -, ,





  3. -, , , . , , , .





, . , , , .





- .





, , , . 





?





  1. -, . , , . , , .





  2. -, TypeScript, .





  3. -, , , unit-.





:













  1. - , .





  2. - .





. 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>;

}
      
      



, - , , .





, .





, , . 





, - :





  1. . - , :













    • ,





  2. ,





  3. . .





  4. .





  5. , :









    1. (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>
    }
}
      
      



:





  1. App "", AppProps





  2. AppState , ,





  3. 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 -:





  1. ,





  2. , -





  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 , .  :





  1. loadData ,





  2. ( )





  3. ,





- .





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);
    });
      
      



:









  1. . , . ,









, , 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";
}
      
      



, , , ":", , :





  1. , , , 00:00





  2. , ,





  3. 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 .





Ketika momen indah itu tiba, Anda cukup meluncurkan aplikasi dan menikmati cara kerjanya. Itu tidak crash karena kesalahan yang terlewat atau skenario yang terlupakan dan tidak direalisasikan, tetapi hanya berfungsi.





Ini, secara umum, merupakan keseluruhan pendekatan. Itu tidak sulit, tetapi membutuhkan kebiasaan dan disiplin. Seperti halnya bisnis rumit lainnya, tantangan terbesar adalah memulai dan menahan dorongan untuk berhenti pada pasangan pertama. Jika ini berhasil, maka setelah beberapa saat Anda bahkan tidak ingin memikirkan tentang cara menulis kode dengan cara lama: tanpa tes, dokumentasi dan dengan fungsi yang lama tidak dapat dipahami. Semoga berhasil!








All Articles