Skip to content

Instantly share code, notes, and snippets.

@kawasima
Last active July 2, 2018 07:18
Show Gist options
  • Save kawasima/f6b829ec183d9292eb155c30a6dc1fc2 to your computer and use it in GitHub Desktop.
Save kawasima/f6b829ec183d9292eb155c30a6dc1fc2 to your computer and use it in GitHub Desktop.
.page-0 *{text-align:center}
.page-5 h1{font-size:large}.page-5 img{width:85%}
.page-17 img{width:50%}
.page-25 *{text-align:center}
.page-27 img{width:80%}
.page-30 h1{font-size:xx-large}
.page-31 *{text-align:center}
.page-37 h1{font-size:x-large}
.page-39 blockquote{font-size:medium}
.page-40 *{text-align:center}
.page-43 h1{font-size:xx-large}
.page-45 code{font-size:large}
.page-47 *{text-align:center}
.page-48 h1{font-size:xx-large}

ソフトウェアアーキテクチャの変遷と再構成に関する一考察

@kawasima


kawasima


本日のはなし

テーマ「越境」ということですが、

Webアーキテクチャのボーダーが崩れてみな越境の必要がある

というお話をします。


前提

私 そこそこ大規模SIer の立場なので、

多分ほとんどの人にとって、

「対岸の変化」ではないはず。


はじめの基礎要素

  • フロントエンド vs バックエンド
  • サーバサイド vs クライアントサイド

アーキテクチャの歴史 (koichik先生の定義)

Isomorphic survival guideより


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=14


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=15


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=16


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=17


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=18


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=19


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=20


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=21


https://speakerdeck.com/koichik/isomorphic-survival-guide/?slide=22


そして現代

サーバサイドでHTMLをレンダリングする時代に終わりが来たようだ。


時代背景

  • レガシーシステムにAPIを生やしはじめた。(FinTechなどのxTechブームはここを変えた)
  • APIを使って多くのアプリケーションを速く作るニーズ。 (PoCへの投資)
  • レガシーブラウザの死 (IE11よ…)
  • プログラマとデザイナの分業
  • ビューコンポーネントの再利用 (動的な側面を含むこともできる)

Monolithの限界点

FinTechもMicroservicesもただの触媒にすぎない。 限界はそこかしこですでに来ている。


フロントエンドとバックエンド N対M の時代


従来の体制の組み方


これまでのサーバサイドMVCの難しさ

  • エラーになった項目をフォーム再表示
  • 薄い機能のテンプレートじゃないとべザインとロジックの分離できない
  • 薄い機能のテンプレートだとコントローラにビューロジック混入しがち
  • 戻るボタンの実装
  • 結局、ブラウザ上での動的な挙動はJavaScriptで実装せざるを得ない

1人の開発者で1画面完璧に実装するのは難易度高い


要求される知識も多すぎる

  • HTMLとCSSに関する基礎知識
  • HTTPの仕様
  • クライアント/サーバ両方のセキュリティリスクと対策
  • ブラウザの違いについての知識
  • 効率的なSQLの書き方
  • セッション管理の設計と実装

ひとりのプログラマが全部できなきゃいけない。

できて当たり前という風潮 😂


新三層アーキテクチャ

  • APIサーバ
  • BFF
  • ブラウザ/ネイティブのフロントエンドアプリ


新三層時代の体制の組み方


APIサーバ


RESTful API

「今までHTML返してたところ、JSON返すようにするだけでしょ」は火傷する

  • 互換性
  • 拡張性
  • エラーハンドリング
  • ……

RESTful API ガイドライン

素晴らしいので読んで準拠していこう。

https://restful-api-guidelines-ja.netlify.com/


