23
とレイヤ化アーキテクチャ 白ヤギコーポレーション 森本 哲也

Goji とレイヤ化アーキテクチャ

Embed Size (px)

Citation preview

Page 1: Goji とレイヤ化アーキテクチャ

とレイヤ化アーキテクチャ

白ヤギコーポレーション 森本哲也

Page 2: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

概要

● Go で API サーバーを開発してきて1年が過ぎました

○ この記事で書いたことの補足

● 良い設計の基礎知識

● Spring フレームワークと AOP (Aspect Oriented Programming)● レイヤ化アーキテクチャ

Go に特化した内容ではなく設計の一般的な話になってしまいました ...

Page 3: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

自己紹介

● 森本 哲也 (@t2y)○ http://t2y.hatenablog.jp/

● 白ヤギコーポレーション所属

○ カメリオ API という Web API サービスを開発している

■ nikkei BPnet で記事の分類に全面採用

● プログラミング言語歴

○ Python (3年) → Java (3年) → Go (1.5年)

Page 4: Goji とレイヤ化アーキテクチャ

良い設計の基礎知識

Page 5: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

● 発売: 2013-04-24 (新人応援号)● 特集1: 「良い設計の基礎知識」

○ 井上 誠一郎 著○ 6章構成で全37ページ

● 私は設計の基礎知識を

この記事から学びました

Page 6: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

● 「設計とは継続する工程」○ 設計という行為は、何を作るか決めたあとから実際にコードを書き上げて

モノができあがるまで、ずっと考え続ける行為

○ 現代のソフトウェア開発では設計と実装は不可分

○ 事前の設計に時間をかけても

コードを書く中で考え直しは避けられない

○ 設計を通じて問題やシステムの理解が

進めば、コードのフィードバックや

最初の設計方針の誤りに気づく場合がある

設計とは?

Page 7: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

「良い設計の基礎知識」から抜粋

● 依存関係の整理○ 安定しているほうへ依存する

● フレームワークのように設計する○ “アプリケーション全体がフレームワークの積み上げのように構成され、不安定な部分を上に

上に押し上げていくのが設計の進化の形です。この形で設計が進化すると、一番上には拡張

言語層が来ます”

● レイヤ化アーキテクチャ○ 上位下位の関係になるように全体を分割する

○ 上位レイヤは直下のレイヤにしかアクセスしないように強制する

● 設計のトレードオフ○ 教科書的には実行速度よりも正しい設計を優先すべき

○ システム制約により設計を変更せざるを得ない場合もあるのが現実

Page 8: Goji とレイヤ化アーキテクチャ

フレームワークと

Page 9: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

フレームワーク

● Java の Web アプリケーションフレームワークの1つ● 最初のリリースは2003年6月● 開発者の Rod Johnson は IoC (後に DI) の提唱者?

● モジュール

○ … たくさんある中の1つとして

○ 11. Aspect Oriented Programming with Spring○ “The key unit of modularity in OOP is the class, whereas in AOP the

unit of modularity is the aspect.”

Page 10: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

アスペクト指向プログラミング

● 本来の思想は難しそうなので省略 ...● オブジェクト指向プログラミング (OOP) を置き換えるもの

ではなく、それを補助するようなもの

● 目的は横断的関心事の分離

(Separation Of Cross-Cutting Concerns)● 参考

○ 第5回:AOPとは何か

○ アスペクト指向プログラミング(AOP)は機能を挿入する仕組み?

Page 11: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

シンプルな実装例

● github.com/gogap/aop○ Aspect Oriented Programming For Golang

例えば、ログイン処理を実行したときに ...

前処理/後処理を呼び出す仕組みを汎用化する● 前処理/後処理は再利用可● 開発者は本質的な処理のみ実装すれば良い● 例) 前: ユーザー名の存在チェック ,

後: ログイン情報のセッションへの保存

● パスワード認証のログイン処理● OAuth認証のログイン処理

Page 12: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

● Any hope for aspect oriented programming? #496○ “ロードマップにはない。”○ “そういうのは go nuts で議論すると良いよ。”

Page 13: Goji とレイヤ化アーキテクチャ

レイヤ化アーキテクチャ

Page 14: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

軽量 アプリケーションフレームワーク

● 設計思想

1. Simple (Sinatra や Flask の流派)2. Composable3. Not magic4. Enough rope to hang yourself with

● リポジトリ

○ 旧: github.com/zenazn/goji○ 新: github.com/goji/goji (2015-11-01 〜)

