🛁

良いコードを書きたい駆け出しエンジニア

2022/10/01に公開

良いコードが書きたい。
そんな風に思うようになってきた駆け出しエンジニアの備忘録。

良いコードとは

シンプルであるコード。
シンプルだと他人が読みやすいため、メンテナンスがしやすくなる。
「他人」には、「将来の自分」も含まれている。

より実務に役立ちそうな言葉を選ぶと下記三つになるだろうか。

「凝集度、結合度、クリーンアーキテクチャ」

それぞれ下記のような役割を果たしている。

  • モジュール内部の実装→凝集度
  • モジュール間の実装→結合度
  • モジュール群の実装→クリーンアーキテクチャ

引用文献と自作アプリを交えながら、学んだことをまとめていきたい。

Clean Architecture

Clean Architecture

将来の変更に強いアプリケーションを作るために考案された設計手法。

三つの重要な原則を伝えている。

下記三つを守るとソフトウェアのメンテナンスがしやすくなる。

  • 必ず上位レイヤーに依存方向を向ける
  • 依存関係と処理方向は分離する
  • 関心事の分離

UI→Controller→UseCase→Entityというように、最重要ビジネスルールに向かって依存関係を向けることが原則として説かれている。

最重要ビジネスルール

💡 コンピューターシステムが実装されているかに関わらずマネーを生み出したり節約したりするルールを指す

「銀行が貸したローンに利息を何%つけるというルール」

コンピューターシステムに関係ないルールを指している。

Zeroken(自作したアプリ)で考えてみる。

「お酒の強さを診断すること」

そのアプリが存在する目的を問うと最重要ビジネスルールが分かる。

最重要ビジネスデータ

💡 最重要ビジネスルールを実現する時に使用するデータを指す

銀行でいう、金利、貸付金残高、支払いスケジュールなどを指す

Zeroken(自作したアプリ)でいうところの

質問、ポイント、お酒の強さ、酔っ払いの尺度、アルコール度数等

を指している

エンティティ

💡 最重要ビジネスルールと最重要ビジネスデータを一つのオブジェクトとして表したもの

ドメインと呼ばれることが多い

ユースケース

💡 自動化されたシステムを利用する方法のこと
💡 エンティティの最重要ビジネスルールをいつ・どのように呼び出すかを規定したルールが含まれている

ユーザーがボタンを押して〜からではなく、インターフェースからやってくるデータとそこから出ていくデータを略式で規定しているだけ。

ユーザーインターフェースについては言及していないことに注意。データがどのようにインターフェースに入出力されるかはユースケースの関心ごとの範疇から離れる。

エンティティは入出力から遠いため、上位レイヤーに位置し、ユースケースは入出力から近いため下位レイヤーに属する。

そのため、依存の方向は必ずユースケース⇨エンティティになっていないといけない。

凝集度、結合度のグラデーション

💡 凝集度とは、モジュール内の協調度を指しており、高い程、堅牢性・信頼性・再利用性・読みやすさの点で好ましい。

良いコードとは何か - エンジニア新卒研修 スライド公開|CyberZ Developer|note

レビューを受ける際に、「コントローラーでこの処理を書くのはダメです」「ここでこの処理をするのは良くないと思います」と先輩エンジニアからレビューを受けた。

良い悪いを断言できるのは、経験からなのだろうかと考えていたところ、どうやらコードにはルールというものが存在すると分かった。

そのルールの一つが、凝集度と結合度である。

偶発的凝集〜機能的凝集まで7つの階層で分けられている。

結合度に関しては、凝集度を高めることで自然と低くすることができるとのこと。

例えば論理的凝集は下記のようなものを指している。

userの職位に応じてタスクを振り分けるようなメソッド。

def assignTask(user: nil)
  levelA()
  levelB()
  levelC()
if user == professional
  levelD()
else
  levelE()
end

これは下記のようにリファクタリングすると機能的凝集、逐次的凝集等の比較的好ましいとされるレベルまで高めることができる。

def assignTaskForProfessional
  levelA()
  levelB()
  levelC()
  levelD()
end

def assignTaskForStandard
  levelA()
  levelB()
  levelC()
  levelE()
end

条件分岐がなくなったことで、このメソッドが何をしているのかが読みやすくなった。

読みやすくなったことで、他のメソッドに使い回しやすくもなった。

善悪を断言できる時、その裏に根拠が隠されている可能性が高いと勘繰ることができる。

オブジェクト指向のその前に-凝集度と結合度/Coheision-Coupling

分散システムにおける適度な結合とは - Viadik Khononov氏のDDD Europeでの講演より

ドメイン固有モデル(DSL)

💡 分野(ドメイン)に存在する固有の事象を表す特殊な語彙

【23】ドメイン特化言語|プログラマが知るべき 97 のこと

メソッドとメッセージの違い

  • メッセージ

レシーバ(オブジェクト)にしてほしい挙動をさす。

下記でいうsubaruにしてほしい挙動

「subaruに皿を洗ってほしい」

subaru = Human.new(name: 'subaru')
subaru.wash_dish
  • メソッド

オブジェクトが持つ関数

class Subaru
  def wash_dish
    prepare_dish
    run_faucet
    scrub_dish
    run_faucet
  end
end

「メソッド」と「メッセージ」はどう違うのか - Crieit

ソフトウェアも人生のどちらもクリーンに設計していきたいものです。

Discussion