APIの後方互換性

  • 任意のフィールドのみ追加して、必須のフィールドは追加してはならない。
  • フィールドの意味は決して変えてはならない (例えばcustomer-numberをcustomer-idに変更することは、両者はカスタマの一意キーとしての意味は異なるのでNG)
  • サーバサイドのビジネスロジックでバリデーションしなきゃいけないような(複雑な)制約をもつ入力フィールド。バリデーションロジックは、より厳しくなる方向には変更してはいけません。すべての制約はdescriptionに明示します。
  • 入力パラメータとして使われる列挙型の要素は、サーバが古い値も受け付けて正しくハンドリングできる場合のみ減らすことができる。出力パラメータとして使われる列挙型はいつでも減らすことはできる。
  • 出力パラメータとして使われる列挙型は、クライアントがハンドリングできないかもしれないので追加してはならない。入力パラメータとして使われる列挙型はいつでも追加できる。
  • 出力パラメータととして使用され将来の拡張も考えておきたい場合は、x-extensible-enumを使う。 明示的に値を上限なしリストと定義し、クライアントは新しい値には依存しない設計をしなければならない。
  • URLを変更するときはリダイレクションをサポートする (301 Moved Permanently).

State-less Backend

そもそもサーバサイドでセッションとしてもつもの

  • 入力/確認/完了までの入力データ
  • 検索条件 (更新ユースケースから一覧へ戻ったとき用)
  • 閲覧履歴
  • 認証状態 (ログインセッション)

認証状態だけなんとかすれば良さそう


認証状態維持をAPIの外に出す

フロントエンド


デザイン/ロジックの分離

pure HTMLに近いテンプレートエンジンを使っても十分には解決しえなかった


デザイン要素の変化

  • コンポーネント指向

プログラマは思考回路がコンポーネント指向なので、

デザインも同様にコンポーネント化する。


コンポーネントの実装

const SlidePreviewList = (props) => (
  <Wrapper height={props.height}>
    {props.slide.pages.map((page, index) => renderSlidePreview(page, index, props))}
    <SlidePreview>
      <SlideContainer>
        <NewSlideButton onClick={props.onPressNewSlide} type="button">+</NewSlideButton>
      </SlideContainer>
    </SlidePreview>
  </Wrapper>)

Atomic Design


Margin-less Design の解消

特にプログラマがデザインレイヤまで作ると…

だいたいmargin, paddingレスデザインになる (Bootstrap使ってもダサい…レイアウトが詰まる…)

→ コンポーネントの組合せ単位で考えることで解消


Atomic Design + styled-components

コンポーネントにスタイルをカプセル化する。

const SlideContent = styled.div`
  ${props => props.center && 'text-align: center;' }
  height: 100%;
  padding: 1em 4em 1em 4em;
  img {
    max-width: 100%;
  }
`

Atomic Designのコンポーネントそれぞれで、適切なマージン・パディングを考えられる。


(参考) オレオレAtomicレベルの決め方

  • Atom: 他コンポーネントに依存しない
  • Molecules: 組合せ可。AtomでもMoleculeでもないもの。
  • Organisms: 他のページでも再利用できる可能性のあるもの。
  • Template: Organisims以下のコンポーネントを配置してpropsを渡すだけ。レイアウトに関する責務のみ
  • Pages: Redux/Fluxとの接続のみ

Storybook

storybook自体には賛否両論あるが、コンポーネントのカタログ化重要


BFF


BFFレイヤの責務

  • ルーティング
  • クライアントステートの設計
  • フロントエンドのロジック
  • APIの呼び出しの最適化

クライアントステート


クライアントステートの永続化

タブを閉じたり、リロードしたときにデータが失われないように。

  • Cookie
  • Local Storage
  • Session Storage
  • Indexed DB

フロントエンドのロジック

redux-saga

  • React Componentのレイヤで非同期イベントハンドリングするとたちまちコードが複雑化する
  • 個別のComponentでイベント処理せず、sagaが一手に担う。
    • そうすることでReact ComponentをSimpleに保ち、分業が可能にできる。

redux-saga

export function* onSlideLoaded(action) {
  const res = yield axios.get(action.payload.url, {
    responseType: 'text'
  })
  const pages = res.data.split(/[\n\r]-{4,}[\n\r]/m)
  yield put(Actions.setEntirePages({ pages, current: 0}))
}

API呼び出しの最適化


まとめ


サーバサイド → クライアントサイド

  • ルーティング
    • 認証領域の保護
    • フロー制御 (戻るボタン/バリデーションエラー時のコントローラメソッド)
  • メッセージ文言
  • セッション管理
  • HTMLレンダリング
    • ビューロジック
    • フォーマッティング
  • ……

あなたはどこに向かう?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment