Angularで

大規模開発に

取り組み始めた話

2017/10/26

Meguro.es #12

自己紹介

  • 西田雅博
  • 株式会社Bizreach
  • HRMOS採用管理
  • Angular 4, Play Framework (Scala)
  • React/Redux

GitHub: adwd

Twitter: @adwd118

 

Angularで大規模開発に

取り組み始めた話

  • AngularJS 1.xで構築されたフロントエンドをAngular 4に置き換えてる最中
  • そこでいろんな施策をやってみた​
    • 良かれと思って
    • フィードバック欲しいです!🙏

Contents

  • 背景

  • Angular

  • UIコンポーネントの分離+デモアプリ

  • オレオレFluxライクアーキテクチャ

背景

  • 2014年くらい?からのコード
  • HTML/CSS/JS合わせて10万行〜
    • サーバーサイドのScalaは20万行〜
    • Angular4は今6万行くらい
  • Angular JS 1.4 (一部 1.5)

背景

  • Flux風アーキテクチャ
  • なかなかおつらいコード(aka 技術的負債)
  • ngUpgradeの使用を断念
  • Angular4で作り直す
  • この機会に色々やったろ😏 
    • 長期間メンテンナンス性を保つ
    • Angular 5,6,7 ... と上げていきたい

Angular

Angular

  • Angularを使うという決断はどうだったのか
    • Angularを使うのが決まったあと参加

Cons

  • 高い学習コスト
    • Module, DI, RxJSあたりは難しい
    • エンジニア・マークアップの住み分けが必要?
    • とはいえ一般的なMVCフレームワークの範疇だと思う
    • 大規模SPAを構築する道具の学習コストなので、結局は必要なコストなのでは
    • 社内勉強会で3ヶ月かけてangular.io/docsを読みきった
  • Reactに比べるとまだまだ枯れてない
    • 周辺ライブラリなど
  • ググるのにいちいち -angularjs するのめんどい

Pros

  • 全部入り
    • Router, HTTP, Form, Test
    • インターフェースにRxJS
  • ドキュメント充実
    • angular.io (英語)
  • Angular-CLI
    • Webpackの知識ほぼ不要
  • @angular/cdk
  • async pipe
  • などなど

async pipe

<!-- user$ は Observable<User> もしくは Promise<User> -->
<ng-container *ngIf="user$ | async as user; else loading">
  <span>{{ user.name }}</span>
  <span>{{ user.mail }}</span>
</ng-container>
<ng-template #loading>
  <my-spinner></my-spinner>
</ng-template>
  • isLoadingみたいなのを管理しなくていい
  • Observableのsubscribe/unsubscribeをよしなにやっておいてくれる
  • 非同期・イベントドリブンなコンポーネントを組みやすい
  • ng-container: 不要なdivとかを生成しない

Angular

  • 個人的には好きです
  • サーバーサイドのMVC FWっぽい
  • 今は日本語の書籍もあるので学習コストの面はある程度楽になっている?

アプリケーションとUIコンポーネントの分離

+デモアプリ

アプリケーションと

UIコンポーネントの分離

  • Button, Toast, Modal などのコンポーネントを別プロジェクトに
  • npmのdependencies経由でアプリから使用
  • Atomic Designに従う
  • デモアプリを作成
    • UIコンポーネント、アプリの両方

Demo

Pros

  • デザイナー・エンジニアの分業
    • html/css/animation ...
    • ロジック/状態管理/http/RxJS ...
  • as a Living Document
  • コンポーネント実装時のサンドボックス

Consなど

  • メンテナンスコスト
  • コードの肥大
  • アプリのデモアプリを書くのは結構大変
    • たくさんの依存をMockしたり

その他

  • 最初はAtomic Componentsを採用していた
    • UI/アプリでの分割基準を見直した結果Atomic Designに落ち着いた
    • 詳しくは以前の発表資料
  • Storybook使ってもいいし自前でアプリ組んでもいいと思う
  • 大規模ならコストに見合うメリットありそう
  • OSSとして公開したらかっこいい…?
  • angular-elementsでWeb Componentsのライブラリとして公開できたらもっとかっこいい…?
  • Angular-CLIのmultiple app機能が便利

Flux-like Savkin inspired Architecture

Flux-like Savkin inspired Architecture

  • Angularは状態管理のレールは無い
    • Redux風のngrxが半公式
  • ngrxは採用しないことにした
    • 主にボイラープレート多すぎ問題
  • 元AngularチームのViktor Savkinが書いたAngularの状態管理に関する記事
    • すごく参考にした
  • ngx-model などと同様の発想

Flux-like Savkin inspired Architecture

  • 記事ではフロントエンドの状態は6種類に分けられるとある
  • それぞれの状態をRxJSのSubjectにして、AngularのDIの仕組みと組み合わせればRedux的なアーキテクチャになると考えた
  • Subject: EventEmitterみたいなやつ
    • Subject#next(data): イベントを送信
    • Subject#subscribe(listener): 受信

だいたいこんな感じ

export interface Todo {
  id: number;
  text: string;
  done: boolean;
}

@Injectable()
export class TodoService {

  _todos = new BehaviorSubject<Todo[]>([
    { id: 1, text: 'learn angular', done: false },
    { id: 2, text: 'learn react', done: true },
  ]);

  todos = this._todos.asObservable();

  constructor() { }

  fetch(): Observable<Todo[]> {
    return this.todos;
  }

  addTodo(text: string) {
    const todos = this._todos.getValue();
    const nextId = todos.length + 1;
    this._todos.next([ ...todos, { id: nextId, text, done: false }]);
  }
}

雑な比較

Redux Angular + RxJS
Store JSON 複数のSubject
Storeの結合 combineReducers (combineLatest とか)
selector あり (ServiceのDIとか)
Action ActionCreatorの実行 Serviceメソッドの実行
状態の変化 reducer Subject#next

こんなイメージ

{ ... }

Redux

RxJS

Componentのasync pipeにObservable突っ込むだけ、相性抜群

map/filter/reduce/flatMap/combineLatestなどでObservableを加工する

1枚のJSONがAction/Reducerで更新されていく

やってみて

  • これでいいじゃん感ある
  • まだ複雑な場合で試せてない
  • NgRxのデファクトっぷりが加速?
    • いまから選定するならNgRxにするかも…
    • Savkin先生もNgRx推し

まとめ

  • Angularで大規模開発の足場を固めている
  • Angular自体大規模に向いている
  • UIとアプリを分離してみた
  • デモアプリを作ってみた
  • NgRxを使わないで状態管理してみた

おわり

Made with Slides.com