Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

平均的プログラマ以前向けのスキル標準の提案

Java経験年数〇年以上のプログラマ募集」みたいなフレーズ、よく聞きますよね。で、そのフレーズで実際に人を募集してみて、来た人って期待どおりでしたか?

プロジェクトの体制構築、特にトラブル発生時の体制強化に必要な人材を集める場合、求めるスキルを示すのに「〇〇言語でプログラミングができること」あるいは「〇〇言語経験年数〇年以上」というジョブディスクリプションを使うことがよくあります。ですが、このレベルの記述では粒度が荒すぎて、求めるレベルとのスキルアンマッチが容易に発生してしまいます。

この問題は、客観的に評価できるスキル標準を利用することで解決できます。コンピュータソフトウェアエンジニアのスキルレベルを示す指標としては、ISO/IEC 24773やSFIAのIFIP、国内ではIPAITスキル標準モデルや情報処理学会のCITP制度などがあります。しかしこれらの指標は、スキルレベルを示すと同時に、目指すべきスキルのモデルケースを示すものでもあります。したがって、これらの指標はエンジニアの平均的なレベルよりも高い水準に設定されています。そのため、トラブル発生時に急いで人員を調達したい場合においては粒度が荒すぎる・レベルが高すぎる・具体性に欠けるといった問題があります。

たとえば、IPA ITスキル標準モデルカリキュラム(レベル2) は、経験の浅いプログラマ向けにレベルが低めの指標になっていますが、いかんせん教育用の指標のため、調達に使うには粒度が細かすぎ、また具体例が少ないという問題があります。 ほかの例としては SFIA 6 プログラミング/ソフトウェア開発 がありますが、これは粒度が荒すぎますし、突貫で人を集めるにはレベル2でもまだレベルが高すぎます。

トラブルプロジェクトでは、何も考えずに「Java経験年数〇年以上の人が欲しい」と言った結果、NullPointerExceptionひとつ直すにも苦労するような人が集まってしまう……という状況がよく発生します。トラブル発生時に、手早くかつ期待するスキルを可能な限り満たす人員を確保するには、プロジェクトマネージャーが協力会社に一言で伝えられる程度の粒度で、まったくの素人から平均的なプログラマまでのレベルを対象とし、あるレベルを満たしている・満たしていないが行動の結果から客観的に判断できる、そんなスキル標準が必要です。

そこで本記事では、アプリケーションプログラムの受諾開発を行うプログラマを例として、まったくの素人から平均的なプログラマまでを対象としたスキルレベルの指標を提案します。このような指標を用いることで、プログラムの開発が遅延したとき、プロジェクトマネージャーから「どういう人が欲しいの」と言われたアーキテクト・テックリード・アプリケーションスペシャリストなどの人たちが、「最低限どのレベルの人が欲しいか」を一言で伝えることができます。また「実行時エラーの修正を順序だてて実施できる担当者が必要だったのに、コンパイルエラーを直せない担当者が来た」のようなスキルアンマッチの防止を狙えるのではと考えます。

