リーダブルコード
初心者
新人プログラマ応援
クリティカル・シンキング
84
どのような問題がありますか?

投稿日

更新日

あなたのコード複雑怪奇になっていませんか?

どんな記事か?

こちらのイベント参加の記事になります。

筆者自身の経験をもとに、コードのシンプルさを保つために難しい技術的な部分ではなく、誰でも意識しだいで取り組めて、プログラミンをする上で重要だと感じたことを記事にさせて頂きます。

KISSの原則

いきなりですが、KISSの原則をご存知でしょうか。

有名な原則のうちの1つで、「Keep it simple stupid」の頭文字をとったものです。

直訳すると「簡潔にしておけ、この間抜け」となりますが、「シンプルさを追求すべきだよね」という原則です。

コードが複雑になると、複雑さ自体がリスクとなります。

ここでいうリスクとは以下を指します。

  • 拡張性が低く使いづらい
  • コードの可読性が低く読みづらい
  • 開発・保守のコストが高い

コードが複雑になりやすいケースとは

sick_noiroze_man.png

では、コードが複雑になりやすいケースとはどんなケースでしょうか?

もちろんプロジェクトや環境によって異なりますが、大きく分類すると以下の4つかなと思います。

  1. 仕様そのものが複雑なケース
  2. 言語やフレームワークへの知見が少なく、複雑になってしまうケース
  3. リーダブルコードや設計(ここではレイヤーを指します)への知見が少なく、複雑になってしまうケース
  4. 前提が間違っており、間違ったまま進めた結果、コードが複雑になってしまうケース(今回取り上げるケース)

それぞれのケースを解説

presentation_shikibou_man.png

それぞれのケースを解説いたします。

1. 仕様そのものが複雑なケース

まず、「仕様そのものが複雑なケース」です。

大規模なアプリなどリッチなものを作ろうとすると、どうしても仕様が複雑になってしまいます。

仕様が複雑である場合、あたり前ですがそれを実現させようとするコード自体も複雑になりやすいと言えます。

対処法

交渉できる余地があれば、要求レベルをなるべく落とさずに仕様を簡単な方向へ倒すなど対応が必要です。

交渉できる余地がなければ、できる範囲で複雑にならないように実現するしかありません。

また、ハードルはかなり高くなってしまいますが、頭の良い先人たちがプログラマが遭遇する同じような問題を解決すべく、パターン化された「デザインパターン」を適切に取り組むことも手段の1つだと思います。

2. 言語やフレームワークへの知見が少なく、複雑になってしまうケース

続いては、「言語やフレームワークへの知見が少なく、複雑になってしまうケース」です。

機能を実現させるコードを簡潔に記述する術がわからず、「あぁでもない、こうでもない」とゴニョゴニョ遠回りしてしまうケースです。

(簡潔 = ワンライナーではございません。筆者は過度なワンライナー否定派です)

対処法

これは単純に経験と知見を蓄えていくしかないため、自分で色々勉強しながら、優しい先輩に教えてもらいつつ、蓄えていきましょう。

新しい気づきや教えてもらったことは、忘れないようにしっかりメモして引き出しを増やしていきましょう。

3. リーダブルコードや設計への知見が少なく、複雑になってしまうケース

続いて3点目は、「リーダブルコードや設計への知見が少なく、複雑になってしまうケース」です。

設計とは大きな枠ではなく、レイヤーのことを指しています。

レイヤーについては深堀致しませんが、View層であれば「関心ごとが見た目だけになっていて、ビジネスロジックとは切り離されているか」、などです。

つまり、「適切な関心の分離」がなされているかになります。

また「リーダブルコード」とは、オライリーから出版されている書籍です。

リーダブルコードには、命名についてや単一責任の原則などすぐに取り組めて且つ、効果の大きな手法が数多く記載されています。

個人的には、全プログラマーにおすすめしたい書籍で多くの学びがあります。

対処法

レイヤー云々は全体を見渡す必要があるため、先輩にしっかりと教えてもらいながら、ぼんやりとでも意識できるようになれれば良いかなと思います。

最初の頃はリーダブルコードの手法を実践するだけでも、コードのシンプルさを保てるようになると思います。

筆者がかなり初期の頃に、簡単にまとめた記事がございますので、リンクだけ載せておきます。

4. 前提が間違っており、間違ったまま進めた結果、コードが複雑になってしまうケース

最後に、今回取り上げるケースになります。

こちらに該当するのは、仕様が複雑ではないのにコードが複雑になってしまうようなケースが該当いたします。

難しい技術的な話ではなく そもそもやろうとしている前提が誤っていれば、当然アウトプットされるものも間違っているよね という内容です。

例えばですが、「仕様を正しく理解しておらず、なんとなくコードを書き始めたらコードがごちゃごちゃになってしまった」など。

対処法

では、前提が正しいかどうか? をどうやって判断すれば良いのでしょうか?