Page 15: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

カメリオ サーバーのアーキテクチャ

App1Interceptor1

Interceptor2

...

Middleware1Middleware2

...

App2Interceptor1

Interceptor3

...

インフラ層 net/http

Goji 層Middleware

Cache Routing

HTTPHandler

アプリケーション層

Interceptor Business Logic

Search QueryApplication Handler

API 処理

Request Response

認証キャッシュJSON変換

重複除去属性の要否

記事の分類処理

Page 16: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

のミドルウェア

● https://godoc.org/goji.io#Mux.Use○ Mux (HTTP Multiplexer) 単位に設定できる

■ ミドルウェアスタックと HTTP ルーターの機能を提供

○ リクエスト単位に必ず実行するような処理を実装する

Page 17: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

ミドルウェアで の実装例

func CommonAPIMiddleware( c *web.C, h http.Handler,) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { for _, before := range beforeHandlers { if !before(*c, w, r) { return } }

h.ServeHTTP(w, r) // next

for _, after := range afterHandlers { after(*c, w, r) } } return http.HandlerFunc(fn)}

type AfterHandler func(web.C, http.ResponseWriter, *http.Request)var afterHandlers = []AfterHandler{ SaveAPIStat, WriteJsonResponse, SaveResponseIntoCache,}

type BeforeHandler func(web.C, http.ResponseWriter, *http.Request) boolvar beforeHandlers = []BeforeHandler{ SetAppSettings, SetPropertiesToContext, CreateCacheKey, WriteCacheResponseIfAvailable,}

Page 18: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

アプリケーション層のインターセプター

● アプリ (インスタンス) 単位に設定できる

○ 実際はアプリ = 顧客になっている

● アプリごとのビジネスロジックなどを実装する

Page 19: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

アプリ層で の実装例func ApplicationHandler(handlerFunc func(c *types.ApplicationContext)) web.HandlerType { return func(c web.C, res http.ResponseWriter, req *http.Request) { app, err := NewApplication(&c, res, req) if err != nil { err := errors.New(ERROR_NEW_APPLICATION) # error handling return }

appCtx := app.GetApplicationContext() for _, before := range app.GetBeforeInterceptors() { before(appCtx) }

handlerFunc(appCtx)

for _, after := range app.GetAfterInterceptors() { after(appCtx) } }}

低レイヤのContext, Resposne, Requestを引数に Application を生成

厳密に AOP をやるならApplication にハンドラーメソッドを定義し、app インスタンスから呼び出すべき?→ いま必要ないからやってない

Page 20: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

「良い設計の基礎知識」から抜粋

● 依存関係の整理○ 安定しているほうへ依存する

● フレームワークのように設計する○ “アプリケーション全体がフレームワークの積み上げのように構成され、不安定な部分を上に

上に押し上げていくのが設計の進化の形です。この形で設計が進化すると、一番上には拡張

言語層が来ます”

● レイヤ化アーキテクチャ○ 上位下位の関係になるように全体を分割する

○ 上位レイヤは直下のレイヤにしかアクセスしないように強制する

● 設計のトレードオフ○ 教科書的には実行速度よりも正しい設計を優先すべき

○ システム制約により設計を変更せざるを得ない場合もあるのが現実

Page 21: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

処理が安定しているとは?

● 要件が変わっても処理を変更する必要がない

● 処理に変更がないとなぜ嬉しい?

○ (その箇所で) バグが発生しない

● 安定した処理とそうでない処理を分けて考える

○ 依存関係の整理

● 変更がある部分を上へ上へ (外へ外へ) 追い出す

○ → フレームワークようなものが出来上がる

○ → 積み重なってレイヤ化されていく

Page 22: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

設計と学び

● Negroni と Gorilla.Context で実装していた (1.2年前)○ Context は WAF とセットで扱いたい

● Negroni から Goji へ移行 (1年前)○ 標準のミドルウェアで API 単位の AOP を実装するのは煩雑

→ Dispatch 機能をもったミドルウェア機構を追加

○ 顧客が増えて API 機能に対する要件が多様化

● アプリ層を導入 (半年前)○ ← いまここ

1年以上、開発しながら設計を考えてきた結果こういう形になってそれなりに機能しているという話

≠ 最初からこう設計すれば良いというわけではない

Page 23: Goji とレイヤ化アーキテクチャ

Shiroyagi.corp. All rights reserved

まとめ

● Go 1.7 おめでとうございます!

● Go の言語機能がシンプルだから設計に注力できる?