แนวทางปฏิบัติที่ดีที่สุดสำหรับแอปพลิเคชันเชิงมุมที่สะอาดและมีประสิทธิภาพ

ฉันได้ทำงานเกี่ยวกับแอปพลิเคชันขนาดใหญ่ที่ Trade Me, นิวซีแลนด์มาสองสามปีแล้ว ในช่วงไม่กี่ปีที่ผ่านมาทีมงานของเราได้ทำการปรับปรุงแอปพลิเคชันของเราทั้งในด้านมาตรฐานการเข้ารหัสและประสิทธิภาพเพื่อให้อยู่ในสถานะที่ดีที่สุด

บทความนี้แสดงแนวทางปฏิบัติที่เราใช้ในแอปพลิเคชันของเราและเกี่ยวข้องกับ Angular, Typescript, RxJs และ @ ngrx / store นอกจากนี้เราจะปฏิบัติตามหลักเกณฑ์การเข้ารหัสทั่วไปเพื่อช่วยให้แอปพลิเคชันสะอาดขึ้น

1) ติดตามโดย

เมื่อใช้ ngFor ในการวนซ้ำอาร์เรย์ในเทมเพลตให้ใช้กับฟังก์ชั่น trackBy ซึ่งจะส่งกลับตัวระบุเฉพาะสำหรับแต่ละรายการ

ทำไม?

เมื่ออาเรย์เปลี่ยนไป Angular จะแสดงทรี DOM ทั้งหมดอีกครั้ง แต่ถ้าคุณใช้ trackBy Angular จะรู้ว่าองค์ประกอบใดที่มีการเปลี่ยนแปลงและจะทำการเปลี่ยนแปลง DOM สำหรับองค์ประกอบเฉพาะนั้นเท่านั้น

สำหรับคำอธิบายโดยละเอียดเกี่ยวกับเรื่องนี้โปรดอ้างอิงจากบทความนี้โดย Netanel Basal