ここからは、筆者が有効だと感じた、「クリティカルシンキング」について述べさせていただきます。

クリティカルシンキングとは?

kangaeruhito.png

まず、クリティカルシンキングとは?ですが、批判的思考法 と呼ばれています。
批判とは決して「攻撃的に批判する」ということではなく、ソースに対して常に疑問を持つ思考法の1つです。

そのため、目的を常に意識して「そもそも何を作ろうとしているのか?」と一度立ち止まって、本質を深堀していく思考法です。

Screen Shot 2022-04-23 at 14.42.20.png
出典元)https://manetore.net/glossary3815/

クリティカルシンキング特徴

クリティカルシンキングの簡単な特徴です。

  • 批判的思考法
    • 攻撃的という意味ではない
    • ソースに対して常に疑問を持つこと
  • 目的を常に強く意識する
    • そもそも何のためにやるのか
    • そもそも何を解決させたいのか
  • 考え方のクセを理解する
  • 本質まで考え続ける
  • 目的達成のための思考法などと呼ばれる

ロジカルシンキングとの違い

思考法のフレームワークとして「ロジカルシンキング」がございますが、ロジカルシンキングとクリティカルシンキングとの違いについてです。

Screen Shot 2022-04-23 at 14.52.47.png
出典元)https://dyzo.consulting/5222/

上記図を見ていただいてわかるように、ロジカルシンキングは複数のソースや前提から積み上げて結論を導き出したり、逆に1つの問いからツリーを複数生やして思考を広げたりする手法です。

一方のクリティカルシンキングは、「そもそもの前提が正しいのか?」を常に問い続けます。

根本や前提が違えば、導き出されるものは全く違ったものになってしまう

ロジカルシンキングでいかに筋の通った結論を出したとしても、前提が間違っていれば導き出されるものも当然間違ってしまいます。

仕様が複雑ではないのに、コードが複雑になってしまうのは経験上このケースが該当すると感じます。

クリティカルシンキングで前提を見直してみる

juuryoku_newton.png

クリティカルシンキングを用いて前提を見直す際に、筆者が留意している点がございます。

  • そもそも何を実装 / 解決したいのか
    • 仕様自体を正しく把握できているか
      • 誤った認識で誤った機能を作ろうとしていないか
    • 仕様が複雑すぎるのであれば、要求レベルを落とさずに仕様をシンプルな方向へ打診してみる
      • 何を実現させたいのか、仕様を正しく理解できていれば仕様レベルでの打診ができるようになる
  • そもそもコードを書いているレイヤーは正しい場所か
    • 例:View層にビジネスロジックが混じっていないか
      • 使う側に知識があるとバグの元となり、保守も大変
  • そもそも性質の違うものを無理に共通化しようとしていないか
    • アクターは誰なのか?
    • 元々違うドメインのものを合体させようとすると、歪になる
  • etc...

これらに留意することで、コードが複雑になっている時点で、前提が誤っていないか立ち止まって振り返ることができます。

実際に筆者が陥ったケース

実際に筆者自身が、陥ってしまいコードの複雑さと格闘していたケースです。

  • やろうとしたこと
    • 共通コンポーネントを作成したい
    • 共通側はどんなデータかを知る必要がないようにしたい
  • 前提が誤っていた時の状況
    • usecase層で記述していたが、デザイン(UI)があったり、componentに依存方向が向いてしまっていた
    • 実装を進めていくと、共通コンポーネントなのに、ジェネリクス以外の具体的な型があったり、TypeScriptの型を実装のために捻じ曲げてオプショナルにしてしまったり、本末転倒な状態になっていた
    • コードが複雑怪奇で実装にも時間がかかっていた
  • 根本を見直した後
    • usecase層ではなく適切なレイヤーへ置いた
    • 実装のために型を捻じ曲げる必要が無くなった
    • 不要なコードがなくなり、見通しがよくなった
    • 結果コード自体がシンプルになった(KISSの原則)

このように、コードが複雑になっているなと感じた時点で、前提を見直していくことで、コードをシンプルに保つことができました。

まとめ

今回のまとめです。

  • KISSの原則とは
    • 「コードはシンプルにしよう」と言う原則
  • コードが複雑になりやすいケースとは
    • 仕様そのものが複雑なケース
      • コードも複雑になりがち
    • 言語やフレームワークへの知見が少なく、複雑になってしまうケース
      • 思ったようにコーディングできなくて、ゴニョゴニョなってしまうケース
    • リーダブルコードやレイヤーへの知見が少なく、複雑になってしまうケース
      • 責務の分離や手法への知見が乏しいケース
    • 前提が誤っており、間違ったまま進めた結果、コードが複雑になってしまうケース
      • 今回取り上げたケース
      • 仕様はシンプルにも関わらず、コードが複雑になってしまうケース
  • クリティカルシンキングとは?
    • 批判的思考法
      • 攻撃的という意味ではない
      • ソースに対して常に疑問を持つこと
    • 目的を常に強く意識する
      • そもそも何のためにやるのか
      • そもそも何を解決させたいのか
    • 考え方のクセを理解する
    • 本質まで考え続ける
    • 目的達成のための思考法などと呼ばれる
  • コードが複雑になっていれば、一度立ち止まって前提を見つめ直してみる

