がんばるぞ

がんばります

可読性についてレビューするときに気をつけていること

この記事はスターフェスティバル Advent Calendar 2023 9 日目の記事です。

qiita.com


最近社内で可読性について会話をするタイミングがあり、可読性について思っていることを言語化してみるか〜と思ったので書いてみます。 可読性って難しいしよくわからないよね〜

この記事では、可読性という単語をコードの把握しやすさといった認知負荷的な意味だったり誤読しにくさみたいな意味で使っています。

メンタルモデルに起因するものなのか、そうではないのかを意識する

メンタルモデル?

メンタルモデルというものは「XXとはこういうもの」や「こうしたらこうなるはず」のような人それぞれが持つ思い込みみたいなものだと理解しています。

コードを読んで理解するときのメンタルモデルは、これまでのプログラミングに関する経験や知識、そのロジックが解こうとしている問題についての理解、自然言語自体の理解などの積み重ねで作られていくものかと思います。

たとえば、僕は getName というメソッドを見たときに

  • 状態の更新は起こらないだろうな
  • I/Oは発生しないだろうな
  • 計算コストは低いだろうな

みたいに思ったりしますが、僕とは違うメンタルモデルを構築している人であれば「小さなロジックとかもなく、インスタンスプロパティをそのまま返しているだけだろうな」といったことまで期待するかもしれません。

メンタルモデルに起因する指摘は難しい

読み手のメンタルモデルと実際にコードに乖離があると読み手は読みにくいなとか理解しにくいなとか思い始めますが、 残念ながらメンタルモデルは人によって異なり、ある人にとって可読性が上がる修正が別の人にとっては可読性を下げる修正になることがあります。

例えば関数指向になれている人は mapfilter を使って配列を処理することは簡潔で読みやすく感じると思いますが、そうではない人にとっては for 文を使ってループ処理している方が読みやすく感じたりします。

そのため、自分にとって可読性が低いから変えてほしいという視点だけだと自分しか得をしない指摘になってしまったり、 たいして実利を得ることができない議論のために時間を消費してしまったりするため、 この可読性の低下はメンタルモデルに起因するものなのか、ロジックの複雑性に起因するものなのかなどを自覚することは大事だと思っています。

とはいえ、綺麗に区切れるものでもないと思うので難しいんですが

普通の範囲に収まっていそうであれば許容する

多くのエンジニアのメンタルモデルに概ね合致するようなコードを書くことは重要なため、 getName というメソッドで状態の更新を行うようなコードを指摘するのは有益だと思いますが、 特別変なことをやっているわけではないコードに対してレビュアーとレビュイーが細かい点を主張しあうといった、お互いの普通あるいは常識をぶつけ合うだけで実利に結びつかないような議論は微妙だなと感じます。

