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
一緒に使うことが多い値は別クラスにしよう(Data Clumps)/data_clumps_i...
Search
kirimaru
August 24, 2022
Technology
840
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
一緒に使うことが多い値は別クラスにしよう(Data Clumps)/data_clumps_is_useful
【LT登壇7名決定!】リーダブルコード LT会 - vol.4 #readablelt
https://rakus.connpass.com/event/253650/
kirimaru
August 24, 2022
More Decks by kirimaru
See All by kirimaru
早くAPI作るならFastAPI がオススメ
hirotokirimaru
1
140
DDD(ドメイン駆動設計)を知らない人に知ったつもりさせる/Introduce_DDD_to_unfamiliar_individuals
hirotokirimaru
0
400
例示! Spring Bootで作られた REST APIのテストコード/ Testing-Example-for-a-REST-API-created-with-Spring-Boot
hirotokirimaru
2
2.3k
Backlogが好きな話。/i_like_backlog
hirotokirimaru
0
200
私が好きなポートアンドアダプターを紹介する/I-like-hexagonal-architecture.pdf
hirotokirimaru
1
1.5k
名付けのためにクラス図を元に会話しよう/Let's-use-class-diagram-to-communicate-with-client
hirotokirimaru
0
700
Code Smellsの Primitive Obsession に気を付けて設計する/Designing-with-Code-Smells-Primitive-Obsession
hirotokirimaru
1
3.9k
FCCを推す/My favorite software architecture is FCC
hirotokirimaru
0
310
我々はなぜオブジェクト指向やDDD等のアーキテクチャを学ぶのか/Why_we_learn_ObjectOriented_and_DDD_Architecture
hirotokirimaru
1
1.2k
Other Decks in Technology
See All in Technology
Account Factory for Terraformによる 標準化されたアカウント発行の自動化
pensuke628
0
120
認知負荷を吸収し、プロダクトをまたぐPR Preview基盤の設計事例
taiki45
2
550
スキルを作る、その前に!複数人で使われるスキルを 作るためのプロセス
junkifurukawa
1
120
形式手法を使って仕様をコーディングしよう
mikanichinose
0
150
1人アドミンな私はAWSアカウント申請をSlackで完結したい!
ysuzuki
0
100
音声コミュニティを守るAI監視基盤_ 90%以上の入力削減を支えたServerless設計と運用判断
shuheioka123
0
120
Argo CDとAtlantisで実現するインフラ管理のセルフサービス化──小規模SREチームで支えるプラットフォーム
cassius7
0
250
Coil3を内部実装から読み解く~キャッシュ戦略とAVIF画像の描画〜/nikkei-tech-talk50
nikkei_engineer_recruiting
0
180
LT:「このままでいいのかな?」から一歩踏み出した私のデータキャリア選択〜社会人3年目に上京を決意したリアル〜Snowflake女子会 vol.8
snowwmn0824
0
120
Swap and Memory Reclaim - Squeezing Out More RAM
ennael
PRO
1
1.4k
Amazon Bedrock Agents ClassicからAmazon Bedrock AgentCoreへ移行した際、ガードレール設定が2箇所に割れた話
matsunobu
0
160
BedrockとLambdaで作る リアルタイム進行型推理ゲーム
kawametho
0
120
Featured
See All Featured
Amusing Abliteration
ianozsvald
1
320
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
3.2k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
330
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
590
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.9k
4 Signs Your Business is Dying
shpigford
187
23k
Skip the Path - Find Your Career Trail
mkilby
1
240
Test your architecture with Archunit
thirion
2
2.4k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
710
Building the Perfect Custom Keyboard
takai
2
890
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
50
10k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
390
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に興味を持つ • 型を作ることをやってみる アクション