以下に示す指標は、いわゆるエンタープライズアプリケーションのビジネスロジックの開発をイメージしていますが、アプリケーションドメイン特有の内容は可能な限り排除したつもりです。また、いずれも筆者が目にしたり、またはWeb上で報告されていたりする事例をベースに、各レベルのプログラマが犯しがちな誤り・望ましくない行動パターンの例を示しています。誤りの例を示すことで「実行時エラーの修正を順序だてて実施できると申告していた人が、実際には手探りの修正しかできなかった」というように、具体的な事例をもってスキルアンマッチをプロジェクトマネージャーに伝えることができます。

  • レベル0:コンパイルされないファイルは編集できるが、コンパイルされるファイルは編集を拒否する。定数しか書かれていないソースファイルすら編集できない *1
  • レベル1:プログラムを書こうとするが、「コードは決まった文法で書かないと受理すらされない」ということを理解できず、プログラム言語の文法に沿わないコードを書き続ける。具体的な事例としては「世の中にはプログラミングを理解できない人間が存在する」を参照。
  • レベル2:文法に沿ってコードを書こうとはするが、自分の知っている他の文法と食い違いがあるために、そのプログラムの文法を受け入れられない。「イコール記号は代入を意味する」ということが理解できないケースなど。
  • レベル3:ターゲットとしている言語の文法を受け入れることができ、その文法に沿ってコードを書こうとはするが、ループが理解できない。if文は理解できるため、リストの代わりに「userName1」「userName2」……「userName20」のように大量の変数を並べて処理を書いたりする。ショートカットキーを使ってコピー&ペーストを行う習慣があればいいが、マウスでのコピー&ペーストしかできなかったり、「手作業が好き」な人の場合は、大量の変数の中にときどきtypoが混入する。具体的な事例としては 「偶数/奇数の判定」 を参照。
  • レベル4:ターゲットとしている言語の文法に従ってコードを書くことができ、ループの概念も理解しているが、コンパイルを通せない。エラーメッセージにはコンパイラがエラーを検知した箇所が含まれているということを理解できない *2コンパイルエラーが発生したら、「プログラムを読み返して、怪しいと思った(多くの場合は見当違いな)場所を修正しては再コンパイル」をエラーが出なくなるまで繰り返す。
  • レベル5:ターゲットとしている言語のコードを書くことができ、コンパイルを通すことができる。コンパイルエラーは解決できるが、実行時エラーを解決できない。コンパイルが通ったからプログラムは完成だと報告を上げてくる。
  • レベル6:実行時エラーが発生しても、めげずに立ち向かえる。エラーの原因を体系的に調査することはできないため、「プログラムを読み返して、怪しいと思った場所を修正しては再実行」をエラーが出なくなるまで繰り返す。結果として、プログラムの挙動が当初の想定から意図せず変わっていたりする。
  • レベル7:実行時エラーログの存在は知っており、業務プログラムが出力した日本語のエラーメッセージは読める。一方で、スタックトレースや、英語のエラーメッセージは読めない。そのため、フレームワークやライブラリの内部でエラーが発生すると立ち往生してしまう。
  • レベル7.5:実行時エラーが発生した際に、スタックトレースをもとにエラーの原因箇所を調査できる。ただし、エラーメッセージ通りの修正しか行えない。たとえば、NullPointerExceptionが発生していたら、発生箇所の直前にnullチェックを入れるくらいしかできず、根本的な原因までさかのぼった修正(メソッドのの戻り値値がnullにならないよう引数を確認する、など)は行えない。
  • レベル8:実行時エラーが発生した際に、スタックトレースをもとにエラーの原因箇所を調査できる。スタックトレースや英語のエラーメッセージを読んで意味が理解できる。一方で、スタックトレースが出力されなかったり、スタックトレースが直接原因箇所を示さなかったりする実行時エラー(JSPスクリプトレットのエラーなど)は解決できない。
  • レベル9:実行時エラーが発生した際に、体系的に原因を調査できる。スタックトレースがなくても、printfデバッグやデバッガの機能を頼りにエラーの発生箇所を特定できる。多くの場合はエラーの原因を調査し、正しいかどうかは別としても簡単な修正が行える。
  • レベル10:ターゲットとしている言語のプログラムを読み書きでき、デバッグも行える。ただし、コードを書く際には擬似コードなどで詳細に書かれた内容をもとにする必要があり、与えられた仕様を元に一からコードを書くことはできない。いわゆる「業務コード『は』書ける」というスキルレベルの下限がこのあたり。
  • レベル11:ターゲットとしている言語のプログラムを読み書きできる。与えられた仕様を元に一から自分でコードを書こうとするが、基本的にはググって見つかったサンプルコードをコピペして、変数名などを調整することで仕様を満たそうとする。作成したコードの中に、与えられた仕様と関係ない処理が混ざっていても、何のためにその処理があるのか理解しておらず、削除するのも怖いので、そのまま放っておく。たとえば古いIEはターゲットに入っていないにもかかわらず、IE6のバグを回避するためのコードが入ったままになっていたりする。
  • レベル12:ターゲットとしている言語のプログラムを読み書きできる。処理の流れが単純なプログラム(「上から読めば分かるプログラム」と言われる)なら、処理内容を把握できるし、自分で一から処理内容を考えることもできる。一方で、メソッド呼び出しのネストが深いプログラム(「ロジックがあっちこっちに飛ぶプログラム」と言われる)では、処理内容の把握は難しい。ソースコード上の記述の順序とプログラム実行時の動きの順序を区別できない。
  • レベル13:ターゲットとしている言語のプログラムを読み書きできる。処理の流れが多少複雑であっても、処理の起点がひとつだけであれば、プログラムの処理内容を把握できるし、自分で一から処理内容を考えることもできる。一方で、コールバック処理・イベント処理・非同期呼び出しなどがある場合は、やはり「ロジックがあっちこっちに飛ぶ」ため把握は難しい。
  • レベル14:ターゲットとしている言語のプログラムを読み書きできる。与えられた仕様を元に、コールバック処理・イベント処理・非同期呼び出しなどを使ってコードを書くことができる(利用法が適切とは限らない)。ただし、雛形となるコードが用意された状態で「このファイルのここにコードを書いてください」と言われないと、コードを書き始められない。雛形コードなしでプログラムを書き始めるよう命じられると固まってしまう。いわゆる「業務コード『は』書ける」というスキルレベルの上限がこのあたり。
  • レベル15:ターゲットとしている言語のプログラムを読み書きできる。与えられた仕様を満たすコードを自分で考えて書くことができるが、行数・性能の両面とも効率的なコードを書くことは難しい。テーブルルックアップで済む処理をif文の繰り返しやswitch文で実装したり、ハッシュテーブルを使うべき処理でリストを使ったりする。
  • レベル16:ターゲットとしている言語のプログラムを読み書きできる。与えられた仕様を元に、コールバック処理・イベント処理・非同期呼び出しや、扱うデータに合った適切なデータ構造を、必要に応じて利用してコードを書くことができる。雛形コードがない場合でも、どのような単位でモジュールを構成すべきかをアプリケーションアーキテクチャをもとに検討して、与えられた仕様を満たすプログラムをスクラッチから開発できる。

