Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
一緒に使うことが多い値は別クラスにしよう(Data Clumps)/data_clumps_is_useful
Search
kirimaru
August 24, 2022
Technology
0
520
一緒に使うことが多い値は別クラスにしよう(Data Clumps)/data_clumps_is_useful
【LT登壇7名決定!】リーダブルコード LT会 - vol.4 #readablelt
https://rakus.connpass.com/event/253650/
kirimaru
August 24, 2022
Tweet
Share
More Decks by kirimaru
See All by kirimaru
DDD(ドメイン駆動設計)を知らない人に知ったつもりさせる/Introduce_DDD_to_unfamiliar_individuals
hirotokirimaru
0
170
例示! Spring Bootで作られた REST APIのテストコード/ Testing-Example-for-a-REST-API-created-with-Spring-Boot
hirotokirimaru
2
1.1k
Backlogが好きな話。/i_like_backlog
hirotokirimaru
0
84
私が好きなポートアンドアダプターを紹介する/I-like-hexagonal-architecture.pdf
hirotokirimaru
1
600
名付けのためにクラス図を元に会話しよう/Let's-use-class-diagram-to-communicate-with-client
hirotokirimaru
0
540
Code Smellsの Primitive Obsession に気を付けて設計する/Designing-with-Code-Smells-Primitive-Obsession
hirotokirimaru
1
2.8k
FCCを推す/My favorite software architecture is FCC
hirotokirimaru
0
140
我々はなぜオブジェクト指向やDDD等のアーキテクチャを学ぶのか/Why_we_learn_ObjectOriented_and_DDD_Architecture
hirotokirimaru
1
940
SLAPを覚えてリファクタリングに方針を/we learn slap for refactoring
hirotokirimaru
1
290
Other Decks in Technology
See All in Technology
オーナーシップを持つ領域を明確にする
konifar
13
3.1k
プラットフォームってつくることより計測することが重要なんじゃないかという話 / Platform Engineering Meetup #8
taishin
1
350
20240416_devopsdaystokyo
kzkmaeda
1
220
Databricks における 『MLOps』
databricksjapan
2
170
ExaDB-D dbaascli で出来ること
oracle4engineer
PRO
0
2.1k
サーバー間 GraphQL と webmock-graphql の話 / server-to-server graphql and webmock-graphql
qsona
2
180
VSCodeの拡張機能を作っている話
ebarakazuhiro
1
350
プロデザ! BY リクルート vol.18_リクルートのリサーチ実践組織「リサーチブーストコミュニティ」
recruitengineers
PRO
3
280
KubeConにproposalを送りたい人へのアドバイス
sat
PRO
3
240
20240418_Google ColabにLLMが搭載されたようなのでPython x データ分析の勉強方法を考えてみる
doradora09
0
130
Next'24 事例セッションの紹介とクラウド資格を活用したキャリア形成について語りMuscle
yasumuusan
1
440
コンテナセキュリティの基本と脅威への対策
kyohmizu
3
760
Featured
See All Featured
Agile that works and the tools we love
rasmusluckow
325
20k
The Invisible Side of Design
smashingmag
294
49k
From Idea to $5000 a Month in 5 Months
shpigford
377
45k
Building Flexible Design Systems
yeseniaperezcruz
319
37k
In The Pink: A Labor of Love
frogandcode
138
21k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
104
6.6k
Principles of Awesome APIs and How to Build Them.
keavy
121
16k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
659
120k
10 Git Anti Patterns You Should be Aware of
lemiorhan
648
58k
GitHub's CSS Performance
jonrohan
1025
450k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
357
22k
Build The Right Thing And Hit Your Dates
maggiecrowley
24
2k
Transcript
一緒に使うことが多い値は 別クラスにしよう (Data Clumps) リーダブルコード LT会 - vol.4 #readablelt 20220824
きり丸(水上 皓登)@nainaistar
※ Javaのソースコードで例示します。
名前:きり丸(水上 皓登) twitter:nainaistar GitHub:hirotoKirimaru ブログ:きり丸の技術日記 https://nainaistar.hatenablog.com/ 3 一度でいいから バズってみたい
良いコードとは?
良いコードとは悪くないコード
悪くないコードにするには、 Code Smellsに気を付けたらいい
今日のキーワード Data Clumps (データの塊)
Data Clumpsとは (データの塊) 関連性が高く、一緒に使われることが多いデータを 別のクラスにまとめること。 モデリングをしっかりしている人にとっては、 当たり前といえば当たり前のお話です。
期間(日付)
例えば、期間(日付) 開始日 または 終了日を纏めたクラスがあるとします。 最低限の仕様としては次の挙動が考えられます • 存在する日付であること(2022/02/31は許容しない) ◦ 文字列型ではなく、日付型なら発生しない • 開始日は必須であること(終了日がないパターンは期間無限) •
開始日のほうが終了日より古いこと(期間の逆転禁止)
例えば、 期間(日付) public class サブスクリプション { String id; LocalDate contractStartDate;
LocalDate contractEndDate; int qty; BigDecimal price; } サブスクリプション のモデル。 契約開始日、契約終了日 を持っています。
例えば、 期間(日付) public class サブスクリプション { String id; 期間 contractTerm;
int qty; BigDecimal price; } public record 期間( LocalDate start, LocalDate end ){ } ちょっとすっきり。 契約の開始日ではなく、 開始日、終了日と 単語を短縮できるのも好き。
例えば、期間(日付) 複雑な仕様も閉じ込めることができます • 経過期間の計算 ◦ 2022/01/15-2022/12/31 -> 11ヵ月?12ヵ月? • 期間が暦上の一か月で割り切れるかどうか。
◦ 開始日に対して、日割の発生しない終了日であるか • 期間の重複チェック ◦ A.start <= B.end && B.start <= A.end
例えば、期間(日付) 期間と期間の比較は初見は面倒。
期間(時刻)
例えば、期間(時刻) 株式市場の取引時間をアプリで管理するとします。 日本市場:0900-1500(9時から15時) 米国市場:2330-0600(23時30分から翌6時) 仮想通貨:0000-2400(24時間いつでも可能)
例えば、 期間(時刻) public class 取引時間 { String id; String startTime;
String endTime; public isBusinessTime(LocalDateTime now) { // いい感じの処理 } } Stringの”0900”と”1500” を元に、 いい感じに処理する
例えば、期間(時刻) 日付を跨ぐ処理はどうしよう…? 2400が上限値ではない? 休み時間は…? Stringをたくさんいじりたくないな…
例えば、期間(時刻) 開始時刻は同じように管理して、 終了時刻ではなくN時間連続して 営業していることを示せばいいのでは? フレックスのように、 9:00勤務開始、18:00勤務終了 が大事ではなく、勤務時間が8H確保していることが大事では?
例えば、 期間(時刻) public class 取引時間 { String id; String startTime;
int straightHours; public isBusinessTime(LocalDateTime now) { // いい感じの処理 } } 終了時刻はすぐにわからない が、日付を跨ぐ場合には優し いかもしれない
例えば、期間(時刻) このモデルが絶対的な正義だという話ではありません。 必要なデータだけに絞って注目し、 制約事項を丁寧に処理していた結果、 当初、想像できなかったモデリングに 導かれることがありうるという例です。
DBの複合キー
None
DBの複合キー public class 企業 { String 企業ID; } public class
契約 { String 企業ID; String 契約ID; } public class 販売 { String 企業ID; String 契約ID; String 販売ID; } public class 仕入 { String 企業ID; String 契約ID; String 販売ID; String 仕入ID; } 適切な例が思い浮かばず…
例えば、DBの複合キー 複合キー自体が、既にデータの塊。 あくまで一意に定めるための塊であり、振る舞いを持つものではない ただ、名前を持ったデータの塊は意図が非常に伝わりやすい。 例: ・企業IDと契約IDと販売IDから仕入全体の金額を知りたい ・この販売の仕入全体の金額を知りたい
※ 私がコードリーディングする時の 脳内に浮かんでいる図です
DBの複合キー public class 販売主キー { String 企業ID; String 契約ID; String
販売ID; } public class 仕入 { String 企業ID; String 契約ID; String 販売ID; String 仕入ID; # パラメータが一つにまとまる public boolean salesEquals(販売主キー id) { return (this.企業ID.equals(id.企業ID) && this.契約ID.equals(id.契約ID) && this.販売ID.equals(id.販売ID)) } } 販売の複合主キーとして、親 のIDをすべて持つ前提
DBの複合キー 企業IDと 契約IDと 販売IDから 仕入全体の金額を知りたい あまりER図は意識しない
仕入 企業IDで絞込 契約IDで絞込 販売IDで絞込
DBの複合キー この販売の 仕入全体の金額を知りたい コードリーディングで 認識すべき内容が減る
仕入 仕入 販売 販売
例えば、DBの複合キー ばらばらのデータだと、それぞれの値に関係性がない可能性がある。 一つのデータの塊にすると、意図を伝えてくれる。 特にER図で考えたときに、複合主キーという存在は、 データの絞込ではなく、一意に決定づけられるため、 思考コストが減る。
ちょっと脱線
ちょっと脱線 • オブジェクト化したからと言って、 DBの構造も合わせる必要はありません。
例えば、 期間(日付) public class 販売 { String id; 期間 salesTerm;
int qty; BigDecimal price; } public record 期間( LocalDate start, LocalDate end ){ } Javaの構造。
例えば、 期間(日付) CREATE TABLE 販売 ( id VARCHAR(13) PRIMARY KEY,
start_date TIMESTAMP, end_date TIMESTAMP, qty INTEGER, price INTEGER, ); DBの構造。
例えば、 期間(日付) CREATE TABLE 販売 ( id VARCHAR(13) PRIMARY KEY,
term_id VARCHAR(13), qty INTEGER, price INTEGER, ); CREATE TABLE 期間 ( id VARCHAR(13) PRIMARY KEY, start_date TIMESTAMP, end_date TIMESTAMP, ) わざわざ ここまでする必要はない。
例えば、 期間(時刻) CREATE TABLE 取引時間 ( id VARCHAR(13) PRIMARY KEY,
start_time VARCHAR(4), end_time VARCHAR(4), ); CREATE TABLE 取引時間 ( id VARCHAR(13) PRIMARY KEY, start_time VARCHAR(4), straight_hours INTEGER ); モデリングの結果、 DBの構造を変えること自体は 良いこと
ちょっと脱線 • 使いづらくなったら、 データ構造を解体してフラットにするのは全然あり
例えば、 期間(日付) public class サブスクリプション { 期間 contractTerm; LocalDate cancelDate;
public boolean isCancelable{ // 期間クラスの開始日を使用する。 // 別クラスの属性を欲しがるという意味のCode Smells // Feature Envy // が起きかねない return this.contractTerm.start .isAfter(cancelDate) } } 解約日 という概念を追加。
例えば、 期間(日付) public class サブスクリプション { 期間 contractTerm; LocalDate cancelDate;
} ↓ public class サブスクリプション { LocalDate contractStartDate; LocalDate contractEndDate; LocalDate cancelDate; public boolean cancelable?(){ return // 期間クラスに // 解約可能かどうか判断メソッドを作ってもいい // 作らなくてもいい new 期間(contractStartDate, cancelDate) .noProration() } } 使いづらかったら、 データ構造をフラットに するのはあり。
ちょっと待って メリットだけなの?
メリットだけなの? • プリミティブな値をオブジェクト化しているので、 意図せずに別インスタンスから同一インスタンスを参照してしまう可能性 があります。 また、コピーも面倒です。 JavaScriptでは {...object} のシャローコピーで済むのに、 ディープコピーをするためにLodashを使う必要があります。
メリットだけなの? • どこまで処理を閉じ込めるかは議論の余地があります。 サブスクリプションを解約する際に、解約時点で利用が不可能になるか、 月末まで利用可能か、日割りが絡む中途半端な時期に解約できないか、 違約金を払えば解約できるのか…。 営業時間にサマータイムの時間は入りますか?
メリットだけなの? • 無難な処理については間違いなく含めていいです。 ただ、業務色が強い機能については、検討の余地があります。 もちろん、「期間」という一般名詞ではなく、 「立合時間」(株式が取引可能な時間)といった業務に特化した名前があ るのであれば、含めても問題ないでしょう。 🤼< 適切かどうかチームで話し合おう
その他の例
他にも • 期間 ◦ 開始日 と 終了日 ◦ 開始時間 と
継続時間 • 行列 ◦ X と Y と Z ▪ 加算・減算・内積・外積 等々
例えば • ページング ◦ 現在ページ数 と 最大ページ数 と ページサイズ ◦
ソート ▪ キー と 優先度 と 順番(ASC, DESC) と Nullableの扱い • LIMIT, OFFSETをまとめたRowBounds
まとめ
まとめ 従えば必ず有力になる強力なルールではありません。 導入せずとも、特に困ることは無いでしょう。 ただ、データをまとめていくことで、 より洗礼されたモデルになる可能性があります。 期間という概念はどのシステムでも実装する概念だと思いますので、 まずは期間からまとめてみてはいかがでしょうか。
Appendix
例えば、期間(日付) 個人的には、日付の比較が非常に苦手なので、閉じ込めてしまいたいです。 これが嫌い。 AがBより古い(同値含まず): A.isBefore(B) AがBより古い(同値含む) :!A.isAfter(B)
話すこと / 話さないこと • Code Smells • Primitive Obsession •
Java • Primitive Obsession が有効ではない個所 (私もわからない) 詰めなおしは推奨されないので、 べき論が分からない 話すこと 話さないこと
対象者 / 非対象者 • リファクタリングをしたいけど、 ヒントが分からない人 • リファクタリングに興味が無い人 • 動的型付言語
対象者 非対象者
登壇を見た人への期待するアクション • Code Smellsに興味を持つ • 型を作ることをやってみる アクション