見出し画像

分かりやすい構造化プログラミングのコツ

こんにちは。ゼバ会です。
本日のテーマは「分かりやすい構造化プログラミングのコツ」です。

要は、デバッグしやすかったり、バグが出にくかったり、仮にバグがあってもそれが判明しやすかったり。
そんな明朗な構造にするにはどうすればいいか、という話。

さて、私が初めてエンジニアになったのは、今をさること25年前。
バブル経済と呼ばれる一大好景気が一気に吹っ飛び、風雲急を告げ日本中が蜂の巣をつついたような騒ぎとなっていた頃のことです。
それまで、「日本はこれからも絶好調であり続ける」と言われて育った私達の世代みんなが、あらゆる夢をどんでん返しされながらも懸命に就職活動したあの頃のことでした。

そのような時代に巧く立ち回れる大人なんてものがそうそういたわけもなく、よって当時はIT業界も全体的に混迷期だったのです。

仕事の指示なんて「あとよろしく」の一言くらいしかないのは当たり前。
何も教えてもらってないのに、問題が出たときだけエンジニアの責任にされるのも当たり前。
飛行機が墜落したり金融システムがシャットダウンしたりすると、ニュースでは「システムの不具合が原因」と、まるでエンジニアだけが悪いかのように報道されました。

ついでに映画やアニメの世界でも、当時はコンピューターが「人間を超越した何か」という役回りを演じるケースが多く、要は社会全体がコンピューターとかエンジニアといったものに対してそういうイメージを持っていたし、知識レベルだってたかが知れていたし、非エンジニアがみんな「エンジニアは万能人間」と思い込んでいたわけですね。
まぁ、なんせ Windows95 だって販売されたばかりでしたのでね。
クッキー? クラッカー? それってクロテッドクリームにつけたら美味しいよね! の世界ですよ。
(なんならクロテッドクリームだって日本国内ではまだあまり知られてませんでした、、、)

当然ながらその程度の社会に「役割・責任を意識したチーム作り」のノウハウなんてありようはずもなく、ゆえに、いわゆる「名もなき業務」と呼ばれる類の仕事の全責任が全てエンジニアに降りかかってきてしまっていました。
なぜなら、当時多くの人達にとってエンジニアは完璧超人の別称だったわけですから、役割分担なんて必要がないはずだったんです。
エンジニアに任せておけば何とかなる。
それが当時の人達の基本スタンスでした。

はい。昔話おわり。

まぁ、最近はかなり改善してきたとはいえ、現在でもかなり名残はありますよね。
エンジニアの責任が何かにつけて重すぎることを、日本中のエンジニアはいつもブーブー文句言ってます。
あなたも言ってるでしょ?
俺もよ。
まぁ、上司に不満のないエンジニアなんて、世界中探したって1人もいないだろうね。

たださ、、、、、?
少し考えてもらいたいことがあるわけなんですよ。

チームビルディングが下手くそすぎることについて、あなた自身も上司に不満があるかもしれません。
が、、、ちょっとお聞きしたいのは、あなた自身が「自分が作ったプログラム」のチームビルディング、きちんとできてる?
コードを書くとき、「メソッドのビジネス上の責任範囲」ってものをちゃんと意識できてるかい? ってこと。

〇そもそも「責任」とは、の部分

さてここで、「責任」という言葉の意味を再確認しましょう。
日本語の「責任」って言葉は意味が独り歩きしがちで、みんなが持ってるイメージは本当にバラバラです。

「ちゃんとやること」くらい思ってる人はまだいい方で、「完璧な状態を維持する義務」「正しい状態を逸脱しない義務」「すごいことをやってのける義務」とかとか、他にも「正体不明の凄く重いもの」と思ってる人も結構います。
が、少なくともこれらの例はどれも違います。

小学館のデジタル大辞林では3つの意味が載っていて、その中の「1番」が今回の話に一番つながりやすいかな。
1 立場上当然負わなければならない任務や義務。

が、これもちょっと書き方が曖昧すぎる。
まぁ、国語辞書の執筆者は間違ったことが書けないので、曖昧にせざるを得なかったんでしょうけど。。。

