Share
Embed
Angular Webアプリケーションの最新設計手法.pdf
Angularを使用したWebアプリケーションの設計手法について、周辺ライブラリやトレンドを踏まえてお話します。近年複雑化しつつあるWebアプリケーション開発に対して、コンポーネントやデータ構造をどのように設計し開発することができるか、最新の技術を紹介しながら解説します。
kou
November 25, 2018
Transcript
70 slides
-
4 設計 拡張性 保守性 信頼性 - 設計とは、アプリケーションの柔軟性や堅牢性の基盤 - 設計とは、開発者同士の実装に対する共通意識 -
良い設計は、アプリケーションの信頼性と拡張性、開発効率の向上を生み出す なぜ設計を考える必要があるのか ? -
5 Angular - Web Applicationのためのフレームワーク - TypeScript / One Frameworkの堅牢なアプリケーション基盤
- Component - based Architecture -
6 Component - based Architecture アプリケーションそのものが 1つの Component で表現される Application
is Component Application Component = -
7 Component - based Architecture <!doctype html> <html> <head> ...
</head> <body> <app-root></app-root> </body> </html> -
8 Component - based Architecture App Component Component Component Component
Component Component - 最上位に AppComponentがあり、その下に子 Component がツリー構造で存在 - アプリケーションのそれぞれの機能は 1つ1つの Component で表現される -
- アプリケーションは Component で表現される - アプリケーション設計とは、Componentの分類と設計の手法と言える - 良い Component 設計さえあれば、複雑な設計は必要でない
14 Component Component Design How should we design Components ? -
16 Component の分類 - Component 設計の第一歩は、適切な分類分けをすること - Component は役割に応じて4種類に分類することができる App
Component Page Component Container Component Presentational Component Component Design -
17 Component の分類 App Component Page Component Container Component Presentational
Component Component Design Application そのものを表す、トップレベルの Component Web Pageを表す、URL単位の Component Serviceを使用して状態管理を行う Component 状態を持たない、表示専用の Component -
24 App Component Application そのものを表す、トップレベルの Component @Component({ selector: 'app-root', template:
` <router-outlet></router-outlet> `, }) export class AppComponent implements OnInit { ngOnInit(): void { // アプリケーション初期化処理など } } Component Design -
25 App Component How should we use App Component ?
- アプリケーションの全体の設定や、各 Serviceの初期化処理などを行う - 例)APIからの初期データの取得、WebSocketの接続処理など - 初期化処理は基本的に Service に移譲し、シンプルに保つ Component Design -
29 Page Component @Component({ template: ` <app-header></app-header> <app-hero [heroId]="heroId"></app-hero> <app-footer></app-footer>
`, }) export class PageComponent implements OnInit { constructor( private route: ActivatedRoute, ) {} ngOnInit(): void { // RouterからURL情報を取得し、Componentの状態を設定 this.heroId = this.route.paramMap... } } Web Pageを表す、URL単位の Component Component Design -
30 Page Component - 1 URLにつき、1 Page Componentを作成する ( 再利用はしない
) - テンプレートは Container Component、Presentational Componentで構成する - Router、ActivatedRoute などの Router関連の機能はこの Componentでのみ使用する Component Design How should we use Page Component ? -
33 Container Component @Component({ selector: 'app-heroes', template: ` <app-hero-detail *ngFor="let
hero of heroes" [hero]="hero" ><app-hero-detail> `, }) export class HeroesComponent implements OnInit { constructor(private heroService: HeroService) {} ngOnInit(): void { // Serviceを使用してComponent内のデータを初期化 this.heroes = this.heroService.getHeroes()... } } Serviceを使用して状態管理を行う Component Component Design -
34 Container Component - Service と Presentational Component のデータの受け渡しに専念し、ロジックを持たせない -
表示については Presentational Component を使用し、この Componentでは行わない - テストが不要になるレベルでシンプルに保つ Component Design How should we use Container Component ? -
37 Presentational Component @Component({ selector: 'app-hero-detail', template: ` <div>{{ hero.name
}}</div> <button (click)="buttonClick.emit()"> Delete </button> `, }) export class HeroesComponent implements OnInit { @Input() hero: Hero; @Output() buttonClick = new EventEmitter(); } 状態を持たない、表示専用の Component Component Design -
38 Presentational Component - シンプルな HTML のみで構成する - Serviceを使用せず、@input のみを使用してデータを受け取る
- テンプレート内のイベントは @Output を使用して上位 Component へ伝播させる - この Component でアプリケーションの大部分を構成するようにする Component Design How should we use Presentational Component ? -
39 Component の分類のコツ - Component の分割は、開発規模に応じて柔軟に行う - 例え冗長であっても、適切に分割することが重要 - 表示専用の
Presentational Component をなるべく多く作成する - Container Component が複雑にならないよう、Serviceに処理を寄せる Component Design App Component Page Component Container Component Presentational Component -
40 Component のテスト粒度 App Component Page Component Container Component Presentational
Component Component Design E2Eテストでページ表示のテストを行う E2Eテストでページ表示のテストを行う Serviceに対してのメソッドコールをユニットテストで確認する @Input、@Outputが適切に処理されているかユニットテストを行う -
42 Module - Module は 機能単位での Component の集合 - Service
なども含めることができるが、アプリケーション用の Module は Component 群のカプセル化と考えるのが良い Module Structure Module is a set of Components has Module Components -
43 @NgModule({ imports: [ CommonModule, MaterialModule, ... ], declarations: [
HeroPageComponent, HeroListComponent, HeroComponent, ], }) export class HeroModule {} Module Module Structure -
44 Module App Module Feature Module Feature Module Feature Module
Feature Module Feature Module Module 設計 - Moduleは Component と同様に、ツリー構造を持つ - Module はそれだけで完結する機能の単位として分割する - App Module の子となる機能単位でカプセル化された Module のことを Feature Module と呼ぶ Module Structure -
45 Module - 小規模なアプリケーションではルートとなる AppModule だけで十分 - 大規模な開発では、機能毎に開発担当者が異なるため Feature Module
が必要 - ( 一部の変更が他の Module に影響を与えないためのカプセル化 ) Module 設計 Module Structure Why should we use Module ? -
46 Core & Shared Module - Angular の公式で紹介されている特殊な Module -
これらの Module は複数の Feature Module で共有して使用される - Core Module は Serviceや関数を、Shared Module は Componentや Pipe を管理する Core Module Shared Module Module Structure -
47 Core & Shared Module - Core Module は Service
などのロジックに関する共通の機能を提供 - Shared Module は Component などの View に関する共通の機能を提供 - 全ての Feature Module はこの 2つの Module を共有して使用する Module Structure -
48 Feature ModuleとComponentのディレクトリ構造 - Feature Module は feature-modules というフォルダに配置 -
Feature Module 内に機能単位でサブフォルダを作成 - Feature Moduleは、他の Feature Module に影響を与えない (1部のFeature Moduleが壊れても他の箇所は動作する) Module Structure -
50 State Management State Management - State とは、移り変わるアプリケーションの状態を表す - State
Management とは アプリケーションのデータ管理方法 - Angularでは、主に Component と Service の連携方法 Component Component State Service -
51 2種類の State Management Component Single Data Service Data Service
Global Store Store Data Service Data Service Component Component Component Component Component State Management -
53 Single Data Service - 1つのデータタイプ (モデル) につき、1つの Serviceを作成し状態管理する -
Service はデータを Stream として提供し、 Component はそれらを subscribe する形で、リアルタイムにデータを受け取る Data Service Component Component update subscribe State Management -
54 Single Data Service @Injectable({ providedIn: 'root', }) export class
HeroDataService { private _data$ = new BehaviorSubject([]); getData(): Observable<Hero[]> { return this._data$.asObservable(); } update(data: Hero[]): void { this._data$.next(data); } } @Component({ ... }) export class HeroListComponent implements OnInit { private heroes$: Observable<Hero[]>; constructor( private heroDataService: HeroDataService, ) {} ngOnInit(): void { this.heroes$ = this.heroDataService.getData(); // データの種類に対して 1つのDataServiceを使う // this.villains$ = this.villainDataService.data$; } } State Management -
55 Single Data Service Data Service Component Component - 小さく始められる
- シンプルで仕様理解が簡単 Pros - Serviceの数が増えた時に急激に複雑化 - どのデータがどの Service にあるのか分かりづらい - 各 Service毎に仕様が異なる可能性がある Cons update subscribe State Management -
56 Single Data Service - 小規模なアプリケーション (1-3人程度の開発者) - 仕様が開発と同時に進むような、スピードの求められる開発 -
ある程度の大規模なアプリケーションが予定される場合は、 後述の Global Storeを使用すべき State Management When should we use Single Data Service ? -
58 Global Store - 1つの Store が全てのデータを管理 (Databaseとなる) - Component
は Actionを使用して Store を更新 - Data (State) の更新処理には reducer という関数を使用 Store reducer dispatch Action subscribe Component Component State Management -
60 Global Store - 決まった形式での統一的な実装 - Storeの拡張性が高く、大規模な状 態管理に強い Pros -
小規模なアプリケーションに対してはやや複雑 - どの Action がどの状態を変更するか分かりづらい Cons State Management Store reducer subscribe Component Component dispatch Action -
61 Global Store - 大規模なアプリケーション (5人以上の開発者) - 適切な Action 設計を考えてアプリケーション開発が可能な開発チーム
State Management When should we use Global Store ? -
63 Action Design - Data Service と違い、Store はアプリケーションの中央 Database そのもの
- 直接 Database の書き換えができないように、 Store の直接の更新はできない - Action / Reducer は、Database に対しての更新クエリと見なせる State Management Why should we use Action ? -
64 Action Design - Actionはアプリケーションの状態変更を示す - 分かりやすい Actionの設計は、アプリケーション仕様の理解を簡単にする - Global
Store を使う上で、Actionの設計が最も重要になる State Management How should we use Action ? -
65 Action Design Login Load Users Update User Detail Load
User Detail Reload Users Login後、User一覧ページから指定のUser情報を閲覧、アップデートする一連の処理 State Management -
66 Action Design Login後、User一覧ページから指定のUser情報を閲覧、アップデートする一連の処理 [ Login Page ] Login [
User List Page ] Load Users [ User Detail Page ] Update User Detail [ User Detail Page ] Load User Detail [ User List Page ] Reload Users Login Load Users Update User Detail Load User Detail Reload Users State Management -
67 Action Design Login後、User一覧ページから指定のUser情報を閲覧、アップデートする一連の処理 [ Login Page ] Login [
User List Page ] Load Users [ User Detail Page ] Update User Detail [ User Detail Page ] Load User Detail [ User List Page ] Reload Users [ Login API ] Login Success [ Router ] Move Page [ User API ] Load Users Success [ User API ] Load User Detail Success [ Router ] Move Page [ User API ] Update User Detail Success [ User API ] Reload Users Success [ Router ] Move Page State Management -
69 Component Design Module Structure State Management Conclusion - Component
分割を適切に行う - 表示に重点を置き、ロジック をシンプルにすること - 機能、URL単位で適切に分ける - 他機能に影響を与えないように カプセル化を利用する - アプリケーション、開発チームの 規模に応じた適切な状態管理を 採用する