Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
MediaDo.go #2 Clean Architectureとの付き合い方/mediado...
Search
kent-hamaguchi
September 25, 2020
Technology
2k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
MediaDo.go #2 Clean Architectureとの付き合い方/mediado-go-2-clean-architecture
MediaDo.go #2 というGoの勉強会で発表したスライドです。
https://mediado-go.connpass.com/event/186625/
kent-hamaguchi
September 25, 2020
More Decks by kent-hamaguchi
See All by kent-hamaguchi
メディアドゥ Go Conference 2021 スポンサーセッション/gocon-2021-mediado
kenthamaguchi
1
12k
メディアドゥ Amazon Personalize in AWS メディアセミナー Q1/mediado-amazon-personalize-aws-media
kenthamaguchi
0
1.6k
MediaDo DynamoDB活用事例/mediado-dynamodb-usecase
kenthamaguchi
0
1.4k
Infra Study Meetup #5 メディアドゥスポンサーセッション/infra-study-meetup-5-mediado
kenthamaguchi
0
930
JAWS DAYS 2020 メディアドゥスポンサーセッション/jaws-days-2020-mediado
kenthamaguchi
1
2.1k
OOC 2020 メディアドゥ スポンサーセッション/ooc_2020_mediado
kenthamaguchi
0
710
MediaDo.go #1 レガシーに立ち向かう / mediado-go-1-vs-legacy
kenthamaguchi
0
1.4k
MediaDo.go #1 GopherCon 2019 参加レポート / mediado-go-1-gophercon-2019
kenthamaguchi
1
1.4k
Go conf 2019 spring, sponsor session "Go初導入の組織で、社内外へ貢献していくために実施した、2つのこと" / go-conf-2019-spring-sponsor-session-mediado
kenthamaguchi
1
610
Other Decks in Technology
See All in Technology
その Lambda、8分で 管理者権限まで奪われます
k1nakayama
7
3.5k
アクセスキーこわい やめかたと漏らさない工夫
sassssan68
1
590
.NET WebAssemblyで実現するクライアントサイドAI推論:NuGetからViteまで、2つのエコシステムを繋ぐビルド戦略
yamachu
0
420
登壇の自信を奪う3匹のオバケ / 3 Ghosts That Rob You of Your Confidence in Public Speaking
pauli
9
1.1k
2026-09-08 そのJavaモダナイゼーション、AIに丸投げで大丈夫?IBM Bobで変わる品質と効率
yutanonaka
1
120
銀行勘定系システムにおける開発プロセス刷新×AIによる環境モダナイゼーション / Development Process Transformation and AI-Driven Environment Modernization
muit
1
2.6k
ADKで始める業務改善 - AIエージェント開発時の考えと設計
harappa80
2
260
AIに任せた品質は、誰が見立てるのか - AI時代のテストマネジメント
nakanao
3
2.7k
AIに賢く動いてもらうためのコンテキスト〜Snowflake女子会 vol.8
snowwmn0824
0
140
え、こんなに早く改修できるの?──新人エンジニアとスクラムマスターの2人が語る、AI×アジャイル開発の現場
ysasago
2
640
品質と信頼性を地続きにする
grimoh
2
900
Railsのように考える: See through the Master
snoozer05
PRO
5
1.2k
Featured
See All Featured
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
850
Building an army of robots
kneath
307
46k
Into the Great Unknown - MozCon
thekraken
41
2.7k
Music & Morning Musume
bryan
48
7.4k
The Limits of Empathy - UXLibs8
cassininazir
1
680
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
300
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
エンジニアに許された特別な時間の終わり
watany
109
250k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
280
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
430
Transcript
MediaDo.go #2 Go初心者向け Clean Architectureとの付き合い方
目次 • パッケージの分け方 • リポジトリ • Use Case Interactor
(書籍の)Clean Architectureは 何を伝えたいのか
優れたアーキテクチャに 共通して見られるルール
ゆえに書籍のこの言葉につながる アーキテクチャの ルールはどれも 同じである!
Clean Architectureは 何をクリーンに保ちたいのか
ビジネスロジックを クリーンに保ちたい
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
時間が経てば ビジネスも テクノロジーも 開発者も変わる それらに対応し続けるために導入する
ということで、コーディングなら このあたりの書籍や記事に求めると良い • 実践テスト駆動開発 (Steve Freeman, Nat Pryce) • Clean
Code (Robert Cecil Martin) • https://refactoring.com/catalog/
モデリングについては下記 • アナリシスパターン (Martin Fowler) • エリック・エヴァンスのドメイン駆動設計 (Eric Evans) •
実践ドメイン駆動設計 (Vaughn Vernon)
完
そうはいってもイメージが沸かないので Goを題材に設計を試す
本題
パッケージ構成
パッケージ構成 Clean Architectureの円に従い、ルートから下記のように切ってみる。 -- entity -- usecase -- adapter --
infrastructure やってみた系で結構見かける構成
パッケージ構成 技術的目線でルートを切ってしまうと、ビジネスロジックの表現力が乏しくなる -- entity -- wallet.go -- book.go -- authentication.go
パッケージプライベートなので お互いのすべてを参照可能、それを前提に作ると ビジネスロジックの凝集度が下がり、結合度が上がる
パッケージ構成 -- entity -- wallet -- wallet.go -- book --
book.go パッケージが分かれることで凝集度が上がり、結合度を下げられるが・・・
パッケージ構成 -- entity -- wallet -- wallet.go -- usecase --
wallet -- wallet.go -- adapter -- wallet -- wallet.go -- infrastructure -- wallet -- wallet.go 同じような構成のサブパッケージが 各種レイヤーに乱立しやすくなる wallet視点で見ると凝集度が低い
パッケージ構成 下記のほうが自然 -- wallet -- wallet.go (もしくはentity配下にwallet.go) -- usecase --
deposit.go -- adapter -- 〜〜〜 walletのことを豊かに表現できる幅がでる 必要に応じてパッケージ追加
パッケージ構成 他のEntityには非依存なのでbookも個別にパッケージ化 -- book -- series.go -- book.go -- usecase
-- search.go ビジネスロジックにおいて関係性が強いものは、 パッケージプライベートのオブジェクトを作用させるのも可
パッケージ構成 Entityを扱う必要がなく、技術的観点が強めなら下記でも良い -- authentication -- cognito.go -- signin.go 認証とかビジネスロジックとちょっ と遠いから、
一旦フラットに作るか・・・
パッケージ構成 モジュールについては、下記のようにモノリスで作っていても... -- wallet -- book -- authentication -- go.mod
パッケージ構成 切り出して別リポジトリにするときに、移動させるだけなので楽 -- wallet -- book -- authentication -- go.mod
別リポジトリ (fuga/wallet) -- go.mod
パッケージ構成 • あの円のレイヤにトップレベルを分ける必要はない ◦ 無理やり構成を合わせると管理しづらい (体験談含) ◦ 実装がFatになりがち、比例して開発コストは上がる ◦ ビジネスロジックを表現しづらくなる
• Goの可視性を活用する ◦ 大文字で始めればパブリック、小文字で始まるならプライベート ▪ Javaでいうクラス単位くらいの気持ちでパッケージを切っても良い ◦ パッケージプライベートを活用する • 単一のGo modulesから分離させるときも楽
リポジトリ
リポジトリ RepositoryはEntityの永続化と再構築の責務 book book repository book book book データベースや 外部のAPI
プログラムの メモリ上に展開
リポジトリ Repositoryはユースケースやドメインサービスから利用される Use Case Repository Service
リポジトリ そのためこのような構成になる -- book -- series.go -- book.go -- repositoryの何かしらの定義
リポジトリ repositoryはinterfaceで定義する -- book -- book.go -- repository -- book.go
どちらかに type BookRepository interface { FindByID(string) (book, error) }
リポジトリ 実装は別パッケージに分ける -- book -- book.go -- adapter -- repository
-- book.go import fuga/book type BookRepository struct { book.BookRepository db *sql.DB // AWSとか使うならそのAPIインターフェース } func NewBookRepository(db *sql.DB) book.BookRepository { return { db: db } }
リポジトリ adapterとか外のパッケージにせず、repositoryパッケージで完結も有り -- book -- book.go -- repository -- book.go
type BookRepository interface { findByID(string) (book, error) } // 小文字始まりなので他のパッケージから参照できない type bookRepository struct { BookRepository db *sql.DB // AWSとか使うならそのAPIインターフェース } func NewBookRepository(db *sql.DB) BookRepository { return { db: db } }
リポジトリ データベースへのマッピング処理はrepositoryの中身で完結させる -- book -- book.go -- repository -- book.go
RDBとか 間にORM用の構造体を挟むなど 引数としてEntityのbookが渡される
リポジトリ 実装が環境によって複数パターンあるなら、実装を増やして付け替える -- book -- book.go -- repository -- book.go
-- book_mock.go (Go modulesは分けたほうが良いけど ) モック用の実装と付替できるようにするなど
リポジトリ データストアのことを考えて共通化が必要ならinternalにそれを出すのもあり -- book -- book.go -- repository -- book.go
-- internal -- rdb.go アプリケーション全体へ渡り共通の処理があるなら、 外部のモジュールから importできないinternalパッケージに 実装をまとめて利用するなど
リポジトリ • まだ実装が固まらない間はインターフェースと実装が隣りにあってもよい ◦ インターフェースをパブリックにして、実装をパッケージプライベートにする ◦ interfaceの定義を組み直したりする際に、定義は一箇所のほうがシンプルに作業が楽 • Entityの構造体とRepositoryの内部で扱う構造体は別 ◦
単純にEntityの構造体をシリアライズするのもよいが、非公開フィールドを解決できない ◦ RDBやKVSや外部APIへの実装をEntityやUse Caseが意識しないようにする • Repositoryの作成単位はEntityに合わせる(ドメイン駆動設計の集約単位) ◦ 定義はEntityの隣りにあるが、実装は外側に配置 (依存性逆転の原則)
Use Case Interactor
Use Case Interactor ここから先の実装は大きくなりがちで、よほど複雑な要件でない限りコストが見合わなさ そうだが、一例を記す
Use Case Interactor Clean ArchitectureではRepositoryだけでなく、入出力についても語られている • Use Caseを入出力から分離する • 入力処理をController、出力処理をPresenterに分ける
◦ 入力と出力を分離することで、 UIに関わる複雑な関係性をシンプルに保つ 流れの通りに実装するとUse CaseがPresenterに依存しがちになるなため、 Use Case Interactorを挟み、インターフェースで依存性を管理する
Use Case Interactor type Usecase interface { Deposit(DepositInput) (DepositOutput, error)
} type DepositInput struct { UserID string Amount int } type DepositOutput struct { TotalAmount int } Use Case (walletのusecaseのつもり) EntityやRepositoryの操作を実装するUse Case自体の 入出力はシンプルな構造体 (可能な限り単純な値 )にしておく (実装内容はここでは重要ではないので省略 )
Use Case Interactor type UsecaseInteractor struct { usecase Usecase controller
Controller presenter Presenter } type Controller interface { ReadDepositInput() (DepositInput, error) } type Presenter interface { WriteDepositOutput(DepositOutput) error } Use Case Interactorの定義 入出力処理は別々のインターフェースに分離し、 UsecaseInteractorの実装の中で流れを作る。 ControllerとPresenterに入出力処理は委ねられるが、 Usecaseの実行に対する流れはここが担う。
Use Case Interactor func (u *UsecaseInteractor) Deposit() error { in,
err := u.controller.ReadDepositInput() if err != nil { return err } out, err := u.usecase.Deposit(in) if err != nil { return err } return u.presenter.WriteDepositOutput(out) } Use Case Interactorの実装 Use Case Interactorで定義したインターフェースに ControllerとPresenterは実装をするため、ここで依存性の 逆転が発生し、外部の環境に依存する実装が外側のレイ ヤにまとまる。 Use Caseはシンプルな値のやり取りで完結するため、 入出力の複雑さがビジネスロジックに介入しない。
Use Case Interactor • 入出力が複雑な場合、インターフェースで分離して実装と流れを分ける ◦ 入力処理と出力処理を別々に実装でき、テストできる ◦ Use Caseの実装のシンプルさを保つことができる
◦ テスタビリティを獲得するかわりに、実装コストは上がる
まとめ
まとめ Clean Architectureにこだわりすぎると実装が辛くなる可能性がある • ビジネスロジックをクリーンに保ちたい場合は導入の検討をする ◦ Entityレベルをいかに実装できるかが鍵、外部の実装の逃し方は前述のとおり ◦ そうではなく、ライブラリ開発などの場合は実装が Fatになりすぎる可能性あり
• アプリケーションの要件で形は変わってくるので、そこを中心に添えておく • 外部のことを考えずにEntityとUseCaseを実装すれば良い • 外のレイヤはControllerなどの枠に固めず、必要な分だけ実装すればよい
Clean Architectureは コーディングにおける銀の弾丸ではない 効果を発揮しそうな要件を見極めて 使っていきましょう
完