でも、もっとシンプルなんですよ。「責任」ってのは。
責任とは、「成功させる」と宣言したことについて、成功するまで取り組むこと、です。

これでいいんです。
責任ってのは本当に単純な話で、「やるって言ったよね。じゃあやって?」ってだけのことなんですよ。

業務指示を受けるとき、「はい、分かりました」って言いますよね。
言った以上は成功させましょう。ってことです。
あるいは、もし成功できないのなら「できる」なんて言わないこと。
もしくは「どこまでならできるか」を、相手に分かるように宣言すること。

そのうえで成功させること。
それが「責任」というもので、これは「メソッド構造」に関しても全く同じことなんです。

〇責任を意識したメソッド構造を作る

たとえば、メソッド名に getAllAccountNames (全アカウント名を取得)って名前を付けたんだったら、「どんなことがあっても確実に全アカウント名を返すこと」が、そのメソッドの責任です。
ついでにメアドも付けちゃおう! とか、フラグが false だったら略称ね! とか、アカウントが1つもなかったら特別な名前を返すよ! とか、そんな余計なことしなくていいんです。
「全アカウント名を取得」というメソッド名である以上は、全アカウント名が取得できれば責任達成なわけです。

逆に言えば、そういう名前である以上はそれ以外の動きをしてはいけないということでもあります。

「全アカウント名を取得」という名前のメソッドが気にしなきゃいけないことは、いかにサービス全体を意識した汎用的な挙動をするかではなく、「自分が何をすれば、次のメソッドが正しく業務遂行できるか」だけです。
サービス全体を見渡すのは人間であるあなたの仕事で、メソッド1個にはそこまで大きな責任はありません。

そうして、全てのメソッドが「自分の責任を確実に果たす」ことに集中することで、晴れてサービスは正常な動きをするのです。
それが責任を果たすということで、ゆえに「余計なことをするヤツが1人でもいると」「システムはたまに狂う」わけです。

〇責任とは、「手順に忠実である」ということ

ですのでプログラムが正しく自分の責任を果たすためには、要は「手順通り」に動いていればそれでいいわけです。
何ごともシンプルに考えることが大事です。

ケリー・ジョンソンは言いました。
「キスはいつでもタイフーン!」

。。。あれ、言ってない?
そうそう、彼が言ったのは Keep It Simple Stupid!(そこはシンプルにしとけバカちんが)で、これが工業製品づくりにおける「KISSの原則」として現在でも語り継がれています。

プログラム作りも同じ。
発想はシンプルに、要点はしっかりと、ね。
たとえばこんな↓感じの削除処理なら、本当の意味で「この通りに動いていれば責任達成」です。

1. 全アカウントの名称を表示する
2. ユーザーに、削除対象となるアカウントをマークさせる
3. 意図して削除しようとしていることを再確認する
4. 削除処理を行う
5. 削除が完了したことをユーザーに報告する

もちろん、これら 1. ~ 5. の手順1つ1つの中にも一筋縄ではいかない箇所もあって、おそらくはさらに細かい「小手順」に分解されたりするでしょう。
もしかしたら小手順の1つも、さらに細かくなるかもしれません。

ですが、だったとしても、「順番通りに処理をこなせば責任達成」というプログラムの大原則だけは、絶対に揺らぐことはありません
ですのでメソッド1つ1つは、「そこに書かれた指示を確実に達成できる」ように組む。
順番に、1つずつ。
その肝心の順番が不明瞭なときは、先に順番をまとめてから作り始めればいいだけのことなのです。

そのあたり変に頑張ったりしない。それ以外の余計なことをしない。
それだけでいいのです。

で、そのような構造にしやすくするための構造のことを世の中では「クラス」と呼び、それを駆使したプログラミングのことを「構造化プログラミング」と呼ぶわけです。

〇そんな簡単に言うけどさ、、、

とはいえ、そんなん言われたって「メソッドの責任」なる概念をすぐに理解するのは難しいでしょう。
とりわけエンジニアとしての経験年数が少ない人は特に、今のところまだ「なんのこっちゃ」って感じでしょう?

