SlideShare una empresa de Scribd logo
1 de 40
どこに何を書くのか?
自己紹介
twitter
pospome
読み方
ポスポメ
職種
サーバサイドエンジニア
興味
クラス設計全般, DDD
ここら辺の技術に興味ある方は
  フォローしてくださると嬉しいです
コード改善ということで、
自分がリファクタリング、レビューで重点的に
確認しているところを紹介
自分が確認するのは「どこに何を書くのか?」という点
どこに?
・レイヤ
・パッケージ
・クラス
・関数
何を書くのか?
・何かしらの具体的なロジック
  ex. ユーザー登録のバリデーションロジック
もう少し具体的に言うと以下になる
・そのロジックはそこにあっていいのか?
・本来あるべきパッケージ、クラスがないのではないか?
例えば
「ユーザー登録のバリデーションロジック」が
商品クラスにあるのはおかしい
ユーザークラスにあるべきでは?
みたいなところを確認する
なぜそういった点を確認するのか?
あるべきところにコードがない
↓
仕様と実装が乖離している
or
パッケージ、クラスの責務が肥大化している
↓
可読性が低くなり、メンテナンス性が下がる可能性がある
↓
ビジネスの成長スピードに
コードの成長がついていけなくなる
例
ソーシャルゲームにおけるユーザーの攻撃力の計算
注意点
・元々ソーシャルゲーム作ってたので、
 こーゆー系の例しか思いつきません・・・
・今回はクラスを対象に説明します
・コードは golang で書いているので、
 正確には class ではなく、struct なのですが、
 まあ、大体一緒なので読み替えて下さい。
type User struct {
Attack int //攻撃力
}
func main() {
u := User{
Attack: 100,
}
//攻撃力は int の Attack に乱数を加算したものになる
rand.Seed(time.Now().UnixNano())
u.Attack = u.Attack + rand.Intn(10)
fmt.Println(u.Attack)
}
type User struct {
Attack int //攻撃力
}
func main() {
u := User{
Attack: 100,
}
//攻撃力は int の Attack に乱数を加算したものになる
rand.Seed(time.Now().UnixNano())
u.Attack = u.Attack + rand.Intn(10)
fmt.Println(u.Attack)
}
攻撃力計算のロジックが
Attack と独立して管理されている
他の場所で同じように攻撃力計算をしたい時に
ロジックが重複する可能性がある
例:バランス調整のシミュレーター
  開発で利用するデバッグ機能など
攻撃力計算のロジックと Attack を一緒に管理してみる
type User struct {
Attack int //攻撃力
}
func (u User) GetAttack() int {
rand.Seed(time.Now().UnixNano())
return u.Attack + rand.Intn(10)
}
func main() {
u := User{
Attack: 100,
}
fmt.Println(u.GetAttack())
}
User に GetAttack() を持たせることで、
Attack と攻撃力計算のロジックが常に一緒になる
User が存在すれば、
常に攻撃力計算が可能になる
これでOK?
type User struct {
HP, Attack, Defense int
Job string
Condition int
}
先程の修正でもよさそうだが、
ユーザーは攻撃力の他にも属性を持つ事が多い
User がロジックを持ってしまうと、
各属性に関する処理を全て User が持つことになる
User クラスの責務がどんどん肥大化してしまう
具体的なロジックを User クラスが持つ必要はないのでは?
type User struct {
Attack Attack //ここがポイント
}
func (u User) GetAttack() int {
return u.Attack.GetPoint()
}
type Attack struct {
Point int
}
func (a Attack) GetPoint() int {
rand.Seed(time.Now().UnixNano())
return a.Point + rand.Intn(10)
}
func main() {
u := User{
Attack: Attack{
Point: 100,
},
}
fmt.Println(u.GetAttack())
}
Attack を int ではなく、
オブジェクトと捉える
Attack 自体にロジックを持たせる
User は Attack.GetPoint() を呼ぶだけ
具体的なロジックは知らない
攻撃力計算ロジックを Attack に実装することにより、
User クラスからその責務がなくなった
これにより User クラスの責務が
肥大化する可能性は低くなるはず
*Attack.GetPoint() をデリゲートしているので凝集度は低いですが・・・
さらに、攻撃に関する仕様変更は Attack という
より具体的なオブジェクトへの修正に限定される
仮に守備力がある場合、
Defense という具体的なオブジェクトへの修正に
限定されるはず
User が直接ロジックを持っている場合、
攻撃力、守備力など User が持つ全ての属性に対する修正は
全て User への修正になってしまう
適切な責務の分離ができているとはいい難い
数値(int) である 攻撃力(Attack) を
わざわざオブジェクトで扱うのはおかしい
数値は int で表現した方がいい
と思う人がいるかもしれない・・・
実はこれが今日のポイント
・そのロジックはそこにあっていいのか?
・本来あるべきパッケージ、クラスがないのではないか?
↓
・攻撃力計算ロジックを User に置いていいのか?
・本来あるべき Attack クラスが存在しないために
 User に置いてるだけではないのか?