ก่อน

  • {{item}}
  • หลังจาก

    // ในเทมเพลต
  • {{item}}
  • // ในองค์ประกอบ
    trackByFn (ดัชนีรายการ) {
       ส่งคืนรายการ. id; // รหัสเฉพาะที่สอดคล้องกับรายการ
    }

    2) const vs let

    เมื่อประกาศตัวแปรใช้ const เมื่อค่าไม่ได้ถูกกำหนดใหม่

    ทำไม?

    การใช้ let และ const ตามความเหมาะสมทำให้เจตนาของการประกาศชัดเจนยิ่งขึ้น นอกจากนี้ยังจะช่วยในการระบุปัญหาเมื่อค่าถูกกำหนดใหม่ให้กับค่าคงที่โดยไม่ได้ตั้งใจโดยการโยนข้อผิดพลาดในเวลารวบรวม นอกจากนี้ยังช่วยปรับปรุงการอ่านรหัส

    ก่อน

    ให้รถยนต์ = 'รถยนต์ที่น่าหัวเราะ';
    ให้ myCar = `$ {car} ของฉัน ';
    ให้ yourCar = `$ {car} ของคุณ;
    if (iHaveMoreThanOneCar) {
       myCar = `$ {myCar} s`;
    }
    ถ้า (youHaveMoreThanOneCar) {
       yourCar = `$ {youCar} s`;
    }

    หลังจาก

    // ค่าของรถไม่ได้ถูกกำหนดใหม่ดังนั้นเราสามารถทำให้มันเป็นค่าคงที่ได้
    const car = 'รถยนต์ที่น่าหัวเราะ';
    ให้ myCar = `$ {car} ของฉัน ';
    ให้ yourCar = `$ {car} ของคุณ;
    if (iHaveMoreThanOneCar) {
       myCar = `$ {myCar} s`;
    }
    ถ้า (youHaveMoreThanOneCar) {
       yourCar = `$ {youCar} s`;
    }

    3) ผู้ประกอบการวางท่อ

    ใช้โอเปอเรเตอร์ที่สามารถใช้ได้เมื่อใช้ตัวดำเนินการ RxJs

    ทำไม?

    ตัวดำเนินการไปป์เป็นความหมายที่สั่นไหวของต้นไม้มีความหมายเฉพาะรหัสที่เราต้องใช้ในการดำเนินการเท่านั้นที่จะถูกรวมไว้

    นอกจากนี้ยังทำให้ง่ายต่อการระบุตัวดำเนินการที่ไม่ได้ใช้ในไฟล์

    หมายเหตุ: ต้องใช้รุ่นเชิงมุม 5.5+

    ก่อน

    นำเข้า 'rxjs / เพิ่ม / ผู้ประกอบการ / แผนที่';
    นำเข้า 'rxjs / เพิ่ม / ผู้ประกอบการ / ใช้';
    iAmAnObservable
        .map (value => value.item)
        .take (1);

    หลังจาก

    นำเข้า {map, ใช้} จาก 'rxjs / โอเปอเรเตอร์';
    iAmAnObservable
        .ท่อ(
           แผนที่ (value => value.item)
           ใช้ (1)
         );

    4) แยก API การแฮ็ก

    ไม่ใช่ APIs ทั้งหมดที่เป็น bullet bullet - บางครั้งเราจำเป็นต้องเพิ่มตรรกะบางอย่างในรหัสเพื่อชดเชยข้อบกพร่องใน API แทนที่จะมีการแฮ็กในองค์ประกอบที่พวกเขาต้องการมันจะดีกว่าที่จะแยกพวกเขาในที่เดียว - ในบริการและใช้บริการจากส่วนประกอบ

    ทำไม?

    สิ่งนี้จะช่วยให้แฮ็ก“ ใกล้เคียงกับ API” มากที่สุดดังนั้นจึงใกล้เคียงกับที่คำขอเครือข่ายทำมากที่สุด วิธีนี้รหัสของคุณน้อยลงจะจัดการกับรหัสที่ไม่แฮ็ก นอกจากนี้ยังเป็นสถานที่แห่งหนึ่งที่แฮ็กทั้งหมดอาศัยอยู่และหาง่ายกว่า เมื่อแก้ไขข้อบกพร่องใน APIs จะเป็นการง่ายกว่าที่จะมองหาพวกมันในไฟล์เดียวแทนที่จะมองหาแฮ็กที่สามารถแพร่กระจายข้ามโค๊ดเบสได้

    คุณยังสามารถสร้างแท็กที่กำหนดเองเช่น API_FIX คล้ายกับสิ่งที่ต้องทำและติดแท็กการแก้ไขด้วยเพื่อให้ง่ายต่อการค้นหา

    5) สมัครสมาชิกในเทมเพลต

    หลีกเลี่ยงการสมัครรับข้อมูลที่สังเกตได้จากส่วนประกอบและแทนที่จะสมัครรับข้อมูลที่สังเกตได้จากเทมเพลต

    ทำไม?

    ท่อ async ยกเลิกการสมัครสมาชิกโดยอัตโนมัติและทำให้รหัสง่ายขึ้นโดยไม่จำเป็นต้องจัดการการสมัครด้วยตนเอง นอกจากนี้ยังลดความเสี่ยงของการลืมสมัครสมาชิกส่วนประกอบโดยไม่ตั้งใจซึ่งจะทำให้หน่วยความจำรั่ว ความเสี่ยงนี้สามารถบรรเทาได้ด้วยการใช้กฎผ้าสำลีเพื่อตรวจจับสิ่งที่น่าติดตาม

    สิ่งนี้จะหยุดการทำงานของคอมโพเนนต์จากสถานะและแนะนำบักข้อมูลที่ได้รับการกลายพันธุ์นอกการสมัครสมาชิก

    ก่อน

    // เทมเพลต

    {{textToDisplay}}

    // องค์ประกอบ
    iAmAnObservable
        .ท่อ(
           แผนที่ (value => value.item)
           takeUntil (this._destroyed $)
         )
        .subscribe (รายการ => this.textToDisplay = รายการ);

    หลังจาก

    // เทมเพลต

    {{textToDisplay $ | async}}

    // องค์ประกอบ
    this.textToDisplay $ = iAmAnObservable
        .ท่อ(
           แผนที่ (value => value.item)
         );

    6) ล้างการสมัครสมาชิก

    เมื่อสมัครรับข้อมูลที่ควรสังเกตให้แน่ใจว่าคุณได้ยกเลิกการสมัครรับข้อมูลอย่างเหมาะสมโดยใช้ตัวดำเนินการเช่น take, takeUntil ฯลฯ

    ทำไม?

    ความล้มเหลวในการยกเลิกการสมัครจากสิ่งที่สังเกตได้จะนำไปสู่การรั่วไหลของหน่วยความจำที่ไม่ต้องการเนื่องจากกระแสข้อมูลที่ตรวจพบถูกเปิดทิ้งไว้อาจเป็นไปได้แม้หลังจากองค์ประกอบถูกทำลาย / ผู้ใช้นำทางไปยังหน้าอื่น

    ยิ่งไปกว่านั้นให้ใช้กฎการตรวจหาวัตถุที่ไม่ได้เป็นสมาชิก

    ก่อน

    iAmAnObservable
        .ท่อ(
           แผนที่ (value => value.item)
         )
        .subscribe (รายการ => this.textToDisplay = รายการ);

    หลังจาก

    ใช้ takeUntil เมื่อคุณต้องการฟังการเปลี่ยนแปลงจนกว่าสิ่งที่สังเกตได้อื่นจะปล่อยค่า:

    ส่วนตัว _destroyed $ = หัวเรื่องใหม่ ();
    public ngOnInit (): void {
        iAmAnObservable
        .ท่อ(
           แผนที่ (value => value.item)
          // เราต้องการฟัง iAmAnObservable จนกว่าส่วนประกอบจะถูกทำลาย
           takeUntil (this._destroyed $)
         )
        .subscribe (รายการ => this.textToDisplay = รายการ);
    }
    public ngOnDestroy (): void {
        this._destroyed $ .next ();
        this._destroyed $ .complete ();
    }

    การใช้หัวเรื่องส่วนตัวเช่นนี้เป็นรูปแบบในการจัดการการยกเลิกการสมัครสมาชิกสิ่งที่น่าสังเกตมากมายในองค์ประกอบ

    การใช้ใช้เมื่อคุณต้องการเพียงค่าแรกที่ปล่อยออกมาโดยที่สังเกตได้:

    iAmAnObservable
        .ท่อ(
           แผนที่ (value => value.item)
           ใช้ (1)
           takeUntil (this._destroyed $)
        )
        .subscribe (รายการ => this.textToDisplay = รายการ);

    บันทึกการใช้งานของ takeUntil ด้วย take ที่นี่ นี่คือเพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำที่เกิดขึ้นเมื่อการสมัครสมาชิกไม่ได้รับค่าก่อนที่ส่วนประกอบจะถูกทำลาย การสมัครรับข้อมูลจะยังคงดำเนินต่อไปจนกว่าจะได้รับค่าแรก แต่เนื่องจากส่วนประกอบได้ถูกทำลายไปแล้วจะไม่มีการรับค่าซึ่งนำไปสู่การรั่วไหลของหน่วยความจำ

    7) ใช้โอเปอเรเตอร์ที่เหมาะสม

    เมื่อใช้ตัวดำเนินการแบบแบนกับสิ่งที่คุณสังเกตได้ให้ใช้ตัวดำเนินการที่เหมาะสมกับสถานการณ์

    switchMap: เมื่อคุณต้องการละเว้นการปล่อยก่อนหน้านี้เมื่อมีการปล่อยใหม่

    mergeMap: เมื่อคุณต้องการจัดการกับการปล่อยทั้งหมดพร้อมกัน

    concatMap: เมื่อคุณต้องการจัดการกับสิ่งที่ปล่อยออกมาหลังจากที่ปล่อยออกมา

    exhaustMap: เมื่อคุณต้องการยกเลิกการปล่อยไอเสียใหม่ทั้งหมดในขณะที่ประมวลผล emisssion ก่อนหน้า

    สำหรับคำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับเรื่องนี้โปรดอ้างอิงจากบทความของ Nicholas Jamieson

    ทำไม?

    การใช้โอเปอเรเตอร์เดียวเมื่อทำได้แทนการผูกมัดกันหลาย ๆ โอเปอเรเตอร์เพื่อให้ได้เอฟเฟกต์เดียวกันอาจทำให้รหัสน้อยลงเพื่อส่งไปยังผู้ใช้ การใช้ตัวดำเนินการที่ไม่ถูกต้องอาจนำไปสู่พฤติกรรมที่ไม่พึงประสงค์

    8) โหลดขี้เกียจ

    เมื่อเป็นไปได้ให้พยายามโหลดโมดูลในแอปพลิเคชันเชิงมุมของคุณ การโหลดขี้เกียจคือเมื่อคุณโหลดบางอย่างเมื่อมีการใช้งานแล้วเท่านั้นเช่นการโหลดส่วนประกอบเฉพาะเมื่อมองเห็นได้เท่านั้น

    ทำไม?

    วิธีนี้จะลดขนาดของแอปพลิเคชันที่จะโหลดและสามารถปรับปรุงเวลาการบูตแอปพลิเคชันโดยไม่โหลดโมดูลที่ไม่ได้ใช้

    ก่อน

    // app.routing.ts
    {path: 'not-lazy-load-' ส่วนประกอบ: NotLazyLoadedComponent}

    หลังจาก

    // app.routing.ts
    {
      เส้นทาง: 'lazy-load',
      loadChildren: 'lazy-load.module # LazyLoadModule'
    }
    // lazy-load.module.ts
    นำเข้า {NgModule} จาก '@ angular / core';
    นำเข้า {CommonModule} จาก '@ angular / common';
    นำเข้า {RouterModule} จาก '@ angular / router';
    นำเข้า {LazyLoadComponent} จาก './lazy-load.component';
    @NgModule ({
      นำเข้า: [
        CommonModule,
        RouterModule.forChild ([
             {
                 เส้นทาง: '',
                 ส่วนประกอบ: LazyLoadComponent
             }
        ])
      ]
      ประกาศ: [
        LazyLoadComponent
      ]
    })
    คลาสการเอ็กซ์พอร์ต LazyModule {}

    9) หลีกเลี่ยงการสมัครสมาชิกภายในการสมัครสมาชิก

    บางครั้งคุณอาจต้องการค่าจากมากกว่าหนึ่งที่สังเกตได้เพื่อดำเนินการ ในกรณีนี้หลีกเลี่ยงการสมัครรับข้อมูลที่สังเกตได้ในบล็อกสมัครสมาชิกของบล็อกการติดตามอื่น ให้ใช้ตัวดำเนินการผูกมัดที่เหมาะสมแทน ตัวดำเนินการผูกมัดทำงานบนสิ่งที่สังเกตได้จากผู้ประกอบการก่อน ผู้ประกอบการบางอย่างคือ: กับล่าสุดจากรวมล่าสุด ฯลฯ

    ก่อน

    firstObservable $ .pipe (
       ใช้ (1)
    )
    .subscribe (firstValue => {
        secondObservable $ .pipe (
            ใช้ (1)
        )
        .subscribe (secondValue => {
            console.log (`ค่ารวมคือ: $ {firstValue} และ $ {secondValue}`);
        });
    });

    หลังจาก

    firstObservable $ .pipe (
        withLatestFrom (secondObservable $)
        () ครั้งแรก
    )
    .subscribe (([firstValue, secondValue]) => {
        console.log (`ค่ารวมคือ: $ {firstValue} และ $ {secondValue}`);
    });

    ทำไม?

    กลิ่นรหัส / ความสามารถในการอ่าน / ความซับซ้อน: ไม่ได้ใช้ RxJs อย่างเต็มที่แนะนำผู้พัฒนาไม่คุ้นเคยกับพื้นที่ผิวของ RxJs API

    ประสิทธิภาพการทำงาน: ถ้าผู้สังเกตการณ์เย็นมันจะทำการสมัครสมาชิกก่อนที่จะได้รับอนุญาตรอให้เสร็จสมบูรณ์จากนั้นเริ่มงานที่สองที่สังเกตได้ หากเป็นคำขอเครือข่ายก็จะแสดงเป็นซิงโครนัส / ฟอลส์

    10) หลีกเลี่ยงการใด ๆ ; พิมพ์ทุกอย่าง

    ประกาศตัวแปรหรือค่าคงที่ด้วยชนิดอื่นที่ไม่ใช่แบบใด ๆ

    ทำไม?

    เมื่อประกาศตัวแปรหรือค่าคงที่ใน Typescript โดยไม่ต้องพิมพ์การพิมพ์ของตัวแปร / ค่าคงที่จะถูกหักด้วยค่าที่ได้รับมอบหมาย สิ่งนี้จะทำให้เกิดปัญหาที่ไม่ตั้งใจ ตัวอย่างหนึ่งที่คลาสสิกคือ:

    const x = 1;
    const y = 'a';
    const z = x + y;
    console.log (`ค่าของ z คือ: $ {z}`
    // เอาท์พุท
    ค่าของ z คือ 1a

    สิ่งนี้อาจทำให้เกิดปัญหาที่ไม่พึงประสงค์เมื่อคุณคาดหวังว่า y จะเป็นตัวเลขเช่นกัน ปัญหาเหล่านี้สามารถหลีกเลี่ยงได้โดยการพิมพ์ตัวแปรอย่างเหมาะสม

    const x: number = 1;
    const y: number = 'a';
    const z: number = x + y;
    // นี่จะทำให้เกิดข้อผิดพลาดในการคอมไพล์โดยบอกว่า:
    พิมพ์ '"a' 'ไม่สามารถกำหนดให้พิมพ์' number '
    const y: จำนวน

    ด้วยวิธีนี้เราสามารถหลีกเลี่ยงข้อบกพร่องที่เกิดจากประเภทที่ขาดหายไป

    ข้อดีอีกประการของการมีงานพิมพ์ที่ดีในแอปพลิเคชันของคุณก็คือการทำให้การปรับโครงสร้างนั้นง่ายขึ้นและปลอดภัยยิ่งขึ้น

    ลองพิจารณาตัวอย่างนี้:

    public ngOnInit (): void {
        ให้ myFlashObject = {
            ชื่อ: 'ชื่อเด็ดของฉัน'
            อายุ: 'My cool age',
            loc: 'My cool location'
        }
        this.processObject (myFlashObject);
    }
    public processObject (myObject: any): void {
        console.log (`ชื่อ: $ {myObject.name}`);
        console.log (`อายุ: $ {myObject.age}`);
        console.log (`ที่ตั้ง: $ {myObject.loc}`);
    }
    // เอาท์พุท
    ชื่อ: ชื่อเด็ดของฉัน
    อายุ: อายุที่เจ๋งของฉัน
    สถานที่: สถานที่ที่น่าอยู่ของฉัน

    ให้เราบอกว่าเราต้องการที่จะเปลี่ยนชื่อสถานที่ให้บริการไปยังสถานที่ตั้งใน myFlashObject:

    public ngOnInit (): void {
        ให้ myFlashObject = {
            ชื่อ: 'ชื่อเด็ดของฉัน'
            อายุ: 'My cool age',
            สถานที่: 'ตำแหน่งที่น่าสนใจของฉัน'
        }
        this.processObject (myFlashObject);
    }
    public processObject (myObject: any): void {
        console.log (`ชื่อ: $ {myObject.name}`);
        console.log (`อายุ: $ {myObject.age}`);
        console.log (`ที่ตั้ง: $ {myObject.loc}`);
    }
    // เอาท์พุท
    ชื่อ: ชื่อเด็ดของฉัน
    อายุ: อายุที่เจ๋งของฉัน
    สถานที่ตั้ง: ไม่ได้กำหนด

    ถ้าเราไม่มีการพิมพ์บน myFlashObject มันคิดว่า loc คุณสมบัติบน myFlashObject นั้นไม่ได้ถูกนิยามไว้แทนที่จะว่ามันไม่ใช่คุณสมบัติที่ถูกต้อง

    หากเรามีการพิมพ์สำหรับ myFlashObject เราจะได้รับข้อผิดพลาดในการรวบรวมเวลาที่ดีดังแสดงด้านล่าง:

    พิมพ์ FlashObject = {
        ชื่อ: สตริง
        อายุ: สตริง
        สถานที่ตั้ง: สตริง
    }
    public ngOnInit (): void {
        ให้ myFlashObject: FlashObject = {
            ชื่อ: 'ชื่อเด็ดของฉัน'
            อายุ: 'My cool age',
            // ข้อผิดพลาดในการรวบรวม
            พิมพ์ '{ชื่อ: สตริง; อายุ: สตริง; loc: สตริง; } 'ไม่สามารถกำหนดให้พิมพ์' FlashObjectType '
            ตัวอักษรของวัตถุอาจระบุคุณสมบัติที่รู้จักเท่านั้นและ 'loc' ไม่มีอยู่ในประเภท 'FlashObjectType'
            loc: 'My cool location'
        }
        this.processObject (myFlashObject);
    }
    public processObject (myObject: FlashObject): void {
        console.log (`ชื่อ: $ {myObject.name}`);
        console.log (`อายุ: $ {myObject.age}`)
        // ข้อผิดพลาดในการรวบรวม
        คุณสมบัติ 'loc' ไม่มีอยู่ในประเภท 'FlashObjectType'
        console.log (`ที่ตั้ง: $ {myObject.loc}`);
    }

    หากคุณกำลังเริ่มโครงการใหม่มันมีค่าที่จะต้องเข้มงวด: เป็นจริงในไฟล์ tsconfig.json เพื่อเปิดใช้งานตัวเลือกการตรวจสอบประเภทที่เข้มงวดทั้งหมด

    11) ใช้ประโยชน์จากกฎผ้าสำลี

    tslint มีตัวเลือกต่าง ๆ ที่มีอยู่แล้วในตัวเช่น no-any, no-magic-numbers, no-console และอื่น ๆ ที่คุณสามารถกำหนดค่าใน tslint.json ของคุณเพื่อบังคับใช้กฎบางอย่างในฐานรหัสของคุณ

    ทำไม?

    การมีกฎผ้าสำลีในสถานที่หมายความว่าคุณจะได้รับข้อผิดพลาดที่ดีเมื่อคุณกำลังทำสิ่งที่คุณไม่ควรจะเป็น สิ่งนี้จะบังคับใช้อย่างสม่ำเสมอในแอปพลิเคชันและการอ่านของคุณ โปรดอ้างอิงกฎเพิ่มเติมที่คุณสามารถกำหนดที่นี่

    กฎผ้าสำลีบางกฎมาพร้อมกับการแก้ไขเพื่อแก้ไขข้อผิดพลาดผ้าสำลี หากคุณต้องการกำหนดค่ากฎผ้าสำลีที่กำหนดเองของคุณคุณสามารถทำได้เช่นกัน โปรดอ้างอิงบทความนี้โดย Craig Spence เกี่ยวกับวิธีการเขียนกฎผ้าสำลีที่กำหนดเองของคุณเองโดยใช้ TSQuery

    ก่อน

    public ngOnInit (): void {
        console.log ('ฉันเป็นข้อความบันทึกคอนโซลซุกซน');
        console.warn ('ฉันเป็นข้อความเตือนคอนโซลซุกซน');
        console.error ('ฉันเป็นข้อความแสดงข้อผิดพลาดของคอนโซลซน');
    }
    // เอาท์พุท
    ไม่มีข้อผิดพลาดพิมพ์ด้านล่างบนหน้าต่างคอนโซล:
    ฉันเป็นข้อความคอนโซลซุกซน
    ฉันเป็นข้อความเตือนคอนโซลซุกซน
    ฉันเป็นข้อความแสดงข้อผิดพลาดของคอนโซลที่ซุกซน

    หลังจาก

    // tslint.json
    {
        "กฎ": {
            .......
            "ไม่มีคอนโซล": [
                 ความจริง
                 "log", // ไม่อนุญาต console.log
                 "เตือน" // ไม่อนุญาต console.warn
            ]
       }
    }
    // ..component.ts
    public ngOnInit (): void {
        console.log ('ฉันเป็นข้อความบันทึกคอนโซลซุกซน');
        console.warn ('ฉันเป็นข้อความเตือนคอนโซลซุกซน');
        console.error ('ฉันเป็นข้อความแสดงข้อผิดพลาดของคอนโซลซน');
    }
    // เอาท์พุท
    ข้อผิดพลาดผ้าสำลีสำหรับคำสั่ง console.log และ console.warn และไม่มีข้อผิดพลาดสำหรับ console.error เนื่องจากไม่ได้กล่าวถึงในการกำหนดค่า
    ไม่อนุญาตให้เรียกไปที่ 'console.log'
    ไม่อนุญาตให้เรียกไปที่ 'console.warn'

    12) ส่วนประกอบนำมาใช้ใหม่ขนาดเล็ก

    แยกชิ้นส่วนที่สามารถนำกลับมาใช้ใหม่ในส่วนประกอบและทำให้เป็นชิ้นส่วนใหม่ ทำให้องค์ประกอบโง่ที่สุดเท่าที่จะเป็นไปได้ซึ่งจะทำให้มันทำงานได้ในหลาย ๆ สถานการณ์ การทำให้ส่วนประกอบเป็นใบ้หมายความว่าส่วนประกอบนั้นไม่มีตรรกะพิเศษใด ๆ ในนั้นและดำเนินการอย่างหมดจดโดยอิงตามอินพุตและเอาต์พุตที่ให้ไว้

    ตามกฎทั่วไปเด็กคนสุดท้ายในทรีองค์ประกอบจะเป็นคนโง่ที่สุด

    ทำไม?

    ส่วนประกอบที่นำมาใช้ซ้ำได้จะช่วยลดความซ้ำซ้อนของรหัสดังนั้นจึงง่ายต่อการบำรุงรักษาและเปลี่ยนแปลง

    ส่วนประกอบที่เป็นใบ้นั้นง่ายกว่าดังนั้นจึงมีข้อผิดพลาดน้อยกว่า องค์ประกอบที่โง่ทำให้คุณคิดหนักเกี่ยวกับ API องค์ประกอบสาธารณะและช่วยลดความกังวลที่หลากหลาย

    13) ส่วนประกอบควรจัดการกับตรรกะการแสดงผลเท่านั้น

    หลีกเลี่ยงการใช้ตรรกะใด ๆ นอกเหนือจากตรรกะการแสดงผลในองค์ประกอบของคุณเมื่อใดก็ตามที่คุณสามารถทำได้และทำให้องค์ประกอบจัดการเฉพาะกับตรรกะการแสดงผล

    ทำไม?

    ส่วนประกอบได้รับการออกแบบเพื่อวัตถุประสงค์ในการนำเสนอและควบคุมสิ่งที่ควรทำ ตรรกะทางธุรกิจใด ๆ ควรถูกแยกเป็นวิธีการ / บริการของตนเองตามความเหมาะสมโดยแยกตรรกะทางธุรกิจออกจากมุมมองตรรกะ

    ตรรกะทางธุรกิจมักจะง่ายต่อการทดสอบหน่วยเมื่อแยกออกไปยังบริการและสามารถนำกลับมาใช้โดยส่วนประกอบอื่น ๆ ที่ต้องการตรรกะทางธุรกิจเดียวกันที่ใช้

    14) หลีกเลี่ยงวิธีการที่ยาวนาน

    โดยทั่วไปวิธีการแบบยาวบ่งบอกว่าพวกเขากำลังทำสิ่งต่าง ๆ มากเกินไป ลองใช้หลักการความรับผิดชอบเดี่ยว วิธีการโดยรวมอาจทำสิ่งหนึ่ง แต่ภายในนั้นมีการดำเนินการอื่น ๆ ที่อาจเกิดขึ้นได้ เราสามารถแยกวิธีการเหล่านั้นเป็นวิธีการของตนเองและทำให้พวกเขาทำสิ่งหนึ่งและใช้พวกเขาแทน

    ทำไม?

    วิธีการที่ยาวนานนั้นยากต่อการอ่านทำความเข้าใจและบำรุงรักษา พวกเขายังมีแนวโน้มที่จะเป็นโรคจิตเนื่องจากการเปลี่ยนแปลงสิ่งหนึ่งอาจส่งผลกระทบต่อสิ่งอื่น ๆ มากมายในวิธีการนั้น พวกเขายังทำให้การปรับโครงสร้างใหม่ (ซึ่งเป็นสิ่งสำคัญในการสมัครใด ๆ ) ยาก

    บางครั้งสิ่งนี้วัดได้ว่าเป็น "ความซับซ้อนตามวัฏจักร" นอกจากนี้ยังมีกฎ TSLint ในการตรวจจับความซับซ้อนของวงจร / องค์ความรู้ซึ่งคุณสามารถใช้ในโครงการของคุณเพื่อหลีกเลี่ยงข้อผิดพลาดและตรวจจับกลิ่นโค้ดและปัญหาการบำรุงรักษา

    15) แห้ง

    อย่าทำซ้ำตัวเอง ตรวจสอบให้แน่ใจว่าคุณไม่มีรหัสเดียวกันที่คัดลอกไปยังที่ต่างๆใน codebase แตกรหัสการทำซ้ำและใช้แทนรหัสที่ทำซ้ำ

    ทำไม?

    การมีรหัสเดียวกันในหลาย ๆ ที่หมายความว่าถ้าเราต้องการเปลี่ยนแปลงตรรกะในรหัสนั้นเราต้องทำในหลาย ๆ ที่ สิ่งนี้ทำให้ยากต่อการบำรุงรักษาและยังมีแนวโน้มที่จะเป็นจุดบกพร่องที่เราอาจพลาดที่จะอัพเดทมันในทุกเหตุการณ์ ใช้เวลานานกว่าในการเปลี่ยนแปลงลอจิกและทดสอบว่าเป็นกระบวนการที่มีความยาวเช่นกัน

    ในกรณีเหล่านั้นให้แตกรหัสซ้ำแล้วใช้แทน นี่หมายถึงที่เดียวสำหรับการเปลี่ยนแปลงและสิ่งเดียวที่จะทดสอบ การมีรหัสที่ซ้ำกันน้อยกว่าส่งถึงผู้ใช้หมายความว่าแอปพลิเคชันจะเร็วขึ้น

    16) เพิ่มกลไกการแคช

    เมื่อทำการเรียก API การตอบสนองจากบางคนจะไม่เปลี่ยนแปลงบ่อยนัก ในกรณีเหล่านั้นคุณสามารถเพิ่มกลไกการแคชและเก็บค่าจาก API เมื่อมีการร้องขอไปยัง API เดียวกันอีกครั้งให้ตรวจสอบว่ามีค่าอยู่ในแคชหรือไม่หากมีให้ใช้ มิฉะนั้นให้ทำการเรียก API และแคชผลลัพธ์

    หากค่ามีการเปลี่ยนแปลง แต่ไม่บ่อยคุณสามารถแนะนำเวลาแคชที่คุณสามารถตรวจสอบว่ามันถูกแคชครั้งสุดท้ายและตัดสินใจว่าจะเรียก API หรือไม่

    ทำไม?

    การมีกลไกการแคชหมายถึงการหลีกเลี่ยงการเรียก API ที่ไม่ต้องการ เพียงทำการเรียก API เมื่อจำเป็นและหลีกเลี่ยงการทำซ้ำความเร็วของแอปพลิเคชั่นจะดีขึ้นเนื่องจากเราไม่ต้องรอเครือข่าย นอกจากนี้ยังหมายความว่าเราจะไม่ดาวน์โหลดข้อมูลเดิมซ้ำแล้วซ้ำอีก

    17) หลีกเลี่ยงตรรกะในแม่แบบ

    หากคุณมีตรรกะใด ๆ ในแม่แบบของคุณแม้ว่าจะเป็นส่วน & & ประโยคที่เรียบง่ายก็เป็นการดีที่จะแยกมันออกเป็นองค์ประกอบของมัน

    ทำไม?

    การมีตรรกะในเทมเพลตหมายความว่าไม่สามารถทดสอบหน่วยได้ดังนั้นจึงมีแนวโน้มที่จะเกิดข้อบกพร่องเมื่อเปลี่ยนรหัสเทมเพลต

    ก่อน

    // เทมเพลต
    

    สถานะ: นักพัฒนาซอฟต์แวร์

    // องค์ประกอบ
    public ngOnInit (): void {
        this.role = 'ผู้พัฒนา';
    }

    หลังจาก

    // เทมเพลต
    

    สถานะ: นักพัฒนาซอฟต์แวร์

    // องค์ประกอบ
    public ngOnInit (): void {
        this.role = 'ผู้พัฒนา';
        this.showDeveloperStatus = true;
    }

    18) เงื่อนไขควรปลอดภัย

    หากคุณมีตัวแปรชนิดสตริงที่สามารถมีชุดของค่าได้แทนที่จะประกาศเป็นประเภทสตริงคุณสามารถประกาศรายการค่าที่เป็นไปได้เป็นชนิด

    ทำไม?

    โดยการประกาศประเภทของตัวแปรอย่างเหมาะสมเราสามารถหลีกเลี่ยงข้อบกพร่องในขณะที่เขียนรหัสในช่วงเวลารวบรวมมากกว่าในระหว่างรันไทม์

    ก่อน

    myStringValue ส่วนตัว: สตริง;
    ถ้า (มันควรจะมี FirstValue) {
       myStringValue = 'ครั้งแรก';
    } อื่น {
       myStringValue = 'ที่สอง'
    }

    หลังจาก

    myStringValue ส่วนตัว: 'ครั้งแรก' | 'สอง';
    ถ้า (มันควรจะมี FirstValue) {
       myStringValue = 'ครั้งแรก';
    } อื่น {
       myStringValue = 'อื่น ๆ '
    }
    // นี่จะทำให้เกิดข้อผิดพลาดด้านล่าง
    ประเภท '"อื่น ๆ ' 'ไม่สามารถกำหนดให้พิมพ์'" First "| "สอง'
    (คุณสมบัติ) AppComponent.myValue: "First" | "สอง"

    ภาพใหญ่ขึ้น

    การจัดการของรัฐ

    พิจารณาใช้ @ ngrx / store เพื่อรักษาสถานะของแอปพลิเคชันของคุณและ @ ngrx / effects เป็นโมเดลผลข้างเคียงสำหรับการจัดเก็บ การเปลี่ยนแปลงสถานะถูกอธิบายโดยการกระทำและการเปลี่ยนแปลงนั้นกระทำโดยฟังก์ชันบริสุทธิ์ที่เรียกว่า reducers

    ทำไม?

    @ ngrx / store แยกตรรกะที่เกี่ยวข้องกับสถานะทั้งหมดในที่เดียวและทำให้สอดคล้องกันทั่วทั้งแอปพลิเคชัน นอกจากนี้ยังมีกลไกการบันทึกช่วยจำเมื่อเข้าถึงข้อมูลในร้านค้าที่นำไปสู่แอปพลิเคชันที่มีประสิทธิภาพมากขึ้น @ ngrx / store รวมกับกลยุทธ์การตรวจจับการเปลี่ยนแปลงของ Angular ทำให้แอปพลิเคชันเร็วขึ้น

    รัฐไม่เปลี่ยนรูป

    เมื่อใช้ @ ngrx / store ให้พิจารณาใช้ ngrx-store-freeze เพื่อทำให้สถานะไม่เปลี่ยนรูป ngrx-store-freeze ป้องกันไม่ให้สถานะกลายพันธุ์โดยการโยนข้อยกเว้น วิธีนี้จะหลีกเลี่ยงการกลายพันธุ์โดยไม่ตั้งใจของรัฐซึ่งนำไปสู่ผลที่ไม่พึงประสงค์

    ทำไม?

    สถานะการกลายพันธุ์ในส่วนประกอบจะนำไปสู่แอปที่มีพฤติกรรมไม่สอดคล้องกันทั้งนี้ขึ้นอยู่กับส่วนประกอบการสั่งซื้อที่ถูกโหลด มันทำลายรูปแบบทางจิตของรูปแบบการเปลี่ยนสี การเปลี่ยนแปลงสามารถจบลงแทนที่หากสถานะการเปลี่ยนแปลงและการจัดเก็บใหม่ การแยกข้อกังวล - ส่วนประกอบคือเลเยอร์มุมมองพวกเขาไม่ควรรู้วิธีการเปลี่ยนสถานะ

    ล้อเล่น

    Jest เป็นกรอบการทดสอบหน่วยของ Facebook สำหรับ JavaScript มันทำให้การทดสอบหน่วยเร็วขึ้นโดยการทดสอบแบบขนานวิ่งข้ามฐานรหัส ด้วยโหมดการเฝ้าดูเฉพาะการทดสอบที่เกี่ยวข้องกับการเปลี่ยนแปลงที่เกิดขึ้นเท่านั้นซึ่งจะทำให้ลูปข้อเสนอแนะสำหรับการทดสอบสั้นลง Jest ยังให้ความคุ้มครองรหัสของการทดสอบและได้รับการสนับสนุนใน VS Code และ Webstorm

    คุณสามารถใช้ค่าที่ตั้งไว้ล่วงหน้าสำหรับ Jest ที่จะทำการยกระดับหนักสำหรับคุณเมื่อตั้งค่า Jest ในโครงการของคุณ

    กรรม

    Karma เป็นนักวิ่งทดสอบพัฒนาโดยทีม AngularJS ต้องใช้เบราว์เซอร์ / DOM จริงเพื่อเรียกใช้การทดสอบ มันยังสามารถเรียกใช้บนเบราว์เซอร์ที่แตกต่างกัน Jest ไม่ต้องการหัวโครเมี่ยม / phantomjs เพื่อทำการทดสอบและทำงานในโหนดบริสุทธิ์

    สากล

    หากคุณยังไม่ได้ทำให้แอปเป็นแอปสากลตอนนี้เป็นเวลาที่ดีที่จะทำ Angular Universal ให้คุณเรียกใช้แอปพลิเคชัน Angular ของคุณบนเซิร์ฟเวอร์และทำการเรนเดอร์ฝั่งเซิร์ฟเวอร์ (SSR) ซึ่งทำหน้าที่เป็น html ที่แสดงผลแบบคงที่ล่วงหน้า สิ่งนี้ทำให้แอปเร็วเป็นพิเศษเพราะมันแสดงเนื้อหาบนหน้าจอเกือบจะทันทีโดยไม่ต้องรอให้ชุดบันเดิล JS โหลดและแยกวิเคราะห์หรือให้ Angular to bootstrap

    นอกจากนี้ยังเป็นมิตรกับ SEO ด้วยเนื่องจาก Angular Universal สร้างเนื้อหาแบบสแตติกและทำให้โปรแกรมรวบรวมข้อมูลเว็บจัดทำดัชนีแอปพลิเคชันได้ง่ายขึ้นและทำให้สามารถค้นหาได้โดยไม่ต้องเรียกใช้ JavaScript

    ทำไม?

    Universal ปรับปรุงประสิทธิภาพของแอปพลิเคชั่นของคุณอย่างมาก เราเพิ่งอัปเดตแอปพลิเคชันของเราเพื่อทำการเรนเดอร์ฝั่งเซิร์ฟเวอร์และเวลาในการโหลดไซต์เพิ่มขึ้นจากหลายวินาทีเป็นสิบมิลลิวินาที !!

    นอกจากนี้ยังช่วยให้เว็บไซต์ของคุณแสดงอย่างถูกต้องในตัวอย่างข้อมูลโซเชียลมีเดีย สีที่มีความหมายแรกนั้นเร็วมากและทำให้ผู้ใช้มองเห็นเนื้อหาได้โดยไม่ล่าช้า

    ข้อสรุป

    แอปพลิเคชั่นอาคารเป็นการเดินทางที่ไม่หยุดนิ่งและยังมีพื้นที่สำหรับปรับปรุงสิ่งต่างๆ รายการเพิ่มประสิทธิภาพนี้เป็นจุดเริ่มต้นที่ดีและการใช้รูปแบบเหล่านี้อย่างสม่ำเสมอจะทำให้ทีมของคุณมีความสุข ผู้ใช้ของคุณจะรักคุณสำหรับประสบการณ์ที่ดีด้วยแอพพลิเคชั่นรถบั๊กกี้น้อยและนักแสดงของคุณ

    ขอบคุณสำหรับการอ่าน! หากคุณชอบบทความนี้โปรดอย่าลังเลที่จะและช่วยให้ผู้อื่นค้นพบมัน โปรดอย่าลังเลที่จะแบ่งปันความคิดของคุณในส่วนความเห็นด้านล่าง ติดตามฉันใน Medium หรือ Twitter สำหรับบทความเพิ่มเติม Happy coding folks !! ️