最後に

コーディングしていると、目の前の機能実現に向けて一杯一杯になり、視野が狭くなってしまう時がどうしてもあると思います。

しかし、客観的にコードを見つめ直してみた時に、「コードが複雑になっているな」と感じることがあれば、一度立ち止まって前提を見直してみることをおすすめいたします。

経験が浅ければコードが複雑になっていることすら気づかないケースもあるでしょう。

その時は書籍を読んでみたり、ちゃんとしたレビューを受けたりして、 まずは「気づけるようになること」 を目標に、焦らずゆっくり経験を積んでいきましょう。

諸先輩の皆さん通ってきた道です。

諦めず正しい方向性で努力すれば、必ず点と点とが結びついて「そういうことだったのか!」となる時が必ず訪れます。

「継続は力なり」です。

以上、新人プログラマ応援 イベント参加の記事でした。

undoukai_ouen_boy_white.png

ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
ユーザー登録ログイン
tak001
ペーペーエンジニア。メインはWebフロント屋。

コメント

ベースになる別の言語からのコンバージョンを自動生成されているソースコードとか読む気が失せますよ。
また、チェーンメソッドを多く使ってなんかうまくやろうとしているのはいいけどみたいなコードも....。
1行でかっこよく書くのは初心者には読むのは相当つらいですよ。
たまにはだれかがコードメンテナンスをしてよりよいコードを目指すほうがよいかと。

0
(編集済み)

中途半端にプログラミングを分かった気になっている人ほど、読みにくく分かりにくくバグが入りやすく改修が難しいコードを書きます。

例えば

  • ある西暦(整数)を入力すると、それがうるう年か、そうでない(平年)か、を判定するプログラムを作成せよ。
  • うるう年と判定する条件は、以下のとおりである。
    A: 4の倍数の年は、うるう年
    B: ただし、100の倍数の年は、うるう年ではない(平年)
    C: ただし、400の倍数の年は、うるう年

という命題に対して、

カルノー図を書くと条件が理解しやすくなるのではないかと思います。

と言いながら、

year = int(input())
if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
    print("うるう年です。")
else:
    print("うるう年ではありません。")

こういうコードを書いてしまう。条件がそれ以上変わらない前提なんです。
それ、初心者向けの演習問題だから成立しているだけですよ、っていうところが分かっていません。

業務でコードを書いていれば、

  • 2022/4/28仕様変更
    D: ただし30の倍数の年は、うるう年
    E: ただし、30と4の倍数の年はうるう年ではない
    F: D, Eは2025年より適用する
         :

みたいな条件が後から足されてきます。
その時に

if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:

こういうコードが書かれてあると、拡張が非常にしずらい。バグも混入しやすくなる。
このやり方で条件を書き足していけば複雑怪奇になって行くのは目に見えています。

この記事の本文に書かれてある通りです。

  • 拡張性が低く使いづらい
  • コードの可読性が低く読みづらい
  • 開発・保守のコストが高い

仕様が提示されたら、その仕様に沿ってコードを書くのは業務でコードを書く場合の鉄則です。
仕様を粉々に砕いてミンチにしてしまったら、元に戻しずらいのです。

ですから、普通に仕事をしていれば

def isLeapYear(year):
  if year % 400 == 0: return True
  if year % 100 == 0: return False
  if year % 4 == 0:   return True
  return False

for year in range(1900, 2101):
  if(isLeapYear(year)):
    print(year, "うるう年です。")
  else:
    print(year, "平年です。")
    

まともな人はこういうコードを書きます。

ですが、自分本位で趣味の延長でコードを書いている人は自己満足から

if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:

こういうコードを書いてしまいます。

そのことを指摘されると、発狂し始めます。@error_401とかね。
極めて基本的なコーディング手法である『ガード』すら知りません。

だから世の中のシステムは大体どれもこれも不具合だらけで『どうしてこうなっちゃうの?』というような謎の挙動をする物ばかりです。

多くのプログラマが身勝手で自分本位なために、『仕様』とは経時的に変更されていくものという当たり前の教訓が、何年経っても身についていかないのです。

0
どのような問題がありますか?
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
記事投稿イベント開催中
新人プログラマ応援 - みんなで新人を育てよう!
~
データに関する記事を書こう!
~
84
どのような問題がありますか?
ユーザー登録して、Qiitaをもっと便利に使ってみませんか

この機能を利用するにはログインする必要があります。ログインするとさらに下記の機能が使えます。

  1. ユーザーやタグのフォロー機能であなたにマッチした記事をお届け
  2. ストック機能で便利な情報を後から効率的に読み返せる
ユーザー登録ログイン
ストックするカテゴリー