レベル感が前後するところや、粒度がチグハグなところもありますが、プログラミングだけに焦点を当てた場合はこんなものではないでしょうか。上記の最高レベルでも、「SFIA 6 プログラミング/ソフトウェア開発」でいえばまだレベル3(5段階の真ん中あたり)程度と思われます。「自分はこんなレベル感の事例を見た」という事例があれば、コメントで教えていただけると面白くなるのではと思います。 また、もちろんこれ以外にも、マルチスレッド動作やレースコンディションを理解しているかとか、フレームワークホットスポットを考慮してコードが書けるかとかの追加の指標が考えられます。そういった指標があれば、併用することもできるでしょう。

なお注意すべき点として、プログラマからよく申告されるフレーズに「ターゲットとしている言語は不得手だが、別の言語のコードなら読み書きできる」といったものがあります。このようなスキルを申告する担当者は非常に多いのですが、その実際のレベルは上から下までバラバラなので、得意な言語でのスキルを上記の基準に基づいて申告してもらった方がまだ精度が高いのではと思います。

2019/01/16 追記:関連する話を書きました。 satob.hatenablog.com

2019/01/20 追記:関連する話をさらに書きました。 satob.hatenablog.com

2019/06/29 追記:「偶数/奇数の判定」の話が流れてきたので追記。またレベル7.5程度と思しき事例を観測したので追記。

*1:意味がわからないと思うかもしれないが、実際にいる。人力デプロイを行なっている現場のデプロイ担当者にときどき見られる。「受け取ったファイルをコンパイルして、決まった時間内にサーバへデプロイする」ことこそがその人たちの責務なので、自分の起こしたコンパイルエラーが原因でデプロイ作業が滞るのは職務からして許容できない、のではないかと想像する。その他にこのレベルに留まっている理由としては、コンパイルエラーを極度に恐れている、IDEの操作が理解できない、チューリング完全な言語が理解できないなど、いろんなパターンが見うけられる。

*2:直すべき箇所と違うところが出てくる場合があるからコンパイラのエラーメッセージは信用できないし、直す箇所は教えてくれるのに直し方は教えてくれないからコンパイラは意地悪だ、と捉えていたりする。