レビュー、リファクタリングには
こういった観点で物事を考える
ここで先程の実装に
「イベントの種類によって攻撃力計算ロジックが変わる」
という仕様を追加してみる
type User struct {
Attack Attack //攻撃力
}
func (u User) GetAttack() int {
return u.Attack.GetPoint()
}
攻撃力計算ロジックは Attack クラスが持っているので、
User クラスは変わらない
type Attack struct {
Point int
AttackLogic AttackLogic
}
func (a Attack) GetPoint() int {
rand.Seed(time.Now().UnixNano())
return a.Point + rand.Intn(10) + a.AttackLogic.Calc()
}
type AttackLogic interface {
Calc() int
}
type XxxEvent struct {
Point int
}
func (x XxxEvent) Calc() int {
//Xxx というイベントでは攻撃力が2倍になる
return x.Point * 2
}
AttackLogic interface を新規作成
AttackLogic を満たすクラスを
Attack にセットすれば、
目的に合った攻撃力計算が可能になる
今回は Xxxイベント というイベント用の
AttackLogic を用意している
func main() {
point := 100
u := User{
Attack: Attack{
Point: point,
AttackLogic: XxxEvent {
Point: point,
},
},
}
fmt.Println(u.GetAttack())
}
AttackLogic の管理方法はちゃんと考える必要があるが、
時間ないので割愛
このようなロジックを User に持たせると辛くなる
と思いませんか?
仕様追加が進むと、どんどん辛くなります
そして、
この実装を通じて以下であることが分かる
Attack … 攻撃を表現するオブジェクト
Attack.Point … 攻撃力を表現する int
実は Attack は攻撃力のオブジェクトではなく、
「攻撃」という概念をオブジェクトにしている
攻撃力である Attack.Point は結局 int
・そのロジックはそこにあっていいのか?
・本来あるべきパッケージ、クラスがないのではないか?
↓
・攻撃力計算ロジックを User に置いていいのか?
・本来あるべき Attack クラスが存在しないために
 User に置いてるだけではないのか?
↓
・「攻撃力」とは別に「攻撃」を表現するオブジェクトが
 存在しないのではないか?
・攻撃と攻撃力は別々の概念として扱うことで
 責務をはっきりさせる
まとめ
今回の例であれば、
Attack は int のままでもいいかもしれない
ただ、それはどーでもいい
今回伝えたかったのは「正解」ではなく「選択肢」
設計の正解を定義するのは難しい
どこに何を書くのか? をしっかりと考えて、
自分なりに正しい選択をして欲しい
「Shadowverse開発事例」〜美麗カードが動く! 制作テク
ニックのすべて〜
https://speakerdeck.com/cygames/shadowversekai-fa-shi-li-mei-li-
カードに関するクラスが60以上らしい
クラスが多い = 複雑
と考えるかもしれないが、
クラスを少なくしても結局必要なロジックは同じ
少ないクラスに大量のロジックを書くのか?
大量のクラスに短いロジックを書くのか?
この違いでしかない
少ないクラスに大量のロジックを突っ込むと
条件分岐が多発し、辛くなる可能性が高い
細かく分けることによって
利用する側が組み合わせられるので、
再利用性が高くなる
いかに小さくて意味のあるクラスを見つけるかがポイント
今回の例では「クラス」を取り上げましたが、
レイヤ、パッケージ、関数についても
同じような観点で考える必要があります
そのロジックはそこにあっていいのか?
という疑問を常に持ってコードの質を上げていきましょう
おわり

Más contenido relacionado

La actualidad más candente

アプリケーションコードにおける技術的負債について考える
アプリケーションコードにおける技術的負債について考えるアプリケーションコードにおける技術的負債について考える
アプリケーションコードにおける技術的負債について考える
pospome
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
増田 亨
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
Kota Mizushima
 

La actualidad más candente (20)

世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
テストコードの DRY と DAMP
テストコードの DRY と DAMPテストコードの DRY と DAMP
テストコードの DRY と DAMP
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
 
アプリケーションコードにおける技術的負債について考える
アプリケーションコードにおける技術的負債について考えるアプリケーションコードにおける技術的負債について考える
アプリケーションコードにおける技術的負債について考える
 
設計してますか?
設計してますか?設計してますか?
設計してますか?
 
やはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っている
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
RESTful Web アプリの設計レビューの話
RESTful Web アプリの設計レビューの話RESTful Web アプリの設計レビューの話
RESTful Web アプリの設計レビューの話
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
 
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
 
リレーショナルな正しいデータベース設計
リレーショナルな正しいデータベース設計リレーショナルな正しいデータベース設計
リレーショナルな正しいデータベース設計
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
C#でわかる こわくないMonad
C#でわかる こわくないMonadC#でわかる こわくないMonad
C#でわかる こわくないMonad
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
 

Similar a どこに何を書くのか?

Phpではじめるオブジェクト指向(公開用)
Phpではじめるオブジェクト指向(公開用)Phpではじめるオブジェクト指向(公開用)
Phpではじめるオブジェクト指向(公開用)
VOYAGE GROUP
 

Similar a どこに何を書くのか? (20)

IDEALIZE YOU
IDEALIZE YOUIDEALIZE YOU
IDEALIZE YOU
 
