はじめに
前回の記事、たくさんの方が見ていただき、とても嬉しく思っております。
見ていただいた方には、誠に感謝しております。
https://qiita.com/tkdayo/items/5701013735c667d4cf03
8月になりましたね。
もう働き始めて3ヶ月になりました。東京での一人暮らしにも、ようやく社会人の生活リズムにも慣れてきました。
と言いたかったのですが、コロナに罹患し基本的に社会から隔絶されてしまいました(現在自宅療養中)。
ただ当社で柔軟な働き方が取れているおかげで、なんとか元気に新人施策に励んでいます。
さて、私は社会人になって、きれいにコードを書くための本を2冊買って読み終わりました。
- 良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方
- リーダブルコード
2冊とも、命名規則やコメントなどの非技術的な要素から、
クラスのメタプログラミング的な設計など、とても勉強になりましたが、
よわよわエンジニアの自分には、中には難しくて「???」となった部分もありました。
とはいえ、読んでいた中で、条件式についてのTipsがとにかく勉強になったので、それについてまとめます。
今回は自分の学習のためのアウトプットであったり、備忘録的な要素が強いです。
この記事の対象
- よわよわエンジニア→是非お役立てください。一緒に頑張りましょう
- 中級エンジニア→知らないのがあれば是非お使いください。お仕事お疲れ様です
- つよつよ・達人エンジニア→知らないことはないと思います。僭越ながら日々のコーディングのふりかえりにお使いください
- すでに読んだことあるエンジニア→復習にお使いください。読んだことない人より定着しやすいです
サンプル説明
概要
今回はReactで簡単に書いてみます。
よくあるチュートリアルのカウントアップアプリにアレンジを加えて、
より汚く書いたものが以下のものです。
動作としては、
- カウントを表示する
- 変数visibleをfalseにしたら、「閲覧不可」と表示される(動画にはない機能です)
- 偶数ならカウントともに「This number is even」と表示
- 奇数ならカウントともに「This number is odd」と表示
- 10の倍数なら「hogehogefugafuga」と表示
そして今回レビューの対象となる汚いコードはこちらです。
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const visible = true;
let str = "odd";
if (!visible) {
return <h1>閲覧不可です</h1>;
} else if (count % 2 === 1) {
str = "odd";
return (
<>
<h1>Count is {count}. This number is {str}</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
} else {
if (count % 10 === 0 && count !== 0) {
return (
<>
<h1>hogehogefugafuga</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
}
str = "even";
return (
<>
<h1>Count is {count}. This number is {str}</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
}
}
このコードの汚い点
さっと見て、少し考えてわかることは、
- 縦に長くてパっと見づらい
- 縦に長いネストがある
- return文が冗長になりがち
もちろんコード整形等で問題も解決できると思いますが、
今回は冒頭の2冊の本の知見を活用して解決していきましょう。
本題
1. 早めのreturnでelse if,elseを最小限にする(ネストを極力させない)
pogteやるにしろ、ドキュメント読むにしろ、
「条件が複数のときは else if句、条件以外に当てはまるときはelse句で書きましょう。」と
私たちは教わってきました。
しかしこれが可読性を低下させております。
それを解決するには、ネストさせる前に早めにreturnを返そう!!
というわけなのです。
実際に書き直してみましょう。
少し見やすくするために、return()
の中も調整します。
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const visible = true;
let str = "odd";
if (!visible) return <h1>閲覧不可です</h1>;
if (count % 2 === 1) {
str = "odd";
return (
<>
<h1>Count is {count}. This number is {str}</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
}
if (count % 10 === 0 && count !== 0) {
return (
<>
<h1>hogehogefugafuga</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
}
str = "even";
return (
<>
<h1>Count is {count}. This number is {str}</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
}
すごい見やすくなったってよりも、
「あーなんか若干見やすいかも」という印象になりましたね。
2. 条件は肯定形を使う
こちらはコードを読んでいる時に、
「これはこの変数の挙動とは反対のやつ」と読ませてしまうと、
この太字の部分にかかる認識のリソースが非常にもったいなくなります。
ですので、素直に読み下せるようなコードにしましょう。
条件分岐も、一度ロジックにして格納します。
(先程の早めなリターンは一度解除します)
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const visible = true;
let str = "odd";
function judgeCount(){
if (count % 2 === 1) {
str = "odd";
return (
<>
<h1>Count is {count}. This number is {str}</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
}
if (count % 10 === 0 && count !== 0) {
return (
<>
<h1>hogehogefugafuga</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
}
str = "even";
return (
<>
<h1>Count is {count}. This number is {str}</h1>
<button onClick={() => setCount(count + 1)}>click to add</button>
</>
);
}
if (visible) {
return judgeCount()
}else{
return <h1>閲覧不可です</h1>;
}
}
例題がよくなかったのか、あまり見やすくはなってないですね…
3. 三項演算子を使う
「短く書く」となると、やはり三項演算子に触れることが書かせませんね。
自分含め、条件分岐となると初心者エンジニアが最初に思いつくのは、
if文であることが多いです。
【条件分岐で書くとなった時の、初心者の自分の心情】
- 「条件分岐かあ」
- 「とりあえずif文書くかぁ」
- 「三項演算子はリファクタリングするときにでも書こう…(やらない)」
最初から三項演算子で書けるようになりたいですね。
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const visible = true;
let str = (count % 2 === 1) ? "odd" : "even"
let message = (count % 10 === 0 && count !== 0) ? "hogehogefugafuga"
: visible ?`Count is ${count}. This number is ${str}`
: "閲覧不可です";
let hidden = visible ? false : true
return (
<>
<h1>{message}</h1>
<button onClick={() => setCount(count + 1)} hidden={hidden}>click to add</button>
</>
);
}
段違いに短いコードになりましたね!!
三項演算子に習熟している人はかなり読みやすくなったのではないでしょうか。
余談
今回紹介したことが必ずしも有効とは限らない
今回紹介した原則は、必ずしもすべての組織やコーダー・エンジニアに当てはまるとは限りません。
例えば、最後に紹介した三項演算子のコードはif文で表すとif elseif else
というネストされた構成になってしまっています。
とはいえ、三項演算子を分割して書いてみると、
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const visible = true;
let str = (count % 2 === 1) ? "odd" : "even"
let messageCondition = visible ?`Count is ${count}. This number is ${str}`: "閲覧不可です"
let message = (count % 10 === 0 && count !== 0) ? "hogehogefugafuga" : messageCondition;
let hidden = visible ? false : true
return (
<>
<h1>{message}</h1>
<button onClick={() => setCount(count + 1)} hidden={hidden}>click to add</button>
</>
);
}
なんだかこれはこれで見づらいですね、、、
また、組織内のコード標準であったり、チーム内のエンジニアの好みによっても読みやすさが左右されます。
例えば、三項演算子が読みにくいから、わざとif else文
で書いたり、
多少のネストは気にしないなどの理由で、軽度なネストはあえてそのままにしない、
わざと条件式内で否定形にしておいたほうが見やすいなど、様々な理由があります。
ですので、チーム開発の際に取り入れる際には、周りのエンジニアとよく相談して採用するのが良いかと考えています。
個人開発のときは、自分の技術スタックとよく相談して利用するのが良いかと思ってます。
以上、主観による意見でした。
おわりに
組織での開発の際にも、上記3つのことを意識して条件文をかければなと思います。
技術書は隅から隅まで読むのが難しいですね。
技術書はスキルアップのためや、つまづいた時の参照物としてこれからも使えたらなと思ってます。
他にもきれいな書き方あれば教えてください。