なので、責任の概念が分かってなくても、とりあえず「分かりやすく」「シンプルで」「バグが出にくいことが目で見て分かる」ような状態を作りやすくする秘儀をお教えします。
これを守っていれば、難しいこと考えなくてもバグの減るプログラムが書けます。

それは「1メソッドあたりの大きさを制限する」ことです。
メソッド1つ1つが小さければ、ロジックは複雑になりようがなくなります。

私のおすすめは Cyclomatic complexity と呼ばれるものを小さくすることです。
この Cyclomatic complexity ってのはメソッドの複雑度合いを測るための数値なんですが、こいつを十分に小さくすることを義務にすれば、プログラムはそもそも複雑に書きようがなくなります。
世の中的にはこの数値を 10 以下にするのが望ましいとされてるらしいですが、そこまで小さいとさすがに業務に支障をきたすケースが増えるので、個人的なおすすめは 20 です。

ですがこの Cyclomatic complexity は、理解するのに10分だか20分だか、そんくらいググってオベンキョしてもらわんといかんとです。
(概念的にちょとムツカシいアルね)

なので、そんな暇すらない忙しいあなたは、単純に行数でもいいかもしれません。
使い勝手は少し悪くなりますが、「1メソッドを最大でも20行以上書いてはならない」とか、そんくらいの制約をつけると、プログラムは必然的にコンパクトにまとめざるをえなくなり、複雑なメソッドが存在することを防げます。

この Cyclomatic complexity は、本当はチームで話し合って開発標準にルールとして組み込んでしまうのがいいんですが、個人的なルールってことにするだけでも違います。
まぁ、まずは「意識的に心がける」くらいのスモールステップから始めるのもいいでしょう。

そうやってメソッドを小さく作るクセをつけていくと、あるときふと気づくはずです。
「このメソッドは何を果たせば責任達成なのか」と「この処理の後ろで何をすべきか」の2つが、とても分かりやすいことにです。

システムをバグの出にくいものにしていくのに大切なのは、あくまでも「手順に忠実」であることです。
手順を定め、その手順1つ1つを確実にこなしていく。
あくまでも「手順を守る」ことを最優先にする。

それが「ていねいな仕事をする」ということの意味です。

〇次回予告

そうはいってもね。
そんなに手順通りにばかりやってられないことはあるでしょう。

とりわけ難敵なのが「ていねいにやりすぎると処理帯域に無駄が出る」という問題。
たとえば、1度に2つの処理が走るプログラムで、その2つの関連性が薄かったとしましょう。
でもその2つの処理が、どちらも同じテーブルからデータを取ってこないといけなかったとしたら、人情としては1度のテーブルアクセスで済ませたくなるものです。
たとえば、「権限チェック」と「データ取得」の2つの処理があって、権限チェックに合格したらデータを取っていいという処理を書くとき、権限データと欲しいデータが両方とも同じテーブルにあったら、SELECTは1回で済ませたいでしょう。

でもこれ、やっちゃダメな動きです。
2つの処理に責任上の関連性がないわけだから、それを混ぜたらバグが出やすくなります。
こういう例に限らず、既存のルールを守るよりも「もっと上手くやる方法がある気がしてならない」って考えが止められないときはあるでしょう。

でもダメなの。
ルールというのは順守することが大事なのではなく、そのルールができた理由の再発を防ぐことが重要なのです。
ですから、ルールができた理由を知らない人が、安易にルール破りをしてはいけません。
これはコードルールに限らず、法律でもなんでもそうです。

プログラム組んでて、ルールより自分のやり方を優先したい気持ちになることが多い人は、あらゆるメソッドを小さく書くのはすぐには難しいはずです。(頭の中でまとまらないことを、自力で無理やり何とかしようとする癖があるってことだからね)

なのでその前に、まずソースコードをキレイに書くテクニックを覚えるのが大事でしょう。
それくらいなら大きな労力もなく改善していけるはずです。

てなわけで次回は、「美しいプログラムとは何か」について語っていきます!

そう、それはまさに「美の定義」!!
なんという暴挙! なんという神への冒涜!
でもやっちゃいます!!
お楽しみに!

この記事が気に入ったらサポートをしてみませんか?