プロダクトにおけるScala
プロダクトにおけるScalaプロダクトにおけるScala
プロダクトにおけるScala
 
Rubocopとの付き合い方
Rubocopとの付き合い方Rubocopとの付き合い方
Rubocopとの付き合い方
 
Phpではじめるオブジェクト指向(公開用)
Phpではじめるオブジェクト指向(公開用)Phpではじめるオブジェクト指向(公開用)
Phpではじめるオブジェクト指向(公開用)
 
アプリ開発を効率化する 方法あれこれ
アプリ開発を効率化する 方法あれこれアプリ開発を効率化する 方法あれこれ
アプリ開発を効率化する 方法あれこれ
 
20160326 第10回 Rad Studio 勉強会@Osaka
20160326 第10回 Rad Studio 勉強会@Osaka20160326 第10回 Rad Studio 勉強会@Osaka
20160326 第10回 Rad Studio 勉強会@Osaka
 
プログラミングを早くする方法
プログラミングを早くする方法プログラミングを早くする方法
プログラミングを早くする方法
 
確認・検討にちょっと役立つプラグイン
確認・検討にちょっと役立つプラグイン確認・検討にちょっと役立つプラグイン
確認・検討にちょっと役立つプラグイン
 
レスポンシブ対応 をサポートするプラグイン
レスポンシブ対応 をサポートするプラグインレスポンシブ対応 をサポートするプラグイン
レスポンシブ対応 をサポートするプラグイン
 
プログラミング講座 #5 競プロをやってみよう
プログラミング講座 #5 競プロをやってみようプログラミング講座 #5 競プロをやってみよう
プログラミング講座 #5 競プロをやってみよう
 
エンジニアの為のWordPress入門 〜WordPressはWebAppプラットフォームです〜
エンジニアの為のWordPress入門 〜WordPressはWebAppプラットフォームです〜エンジニアの為のWordPress入門 〜WordPressはWebAppプラットフォームです〜
エンジニアの為のWordPress入門 〜WordPressはWebAppプラットフォームです〜
 
TDD を自分の道具にしよう
TDD を自分の道具にしようTDD を自分の道具にしよう
TDD を自分の道具にしよう
 
サポーターズ勉強会スライド 2018/2/27
サポーターズ勉強会スライド 2018/2/27サポーターズ勉強会スライド 2018/2/27
サポーターズ勉強会スライド 2018/2/27
 
仕様七変化
仕様七変化仕様七変化
仕様七変化
 
クラウド登場で変化した受託案件と開発スタイルのRe-design~WebSig1日学校2013_受託の未来コース_後藤 和貴先生
クラウド登場で変化した受託案件と開発スタイルのRe-design~WebSig1日学校2013_受託の未来コース_後藤 和貴先生クラウド登場で変化した受託案件と開発スタイルのRe-design~WebSig1日学校2013_受託の未来コース_後藤 和貴先生
クラウド登場で変化した受託案件と開発スタイルのRe-design~WebSig1日学校2013_受託の未来コース_後藤 和貴先生
 
How to develop a huge Single Page Application
How to develop a huge Single Page ApplicationHow to develop a huge Single Page Application
How to develop a huge Single Page Application
 
Infra as Code Sapppro Casual 札幌の開催趣旨とTest-Kitchenの話
Infra as Code Sapppro Casual 札幌の開催趣旨とTest-Kitchenの話Infra as Code Sapppro Casual 札幌の開催趣旨とTest-Kitchenの話
Infra as Code Sapppro Casual 札幌の開催趣旨とTest-Kitchenの話
 
良い?悪い?コードコメントの書き方
良い?悪い?コードコメントの書き方良い?悪い?コードコメントの書き方
良い?悪い?コードコメントの書き方
 
JavaScriptで味わう! 関数型プログラミングのメリット!!
JavaScriptで味わう! 関数型プログラミングのメリット!!JavaScriptで味わう! 関数型プログラミングのメリット!!
JavaScriptで味わう! 関数型プログラミングのメリット!!
 
概観テキストマイニング
概観テキストマイニング概観テキストマイニング
概観テキストマイニング
 

Más de pospome (6)

MicroServices & APIs
MicroServices & APIsMicroServices & APIs
MicroServices & APIs
 
Datastore/Go のデータ設計と struct の振る舞いについて
Datastore/Go のデータ設計と struct の振る舞いについてDatastore/Go のデータ設計と struct の振る舞いについて
Datastore/Go のデータ設計と struct の振る舞いについて
 
Goのシンプルさについて
GoのシンプルさについてGoのシンプルさについて
Goのシンプルさについて
 
パッケージの循環参照
パッケージの循環参照パッケージの循環参照
パッケージの循環参照
 
Controllerのbefore_actionにおける インスタンス変数セットについて
Controllerのbefore_actionにおける インスタンス変数セットについてControllerのbefore_actionにおける インスタンス変数セットについて
Controllerのbefore_actionにおける インスタンス変数セットについて
 
サーバサイドNodeの使い道
サーバサイドNodeの使い道サーバサイドNodeの使い道
サーバサイドNodeの使い道
 

どこに何を書くのか?