Upload
shiroyagi-corporation
View
662
Download
0
Embed Size (px)
Citation preview
とレイヤ化アーキテクチャ
白ヤギコーポレーション 森本哲也
Shiroyagi.corp. All rights reserved
概要
● Go で API サーバーを開発してきて1年が過ぎました
○ この記事で書いたことの補足
● 良い設計の基礎知識
● Spring フレームワークと AOP (Aspect Oriented Programming)● レイヤ化アーキテクチャ
Go に特化した内容ではなく設計の一般的な話になってしまいました ...
Shiroyagi.corp. All rights reserved
自己紹介
● 森本 哲也 (@t2y)○ http://t2y.hatenablog.jp/
● 白ヤギコーポレーション所属
○ カメリオ API という Web API サービスを開発している
■ nikkei BPnet で記事の分類に全面採用
● プログラミング言語歴
○ Python (3年) → Java (3年) → Go (1.5年)
良い設計の基礎知識
Shiroyagi.corp. All rights reserved
● 発売: 2013-04-24 (新人応援号)● 特集1: 「良い設計の基礎知識」
○ 井上 誠一郎 著○ 6章構成で全37ページ
● 私は設計の基礎知識を
この記事から学びました
Shiroyagi.corp. All rights reserved
● 「設計とは継続する工程」○ 設計という行為は、何を作るか決めたあとから実際にコードを書き上げて
モノができあがるまで、ずっと考え続ける行為
○ 現代のソフトウェア開発では設計と実装は不可分
○ 事前の設計に時間をかけても
コードを書く中で考え直しは避けられない
○ 設計を通じて問題やシステムの理解が
進めば、コードのフィードバックや
最初の設計方針の誤りに気づく場合がある
設計とは?
Shiroyagi.corp. All rights reserved
「良い設計の基礎知識」から抜粋
● 依存関係の整理○ 安定しているほうへ依存する
● フレームワークのように設計する○ “アプリケーション全体がフレームワークの積み上げのように構成され、不安定な部分を上に
上に押し上げていくのが設計の進化の形です。この形で設計が進化すると、一番上には拡張
言語層が来ます”
● レイヤ化アーキテクチャ○ 上位下位の関係になるように全体を分割する
○ 上位レイヤは直下のレイヤにしかアクセスしないように強制する
● 設計のトレードオフ○ 教科書的には実行速度よりも正しい設計を優先すべき
○ システム制約により設計を変更せざるを得ない場合もあるのが現実
フレームワークと
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.”
Shiroyagi.corp. All rights reserved
アスペクト指向プログラミング
● 本来の思想は難しそうなので省略 ...● オブジェクト指向プログラミング (OOP) を置き換えるもの
ではなく、それを補助するようなもの
● 目的は横断的関心事の分離
(Separation Of Cross-Cutting Concerns)● 参考
○ 第5回:AOPとは何か
○ アスペクト指向プログラミング(AOP)は機能を挿入する仕組み?
Shiroyagi.corp. All rights reserved
シンプルな実装例
● github.com/gogap/aop○ Aspect Oriented Programming For Golang
例えば、ログイン処理を実行したときに ...
前処理/後処理を呼び出す仕組みを汎用化する● 前処理/後処理は再利用可● 開発者は本質的な処理のみ実装すれば良い● 例) 前: ユーザー名の存在チェック ,
後: ログイン情報のセッションへの保存
● パスワード認証のログイン処理● OAuth認証のログイン処理
Shiroyagi.corp. All rights reserved
と
● Any hope for aspect oriented programming? #496○ “ロードマップにはない。”○ “そういうのは go nuts で議論すると良いよ。”
レイヤ化アーキテクチャ
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 〜)
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変換
重複除去属性の要否
記事の分類処理
Shiroyagi.corp. All rights reserved
のミドルウェア
● https://godoc.org/goji.io#Mux.Use○ Mux (HTTP Multiplexer) 単位に設定できる
■ ミドルウェアスタックと HTTP ルーターの機能を提供
○ リクエスト単位に必ず実行するような処理を実装する
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,}
Shiroyagi.corp. All rights reserved
アプリケーション層のインターセプター
● アプリ (インスタンス) 単位に設定できる
○ 実際はアプリ = 顧客になっている
● アプリごとのビジネスロジックなどを実装する
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 インスタンスから呼び出すべき?→ いま必要ないからやってない
Shiroyagi.corp. All rights reserved
「良い設計の基礎知識」から抜粋
● 依存関係の整理○ 安定しているほうへ依存する
● フレームワークのように設計する○ “アプリケーション全体がフレームワークの積み上げのように構成され、不安定な部分を上に
上に押し上げていくのが設計の進化の形です。この形で設計が進化すると、一番上には拡張
言語層が来ます”
● レイヤ化アーキテクチャ○ 上位下位の関係になるように全体を分割する
○ 上位レイヤは直下のレイヤにしかアクセスしないように強制する
● 設計のトレードオフ○ 教科書的には実行速度よりも正しい設計を優先すべき
○ システム制約により設計を変更せざるを得ない場合もあるのが現実
Shiroyagi.corp. All rights reserved
処理が安定しているとは?
● 要件が変わっても処理を変更する必要がない
● 処理に変更がないとなぜ嬉しい?
○ (その箇所で) バグが発生しない
● 安定した処理とそうでない処理を分けて考える
○ 依存関係の整理
● 変更がある部分を上へ上へ (外へ外へ) 追い出す
○ → フレームワークようなものが出来上がる
○ → 積み重なってレイヤ化されていく
Shiroyagi.corp. All rights reserved
設計と学び
● Negroni と Gorilla.Context で実装していた (1.2年前)○ Context は WAF とセットで扱いたい
● Negroni から Goji へ移行 (1年前)○ 標準のミドルウェアで API 単位の AOP を実装するのは煩雑
→ Dispatch 機能をもったミドルウェア機構を追加
○ 顧客が増えて API 機能に対する要件が多様化
● アプリ層を導入 (半年前)○ ← いまここ
1年以上、開発しながら設計を考えてきた結果こういう形になってそれなりに機能しているという話
≠ 最初からこう設計すれば良いというわけではない
Shiroyagi.corp. All rights reserved
まとめ
● Go 1.7 おめでとうございます!
● Go の言語機能がシンプルだから設計に注力できる?