Clean Coder

プロ意識 プロになる前に注意したいこと プロにならないのは簡単だ。自分の仕事に責任を持たなければいい。すべて上司にお任せだ。 ミスをしたら上司が後始末をしてくれる。だた、プロは自分で後始末をする。 機能に危害を加えてはいけない ソフトウェアをリリースするときには、QAに問題を見つけてもらってはいけない。 不具合がありそうなコードをわざとQAに渡すようでは、プロの風土にも置けない。 では、不具合がありそうなコードとは何だろうか?詳細がわからないコードだ! コードが動いていることをどうやって把握するのだろうか?簡単だ。テストすればいい。 何度もテストするのだ。手を変え、品を変え、あらゆる方法でテストするのだ。 テストには時間がかかりすぎると思っているかもしれない。スケジュールや納期は守らないければいけない。 テストだけやってたらコードが書けないじゃないか。いい指摘だ! だからこそ、テストを自動化するんだ。すぐに実行できるユニットテストを何度も実行するんだ。 本物のプロは、構造を犠牲にして機能を届けるのはバカのやることだと思っている。 コードの柔軟性はその構造にかかっている。構造が不安定ならば未来も不安定になる。 ソフトウェアは適切なコストで変更できなければいけない。 労働倫理 1週間は168時間だ。雇用主に40時間、君のキャリアに20時間を使える。 残りは108時間。睡眠に56時間を使うとして、残りの52時間は自由に使える。 自分の専門を知る ソフトウェアのプロが備えるべき最低限のこと デザインパターン GOF の 24 のパターンについて説明できる。 POSA のパターンを実際に使える知識がある。 設計原則 SOLID 原則を知っている。コンポーネントの原則を熟知している。 方法論 XP・スクラム・リーン・カンバン・ウォーターフォール・構造化分析・構造化設計を理解している。 規律 TDD・ オブジェクト思考・設計構造化プログラミング・継続的インテグレーション・ペアプログラミングを実践している 成果物 UML・DFD・構造チャート・ペトリネット・状態遷移図・状態遷移表・フローチャート・ディシジョンテーブルの使い方を知っている。 ドメインを知る プログラミングの対象ドメインを理化する責任がある。会計システムを作っているのなら、会計の知識が必要。 ドメインの専門家になる必要はないが、仕事に必要な知識というものがある。 新しいドメインのプロジェクトが始まるときには、関連書籍を1~2冊読んでみよう。 専門家と一緒に時間を過ごして、彼らの原則や価値を理解しよう。 ビジネスを理解せずに仕様からただコードを書くのはプロとして最低だ。 仕様の間違いを発見・指摘できるように、ドメインを理解しなければいけない。 「ノー」と言う 奴隷は「ノー」と言うことを許されていない。労働者は「ノー」と言うことをためらうだろう。 だが、プロは「ノー」と言うことを期待されている。 反対者の役割 「なぜ」よりも「事実」のほうが重要。 だが、「なぜ」を説明することで相手の理解が深まり、事実を受け入れてくれることもある。 相手には技術的な知識があり、理解しようとしてくれるならば、理由を説明するのもいいだろう。 だが、理由を説明しても相手が納得しないこともある。 それどころか、あなたが全て悪いと決めつけていまうこともある。 詳細を説明しすぎると、マイクロマネジメントを招いてしまう。 試しにやってみる 「試しにやってみる」にはさまざまな意味がある。問題にしているのは、「余分な仕事をする」ことだ。 期日に間に合わせるために何かできたのであれば、それまで仕事をしていなかったことになる。 つまり、力を温存していたわけだ。 もし力を温存していないのんら、もし新しい計画がないのであれば、もし振る舞いを変えないのであれば、もし最初の見積もりに自信があるのであれば、 試しにやってみると約束するのは不誠実である。ウソをついているのと同じだ。おそらくは、自分のメンツを保ち、対立を避けるためにやっているのだろう。 「イエス」と言う代償 できることなら「イエス」と言いたい。健全なチームはみんなで「イエス」と言うことを目指している。 うまくいっているチームのマネージャーや開発者は、お互いに合意するまで実行計画の内容について交渉する。 しかし、これまで見てきたように、正しい「イエス」を言うには、「ノー」も恐れずに言わなければいけない。 コードの実現不可能性 プロはヒーローになることがある。しかし、それはヒーローになろうとしたからではない。 プロは、納期・予算どおりに仕事を成し遂げたときにヒーローになる。...

March 1, 2022

Dependency Inversion Principle

ソースコードの依存関係が(具象ではなく)抽象だけを参照しているシステムが最も柔軟である。 Before from abc import ABC, abstractmethod class Order: def __init__(self): self.items = [] self.quantities = [] self.prices = [] self.status = 'open' def add_item(self, name, quantity, price): self.items.append(name) self.quantities.append(quantity) self.prices.append(price) def total_price(self): total = 0 for i in range(len(self.prices)): total += self.quantities[i] * self.prices[i] return total class Authorizer(ABC): @abstractmethod def is_authorized(self) -> bool: pass class Authorizer_SMS(Authorizer): def __init__(self): self.authorized = False def verify_code(self, code): print(f'Verifying SMS code {code}') self.authorized = True def is_authorized(self) -> bool: return self....

February 18, 2022

Interface Segregation Principle

包括的なインターフェースがあるより、いくつかの特定のインターフェースに分割すべき。 Before from abc import ABC, abstractmethod class Order: def __init__(self): self.items = [] self.quantities = [] self.prices = [] self.status = 'open' def add_item(self, name, quantity, price): self.items.append(name) self.quantities.append(quantity) self.prices.append(price) def total_price(self): total = 0 for i in range(len(self.prices)): total += self.quantities[i] * self.prices[i] return total class PaymentProcessor(ABC): @abstractmethod def auth_sms(self, code): pass @abstractmethod def pay(self, order): pass class DebitPaymentProcessor(PaymentProcessor): def __init__(self, security_code): self.security_code = security_code self.verified = False def auth_sms(self, code): print(f'Verifying SMS code {code}') self....

February 18, 2022

Liskov Substitution Principle

サブクラスは、スーパークラスと置換可能でなければならない。 Before from abc import ABC, abstractmethod class Order: def __init__(self) -> None: self.items = [] self.quantities = [] self.prices = [] self.status = 'open' def add_item(self, name: str, quantity: int, price: int) -> None: self.items.append(name) self.quantities.append(quantity) self.prices.append(price) def total_price(self) -> int: total = 0 for i in range(len(self.prices)): total += self.quantities[i] * self.prices[i] return total class PaymentProcessor(ABC): @abstractmethod def pay(self, order: Order, security_code: str) -> None: pass class DebitPaymentProcessor(PaymentProcessor): def pay(self, order: Order, security_code: str) -> None: print('Processing debit payment type') print(f'Verifying security code: {security_code}') order....

February 18, 2022

Open Closed Principle

ソフトウェアの構成要素は拡張に対しては開いていて、修正に対しては閉じていなければならない。 ソフトウェアの振る舞いは、既存の成果物を変更せず拡張できるようにすべき。 Before class Order: def __init__(self) -> None: self.items = [] self.quantities = [] self.prices = [] self.status = "open" def add_item(self, name: str, quantity: int, price: int) -> None: self.items.append(name) self.quantities.append(quantity) self.prices.append(price) def total_price(self) -> int: total = 0 for i in range(len(self.prices)): total += self.quantities[i] * self.prices[i] return total class PaymentProcessor: def pay_debit(self, order: Order, security_code: str) -> None: print("Processing debit payment type") print(f"Verifying security code: {security_code}") order....

February 18, 2022