(幸い自分の会社でそういった光景を見たことはないです

何を普通とするかは難しいためあくまで感覚的な話にはなってしまいますが、ある程度普通なコードに対しては nits くらいの温度感で意見を共有するに留めて、 プロダクトのコード規約のアップデートなどに時間を使った方が有意義かなと思っています。

コメントの不備による可読性の低下は指摘する

A Philosophy of Software Design という書籍の中では、コードだけでは必要な情報を全ては表現しきれないためコードコメントを残さないと情報の欠落が発生するというようなことが書かれています。たしか。

言葉足らずな文章が理解しにくいのと同じように、コードから読み取れない重要な情報はコメントとして残されていないとロジックの意図が捉えられず、ほとんどの人にとって可読性が低下してしまうため、こういったところは進んで指摘をするようにしています。

複雑度に起因する可読性の低下は指摘する

先日 fukabori.fm の認知負荷回を聞いてとにかく最高だったのですが、 fukabori.fm で語られていたように人の認知リソースは限られており、認知リソースを多く必要とするコードは全ての人にとって可読性がよくないため可能な限り複雑度が低くなるよう努力した方がいいです。

fukabori.fm

条件分岐を無理なく減らせたり、責務が分割されすぎているクラス群をある程度まとめるような修正は循環性複雑度などの数値の改善につながり、 大体の場合は認知リソースの節約になると思うので極力指摘をするようにしています。

とはいえこちらも、デザインパターンに慣れている人とそうでない人で複雑に感じる度合いが異なるなどメンタルモデルに左右される部分もあるので難しいのですが...

可読性という単語をあまり使わない

最後に、可読性という単語はあまり使わないようにしています。 というのも可読性という単語は便利なのですが抽象度が若干高いため、可読性という単語だけで説明した気になってしまうと意図が伝わらずにレビュイーを困惑させてしまったり手戻りが発生したりといったことに繋がるように思うからです。

可読性を低下させている原因は可読性という単語を使わずに説明可能なことが多いので、より具体的な単語を使って説明する方がコミュニケーションしやすいかなと思います。

おわりに

なんか書いてる間、テンションずっと変だった〜〜〜〜〜〜〜〜〜〜〜

可読性〜〜〜〜〜〜〜〜〜〜〜嫌!

PHPerKaigi 2023 に参加しました! #phperkaigi

phperkaigi.jp

数年ぶりにオフラインでカンファレンスに参加してきました。 去年も行きたかったんですが家庭の都合が合わず参加できなかったので、念願の!でした。

セッションの感想など

PHPの最高機能、配列を捨てよう!!

fortee.jp

朝1発目から uzulla さんの発表、目が覚めていいですね! 会場の盛り上げ方とかうますぎるし、何回も笑ったので最高でした。

技術的な内容に関しても、PHPの配列が生み出す辛みがめちゃくちゃ現場感あるもので課題感がとても伝わってきましたし、その解決策もとても簡潔にまとまっていたのですごく良いセッションだと思いました。

日頃の開発でも個人的に気をつけていた内容だったのですごく共感しつつ、僕にはここまでの言語化はできないので改めて uzulla さんすごいなぁと感じました。

面倒なのは嫌なのでコンテナのマネージドサービスに極振りしたいと思います。

fortee.jp

App Runner など使った経験がないしCaaSという単語すら知らないレベルだったので、情報のキャッチアップのために聞いてみましたがとても参考になりました。

n さんは Twitter で見ている限り技術的な守備範囲が異常に広いと感じているのですが、このセッションで守備範囲が広くなる背景を垣間見た気がしますw とにかくしっかり調査されているし、見習わなければと背筋がピンッとなりました。

Laravelへの異常な愛情 または私は如何にして心配するのを止めてEloquentを愛するようになったか

fortee.jp

武田さんの Laravel への異常な愛情を聞いてみたくて参加しました。 Laravel のドキュメントをもとに「Laravel はこういう構造をベストプラクティスとして想定しているのでは?」という仮説はすごく面白かったですし、なるほどなとなりました。

その仮説を踏まえると、Laravel は Eloquent 使ってこそだよねという結論もとても納得感があり面白かったです。

セッションを聞いていて、Laravel は開発するアプリケーションが Eloquent で耐えられる(= テーブルとドメインエンティティを 1:1 にマッピングする構造で問題ない)場合に採用するとうまくいく、と個人的に整理したのですが、じゃあ武田さんはこのアプリケーションは Eloquent でうまくいく/いかないをどういった指標で判断しているんだろう?というのが聴きたくなったので、そこらへんの話を続編として別のカンファレンスでしてくれることを勝手に期待していますw

そのほか感想

最終日しか参加できなかったのと、カンファレンスの廊下でたくさん雑談をしていたので、セッション自体はあまり参加できていないですが 後日オンラインで色々見ようかなと思ってます!

PHPをブラウザで動かす技術とか、めちゃくちゃ気になりますw

おわりに

久しぶりにオフラインで参加したPHPerKaigiはめちゃくちゃ楽しかったです! 最近は Twitter もだいぶ見なくなってコミュニティから消えかかっていたんですが、改めてもうちょっとコミュニティに参加したいなという気持ちになりました!

開催・運営してくださったスタッフの皆様、カンファレンスで僕と会話してくれた皆様、ありがとうございました〜〜〜〜!!!!!!!!!

スターフェスティバルに入社して2年が経ちそうです

この記事はスターフェスティバル Advent Calendar 2022 18 日目の記事です

https://qiita.com/advent-calendar/2022/stafes

昨日は @k1rnt自作プログラミング言語「リンちゃんなう!」 でした。
リンちゃん、だいぶ荒れ狂ってましたね。

はじめに

早いものでスターフェスティバルに入社して 2 年が経ちそうです。
スターフェスティバルに入社してからは一度もこういった振り返りをしていなかったので、久しぶりにしてみようかなと思います。
Advent カレンダーのネタがなかった

これまでから今まで何をやっていたのか

ごちクル期

入社してから 1 年と少しの間は ごちクル というアプリケーションの改善を主にやっていました。

入社した時点では CI が存在していなかったりテストが 8 割がた壊れたりしていたので、 まずは CI の導入とテストを全て直すところから始め、その後 PHPStan の導入をしてPHPStan のエラーを 2000 個弱解消したり、EC2 上で動いていたものをコンテナ化したり、一部の API を 40 倍以上高速化させたり、色々としていました。
CI 周りの改善やコンテナ化は今後の運用保守に良い効果を与えることが出来たんじゃないかなぁと思ってます

また、ごちクルと並行して ごちクル deli BOXという小さい新規サービスの開発をしたりもしました。
新規アプリケーションの開発を要件定義や仕様決めの段階からやるのは久しぶりだったので楽しかったです。追加の要求はやっぱり斜め上からくるなぁというのを改めて実感したので、各要素とその関係性を極力シンプルに保つような備え方を身につけないとなーってなりました。

リリース後、ごちクル deli BOX はご飯を食べながらの 1on1 やオンライン飲み会・イベントといったユースケースで利用いただいているようで、とても嬉しいです。
弊社主催のオンラインイベント でもこのサービスを使っていて、実際に食べるとやっぱりおいしいですね。

後半はCore Web Vitalsのスコア改善に取り組んでいましたが、こちらは残念ながらあまり結果を出すことが出来ませんでした。フロントエンドむずい。
数ヶ月後に弊社のフロントエンドエンジニアが片手間で対応してくれたんですが、(まだ途中ではありますが)グングンスコアが改善していくのを見てすげ〜ってなりました。やっぱり Webpack と向き合わなきゃいけないんや...

社内基盤期

今年の 4 月ごろにごちクルチームを抜け、社内管理基盤のリプレイスを進めるチームに移動しました。 弊社は様々な背景により社内基盤のリプレイスというものを数年単位で計画しているのですが、このチームではそれの要件定義から設計開発運用までを愚直にやっていきます。 また、単にリプレイスするだけだと改善しない点が多くあるので業務フローの再定義やデータモデリングのやり直しなども同時並行で行っています。マジですごく大変!

この社内基盤チームに移動してからは、社内基盤に商品を登録・変更するフローが様々な経緯でまぁえらい大変になっているのでそれの改善にずっと取り組んでいます。商品という事業的に重要なものについて色々考えなきゃいけないので、ずっと頭抱えて白目剥いてます。むずい!
(使ってる技術も未経験のものばかりだったので初期は白目が二回転してました。早く黒目に戻りたい)

僕は設計周りが好きなので要件定義とかも好きでやらせてもらってるんですが、このチームでは営業や社内オペレーションの担当、事業戦略を考える人など様々なロールの人たちが一体となって要件定義を進めているので、かなり面白いし勉強になることが多いです。

営業戦略とか事業戦略を踏まえて考えると設計にも新しい視点が入ってきて面白いですし、問題を解決するモデルとして担保しなきゃいけない部分と事業を回す上で担保しなきゃいけない部分って結構違うっぽいなぁというのが見えてきた気がしていて、これも面白いですね。
ドメインロジックとビジネスロジックの違いってこういうことなのかなぁと思いつつ、まぁここらへんは色々な考え方がありそうなのでアレですが。

振り返り

今までもそうですが、社内基盤チームに移動してからは特に自分の経験不足を強く感じるようになりました。
社内基盤では周辺のアプリケーションとの結合度を下げつつ協調していくためにイベント駆動をメインに開発を進めているんですが、まぁひたすらに難しく(僕が)失敗を重ねています。

幸い弊社はリファクタリングなどにかなり理解がある環境なので(本当にとてもとてもありがたい)失敗をしながらも軌道修正ができているのですが、あの時僕がちゃんと設計ができていればもっとスムーズに開発を進めることが出来たなということが本当にひたすらにめちゃくちゃあり反省しています。

  • イベント自体の設計
  • イベント駆動を元にした実装・テスト
  • データモデリング
  • テーブル設計
  • モジュール設計

あたりの知識をもっとつけるとここらへんはもうちょっと改善できるかなと思ってます。

一方で学びはかなり多く(結果に結びつけるにはもう少し時間が必要そうですが)、チームメンバーにもとても恵まれているのでワイワイ楽しく改善を続けられたらと思ってます。

ということで、スムーズな開発を実現するために来年以降も引き続き色々と学んでいきたい所存です。

がんばるぞ!

採用がんばってます!

エンジニアとしてスキルアップするチャンスに溢れている環境でワイワイ開発したい人にとてもオススメなスターフェスティバルなのですが、絶賛エンジニア募集中です! 社内基盤のリプレイスだけじゃなくて新規プロダクトの開発なども色々やっているので、食という領域に興味がある人は是非〜〜〜〜!楽しいよ!

stafes.notion.site

社内の雰囲気はざっくりこんな感じだったりするので、カジュアル面談とかしたい方は是非僕のTwitterにDMください! zenn.dev

知らない技術まみれのチームに移動した時に実践したこと

この記事はスターフェスティバル Advent Calendar 2022 11 日目の記事です

qiita.com

昨日は @shota1995mオブジェクト指向 UI デザインを読んだから図解してみる でした

はじめに

僕は生粋(?)の PHPer なので、PHP 以外の技術はなんちゃってレベルでしか触ったことがないのですが
知らん言語(TypeScript)、知らんフレームワーク(Koa, NestJS, commander)、知らんミドルウェア(Apache Kafka)、知らんその他諸々(Protocol Buffers, Terraform)を使ってるチームに移動して難易度が高めな課題に取り組むことになったため、効率的に技術をキャッチアップできないと終わると思いヒィヒィ言いながらがんばったことを共有します

やったこと

座学の時間をガッツリとる

まずは手を動かす方が有効な場面もありますが、その技術の設計や哲学、全体像を把握してから実践に移る方がスムーズなこともよくあると思います。
特に今後長く付き合う技術であれば、ドキュメントをしっかり読む時間を早めに取っておくと色々と捗ると思っているので主要な技術に関しては座学の時間を多めにとりました。

ライブラリやフレームワークは、公式ドキュメントをあらかた読み切る

ライブラリやフレームワークはドキュメント量がそこまででもない場合が多いので、主要なページはひととおり全て目を通します。
こういう学習コストが低いものに関しては公式ドキュメントをとりあえず全部読むのは個人的にはオススメムーブです。

言語やミドルウェアなど学習コストが高いものは書籍にあたる

言語やミドルウェアはドキュメントの量が膨大であることが多いので、そういった場合は書籍にあたると重要度の高い情報に絞られていて学習の効率が良いと感じます。
(もちろん公式ドキュメントも読んだ方がいい)

雰囲気でいけそうなやつは後回しにする

キャッチアップしなければいけない技術がたくさんある場合は、優先順位をつけて一部の技術に見切りをつけることも重要かなと思います
Terraform に関しては参考にできるコードが社内に多くあり、かつ既存のコードの枠組みに乗れば十分そう(=新たな設計が必要なさそう)だったため、概要をざっくり把握する程度で一旦 OK としました。

期待値調整をする

自分はこの技術についてどこまで知っているのかをざっくりにでも共有しておかないと、工数の見積もりに悪影響が出たり、コードレビューの前提知識をどこに置くかがわからなくなってしまうため 「この技術のこと、全く知らないぜ!」とちゃんと共有するようにしました。

学習の共有

「今この記事を読んでいる」などを共有することで、知見のあるメンバーから「こっちの記事の方がオススメ」といったアドバイスをもらえたり、自分の理解度が周囲に共有される効果もあってオススメです。

言語仕様に慣れれば、得意な言語と同じくらいの生産性に戻る...わけではない

使う言語を本格的に変えたことでわかったことは、僕は PHP だけではなく PHP を取り巻くエコシステムやコミュニティといった文化にも慣れていたということです。
TypeScript はモジュールシステムなどはかなり体感が違うものの、おおまかな構文は PHP と近く「とりあえずロジックを組み立てられるようになる」というところまではあまり苦労しませんでした。

それでもいくつかのポイントで生産性の低下を感じ、言語だけではなく言語の文化に慣れないといけないということを身をもって知りました。

ライブラリ選定に大幅に時間がかかるようになった

PHP であればこの組織が出してるライブラリは品質が良いということを把握していたり、PSR という安定した抽象に準拠したライブラリであればとりあえずで導入しても乗り換えやすいだとかそういった知識をもとにそこまで時間をかけずにライブラリの選定を進めることができました。
しかし、言語が変わるとそもそもデファクトスタンダードを知らないのでそこから調べたり、デファクトスタンダードがないこともあるので複数のライブラリのソースコードを読んで自分で品質を評価したり、評価してるうちに品質の良さの基準(というか文化?)が PHP とは違うっぽいということに気づいたり(JS はモジュールが状態を持つようなデザインが多い気がする)で、PHP 時代に比べて異様に時間がかかるようになりました。

細かい試行錯誤が増えた

言語仕様とは別に TypeScript らしいコードを書こうとした結果、ちょっとした書き方、モジュール設計のノリ(?)の微調整、ファイル名・ディレクトリ名の命名規則(snake_case, PascalCase)、object にすべきか class にすべきか、などなど、慣れている言語では発生しなかった試行錯誤が自然と多く発生するようになりました。
これによって作業が一瞬止まることが度々発生して集中力に悪影響があったり、細かい部分で全体の統一感がなくなるなどが発生してしまいました。

これまでの経験で活きたこと

知らん技術まみれだったのでキャッチアップにどれほど苦労するのか不安に感じていましたが、いざキャッチアップを始めてみると想像よりスムーズに行ったものも多かったです。

これらの多くは1つの技術を深めに学習していたおかげだったので、深く学ぶことは大事だなと改めて感じました。

PHP などで培われたプログラミング言語の基礎的な知識

PHP から TypeScript への切り替えであれば流用できる知識がかなり多かったので「とりあえず動くコードを書く」程度であれば障害はあまりなかったように感じました(ただし環境構築を除く) Haskell などの純粋関数型言語に切り替わるレベルの変化でない限りは言語が変わっても流用できる知識はめちゃくちゃ多いんだなとわかりました。

  • 構文
  • 式と文の違い
  • 型の知識
    • 主に PHPStan に鍛えられました。PHPStan 最高!
    • PureScript とかを遊びで触ったのも良かった気がする
  • etc

ただ、型システムに関しては TypeScript は PHP に比べてかなり独特なので、型演算周りはもうちょっと学習が必要そうだなとなっています
(が、 Web アプリケーション開発では型パズルが求められる状況はそんなにないと思っているので、のんびり学べばいいかなと思います)

Web フレームワークの知識

今回は同時に 3 つのフレームワークを使えるようにならないといけなかったのですが、PHP のいくつかの Web フレームワークソースコードを読んだり、個人的にちょっとしたフレームワークを作ったり、オレオレフレームワークの現場でフレームワークレイヤのコードをいじったりした経験があったので
ドキュメントを読んでフレームワークの哲学やリクエストのライフサイクルなどを把握するだけでとりあえず動かすことができる程度には理解が進みました。

おわりに

この記事では知らない知識をキャッチアップする際に僕が意識して実践したことを共有してみました。
中でも座学の時間をしっかり取ったのは一番効果があったように感じています。
目の前に開発タスクがあると焦って手を動かすことを優先してしまいがちなんですが、一回体系的に知識をインプットしておかないと開発スピードの伸びが悪いように感じます。
今回は焦る気持ちを抑えてしっかりドキュメントなどを読んだことで割と早い段階でとりあえず開発はこなせる状態に移行でき、その先の「その言語特有の設計の勘所」のような座学からは学びにくいステップに進むことができました。

まだまだキャッチアップしないといけないことが山のようにあるので、引き続きがんばっていきます!
完!

DynamoDBに入門したい

そろそろDynamoDBを触らないといけなさそうな雰囲気があったので、土日に勉強してみました。 勉強した順にリンクを並べていく

そもそもNoSQLって何

そもそもNoSQLとはってところから説明してくれている。 NoSQLの使い所やNoSQLの種類についてざっくり学べる www.youtube.com

DynamoDBの概要

めちゃくちゃわかりやすくてよかった。 完全にDynamoDBを理解した気持ちになれた dev.classmethod.jp

Dynamo DBの基礎知識から始まり色々説明してくれておる

www.slideshare.net

データ設計まわり

デザインパターン的なのを紹介してくれている www.youtube.com

公式のベストプラクティス集
docs.aws.amazon.com

実際に動かしてみる

ローカル環境

Dockerでいける。npmでGUIも簡単に手に入る。

qiita.com

PHPから扱う場合はここらへんを見ると良い

docs.aws.amazon.com

来週DynamoDBを使って何かしらのアプリケーションを作るぞ〜

ロジックを書くときは抽象度を揃えるように気を付けている話

この記事はスターフェスティバル Advent Calendar 2021 の19日目です。

qiita.com


尽く会社と関係のない話ばっかりしていてアレですね。 抽象度揃ってる方がイイヨーみたいな話をレビューとかでたまにしているので、ちゃんと言語化しよーと思ったのでブログに書くことにしました。

自然言語で考える

抽象度を揃えるというとなんか難しそうな雰囲気がありますが、日常会話で無意識にやっていることをプログラムでもやってみようくらいの感覚です。

例えば今日の予定を家族に伝える時は「今日は友人とご飯に行ってくる」みたいなことを言うかと思いますが、こういうのが抽象度が揃った状態かなーと思います。

じゃあ抽象度が狂うとどうなるのかというと「2021年11月15日11時15分に家を出て11時30分発○○行きの電車に乗って○○駅で中学の頃から仲の良い○○くんと合流した後、東京都○○区○○1−2−3○○ビル6Fにある○○っていう中華料理屋に行ってエビチリを食べてくる」みたいな感じになります。たぶん。

これは抽象度が下がりまくった結果情報量が増えまくって文章が読みにくくなるパターンですね。

逆に抽象度を上げまくってみましょう。 「友人」は生き物として抽象化することができそうですね。「ご飯」はwikipediaによると料理を作ってくれた人の愛を実感するための行為でもあるらしいので、愛を実感する行為として抽象化しましょう。 「今日」は...わからないけど今年とかにしておきましょうか。

そうすると「今年中に生き物と愛を実感してくる」みたいになります。こいつ大丈夫か。

抽象化を繰り返すと情報が減っていくので、この場合は情報が減りすぎてもはや意味がわからなくなっているパターンですね。

日常生活では、伝えたい内容から必要な情報だけを取り出し(抽象化)、それを言語化するというのを無意識に行っているわけですね。たぶん。

めっちゃ極端な例を出してみましたが、プログラムだと意外と似たようなことをやってしまうことがあるんですね。

プログラムで考える

じゃあプログラムだとどうかというと、ユースケースのような手続きっぽくなりがちなクラスだとわかりやすいです。

例えば、会員登録みたいなユースケースを考えてみます。 これを言葉で説明すると 「メールアドレスの重複がないか確認して重複があればエラーを返し、重複がなければパスワードをハッシュ化したのち入力値から会員を作成する」みたいな感じになるのではないでしょうか

<?php

class RegisterUser
{
    public function run($input)
    {
        // メールアドレスの重複をチェック
        // 重複していたらエラーを返す
        // パスワードをハッシュ化する
        // 入力値から会員を作成する
    }
}

ですが、いざコードを書いてみるとこんなことになったりします。

<?php

class RegisterUser
{
    public function run($input)
    {
        $records = $this->database->table('users')
            ->where('email', '=', $input['email'])
            ->execute();

        if ($records !== []) {
            throw new ValidationException('メールアドレスが重複しています。');
        }

        $hashedPassword = password_hash($input['password'], PASSWORD_DEFAULT);

        $this->database->table('users')
            ->insert([
                'name' => $input['name'],
                'email' => $input['email'],
                'password' => $hashedPassword,
            ]);
    }
}

これを読んでみると「usersテーブルからメールアドレスが一致するレコードを取得し、レコードが空じゃなければエラーを返し、空であればパスワードをPHPのデフォルトアルゴリズム(bcrypt)でハッシュ化し、入力値からusersテーブルにレコードを追加する」のようになるので、最初の説明と随分かけ離れてしまいました。

先ほどの例の具体的になりすぎて情報量が増えて読みにくくなってるパターンと同じですね。

まぁこの程度であれば読めね〜!ってこともないのですが、アプリケーション全体がこのノリで書かれていると脳のメモリを圧迫されるのでしんどくなってきます。

例えば以下のコードはメールアドレスの重複をチェックする意図を持つロジックですが、作者の気持ちを考えなさいみたいな感じのコードなので、書いた人の意図をがんばって想像しながら「レコードが0件ではないという状況はメールアドレスが重複していることを示すのだ」と自力で翻訳する必要があり、このような翻訳が頻繁に必要になるとコードを読む負荷がグイングインと上がっていきます。

<?php
$records = $this->database->table('users')
    ->where('email', '=', $input['email'])
    ->execute();

if ($records !== []) {
    throw new ValidationException('メールアドレスが重複しています。');
}

このロジックでは「重複チェックをした上で何をするか」という行為に興味があるのであって「具体的にどのような方法で重複チェックをするのか」こういった情報は不要です。(個人的な意見です)
なのでこの場合はちゃんと必要な意味を抜き出し抽象化してあげるとよいと考えています。

<?php

class RegisterUser
{
    public function run($input)
    {
        if ($this->duplicationChecker->isDuplicated($input['email'])) {
            throw new ValidationException('メールアドレスが重複しています。');
        }

        // ...
    }
}

どうでしょうか、こうすれば意図が明確なので作者の気持ちを考えなさいというコードではなくなった上に、他の箇所でも同じロジックを使いまわせるのでDRYの観点からも望ましそうです。

とまぁこんな感じで、このロジックを説明する上で必要最低限の情報ってなんだろうみたいなところに注目してコードを書いていくと、抽象度が揃っていって可読性が上がったり関心の分離ができたりするのかなーと思っております

<?php

class RegisterUser
{
    public function run($input)
    {
        if ($this->duplicationChecker->isDuplicated($input['email'])) {
            throw new DuplicatedEmailException();
        }

        $hashedPassword = $this->passwordHasher->hash($input['password']);

        return new User(
            $input['name'],
            $input['email'],
            $hashedPassword
        );
    }
}

おわりに

抽象度を揃えることを個人的に気を付けている話をしましたが、みんなが気を付けていることも知りたいですね。教えて〜!