プログラマが一人前になるとはどういうことかについて、考察してみました。
あるプログラムを書くときに、例えば3日かかったものが、次に同じようなプログラムを書くのにどの程度の時間がかかるのかは、人によってかなりの差があるような気がします。
次に同じ仕事をする時間が短くなればなるほど、プログラマは楽になっていくし、お客様にも喜んでもらえることになる、と思えば、仕事を早くするスキルを磨くのが大切なのだと思います。
開発生産性の向上とプログラムの共通化
真のプログラマとは
「真のプログラマは、再利用を考慮してプログラムを開発するもの」、とは自分が最初に仕事を始めた時に教えてもらった言葉で、今でもそれを心がけています。
「類似のシステムを作るときには、前回開発したシステムの違いを反映するだけで、システムが完成する」
もちろん、法的な問題もあるので、再利用は十分に気を付けるべきですが、基本的な考え方は再利用で、システムの開発効率の向上の一旦は、ソフトウェアの再利用が握っていると確信しています。
人間が一定期間内に認識できるコードの量には、おのずと限界があります。
認識力には、多少個人差があるのでしょうけど、実際には100メートルを10秒なのか、15秒なのかといった違いに過ぎないとは思われます。
しかし実際にプログラム開発の効率となると、1桁程度の違いは普通にあるような気がします。
2本足歩行は、日常だれもがおこなっていることで、プログラミングは日常作業ではないという違いはあると思いますが、1桁の差は別に全くの素人とその道のプロとを比較した結果でなくともよくみられます。
一桁違うとなると、どれだけ早くタイピングしようと限界はあるので、バグを発見する時間が短いとか、そもそもバグを出さないとかに加えて、優秀なプログラマのコーディングを除いてみると、コードの再利用が効いてきているようです。
再利用性の高いプログラムを作るためのポイント
それでは、再利用性の高いプログラムを作成するには、何に気をつけたらいいでしょうか。
開発者としての立場と、利用する側の両方の側面を考慮すると、よりよい部品になっていきます。
利用側面とは、使いやすさと開発生産性(どれだけ便利になるか)の追求になります。
利用側面
・シンプルなインターフェース
・同一機能はまとめて提供
・必要性があるなら高度な利用も可能
3つのポイントをあげました。
・シンプルなインターフェース
やりたいことに対して、複雑な引数を渡したりするのは不要です。
最低限やりたいこと、最大限やりたいことを想定して、パラメータを絞り込んだ部品にすべきです。
標準部品などは、汎用的に作成されているため様々なことができますが、開発対象のプロジェクトにとって不必要であれば、特定の値をデフォルト値で埋めてしまって、利用時には意識させないことが重要です。
たとえば、デバッグ用にファイルに追加でログを出力するとしたら、ファイル名やファイルオープンのモード等は不要で、書き込みたい文字列だけを引数にした関数を提供するだけで、十分です。
もし書き出すファイルを変更するニーズがあるのであれば、別に機能を容易するか、設定により変更ができるような部品にしておけば拡張ニーズにも耐えられます。
よくある例ですが、Pythonだったら、追加モードでファイルに書き込む場合。
try: with open(FILE_NAME, mode='a', encode='utf-8'): print(MESSAGE, file=f) except: pass
とやるところを、例えば
prjdbg.debuglog(MESSAGE)
だけで提供して十分ですね。
こうやっておけば、単体テストのときはファイルで十分だっのが、結合テスト以降でみんなでやるときには、非同期書き込みのログの実装に書き換えてやっても、各自の書いたコードは変更せずにすみます。
・同一機能はまとめて提供
同じ機能、似たような機能は複数提供しないということです。
先ほどのログだったら、debuglog があるかと思えば、debugwrite, debugprint と似たような機能がたくさんあると使う側がとまどいます。
また、デバッグ関係はまとめて提供とかある程度のまとまりでの提供が望ましいです。
・必要性があるなら高度な利用も可能
デバッグログでファイル名や書き込み先を変えたいというニーズがあって対応の余裕があるのであれば、機能としては、別に提供すれば、より利用者ニーズは満たします。
prjdbg.change_output_file(FILENAME)
とかでいいと思います。必要な人にだけ意識しれ利用してもらうのが、ポイントです。
次に開発者の側面です。
作り方としては、クラスを使う使わない、クラスで提供する、関数で提供するなどいくつかのパターンがありますが、これだけは注意ということで2つあげました。
開発側面
・同一レイヤでの独立性
・実装方法の一貫性(エラー処理、ログ出力等)
・同一レイヤでの独立性
これは、下記のようなイメージです。
横のレベルをレイヤとして、そのレイヤの間では独立して部品化して、利用するのはより下層の部品のみにするということです。
逆に横で連携したりする必要がるとしたら、独立性が保たれていないので、おそらくまとめて一つのクラスやパッケージで提供した方が、開発側も疎結合のほうがプログラムの複雑性が減るので保守していくのが楽になるし、利用する側もわかりやすくなります。
レイヤ | 事例 |
アプリケーションレベル | 販売管理パッケージ、生産管理パッケージ等 |
フレームワークレベル | 業務画面フレームワーク、管理画面フレームワーク等 |
業務共通部品レベル | 会社専用の認証部品、会社専用のDBアクセス部品等 |
共通機能レベル | テンプレートエンジン、表計算部品、認証部品等 |
汎用部品レベル | ログ出力、エラー処理、文字列操作、メール送付、通信部品等 |
・実装方法の一貫性(エラー処理、ログ出力等)
これは、一貫した共通部品は同じ考え方で実装していくということです。
ログを出すときに、ある人は自作でファイルをオープンしており、ある人は独自関数、ある人はプロジェクト共通関数を利用している、となると結局、そのレイヤは共通にはならない個別のものとして扱われているということになります。
最初から一貫して開発はすすめられないとしたら、リファクタリングしながら共通部品群として整備していくということを繰り返していけば、独自ライブラリが蓄積されていきます。
そうして作られた独自ライブラリは、その人、そのプロジェクト、そしてその組織の共通の資産になっていきます。
蓄積が進めば、最初は1か月かかっていた開発が、3日ですむということもでてくるわけです。
一定の時間内で開発可能なコード量にそう大差がないのであれば、どれだけ使いまわしできるか(それもコピーではなく、そのままで)生産性をあげる大きなポイントになります。
その先に、人の何倍もの生産性を出す、プロのプログラマの道がまっているのだと思っています。