読者です 読者をやめる 読者になる 読者になる

UXエンジニアになりたい人のブログ

転職活動はじめてすぐやめた

SIerの下請け開発者ってレベル低すぎない?

主張/考え

ネット上ではSIer批判=技術のことをわかっておらずプログラムも書けずPMも出来ない非効率でダメダメな上流工程と、 人月単位での労働力提供という業界の慣習に縛られ、持ち前の優秀な技術力・知識を生かせず非効率な作業を強いられているかわいそうな下請け開発者、という構図が確立されているように思います。

自分が関わるまでは、まあそうなんだろうなと思っていましたが、しかし実際にそういう立場のひとと関わりをもつにつれて、どうもそうではないのではないかと思うようになりました。このあたりの実情を書いていこうと思います。


なお、先に言っておきますが本記事で書くことは、上流工程がどうのとか、業界の多重請け負い構造がどうのとか、給料が安くてとか労働条件が過酷でとか、そういう話とは全く関係がなく、純粋にプログラミングのスキルの話だけです。

対象はおもに詳細設計、実装UTだと思ってもらえれば。外部仕様が決まった状態で、それを満たすそれぞれのモジュールを、必要であれば詳細化した上で実装して単体テストする、っていう。


自分の作ったものの仕様を説明できない

言ってみれば問題は全てはこれに尽きるのですが。


自分の作ったもの、たとえばメソッドなりクラスなりなんなりを作ったとして、その仕様を説明できないという人がかなりいます。

代わりに、延々と自分がコーディングした記述の説明をしてきます。

どんなプログラムであれ、特定の入力状態においてなんらかの処理を実行させて出力状態を得る、という構造は変わらないはずです。それは純粋関数なら引数と戻り値だし、オブジェクトならメッセージとオブジェクト状態だし、WebURL呼び出しならURL+パラメータとHTML(テキスト)だし、といった具合に、ジャンルによって表現はかわりますがその本質は変わりません。


こういう風な出力を得ることを目的としてプログラムを書きました、こういう条件で入力のパターンをテストして全部出力が想定通りであることを確認しました、だからこのプログラムは(ある範囲で)正しいです。

これを説明するのが当たり前の基本だし、やるべき唯一のことであるのだけれども、そもそもプログラムが完成したのに「何をどうしてどうするプログラムなのか」が説明できないケースが多々あるのです。

意味がわからないとおもったあなたは常識的であると思います。わたしも、それがわからなくてどうやってプログラムを書いてテストするのか、わけがわかりません。


しかし、現実には以下のような会話が頻発します。

「この引数にマイナスの値を設定すると、NullPointerになりますね」

「そうですね」

「?そうですねってどういうこと?この動きは正しいの?」

「XXライブラリがnullを返してくるからですね」

「??XXライブラリが返したnullにアクセスしてるのはあなたが書いたコードですよね?どういうこと?このメソッドは負の値で呼ばない、というのが制約なの?」

(なにを聞かれているのかわからないという顔)


これ「テスト終わった」後のモジュールの話ですよ?

いったい何をテストしたんでしょうか。こんな話がしょっちゅうです。「そもそもこれは何をする関数なの?」とか「え?自分で書いたコードですよね?」とかそういうセリフを何度も言わなければなりません。

どういうことなのでしょうか。


フレームワークやライブラリとの主従関係が逆転している

仕様がわからないものをどうやってテストするのか。強い味方はカバレッジ確認ツールです。

彼らからするとテストとは、

× プログラムが仕様/想定通りにうごいてることを確認する作業

○ カバレッジが通るようにテストコードをこねくり回す作業

であるようです。カバレッジが100%に近くなると、テストコードに結果的に「仕様らしきもの」が浮かび上がってくる、と。うん、逆ですしそれ漏れますよね。

テスト終わりました!カバレッジ100%です、と言われて見てみたら、たしかにカバレッジは100%だけど返り値の確認を一切していないというコードを見た時が一番度肝を抜かれました。


これに限らず、プログラミングとはものを作る作業じゃなくて、なにか巨大なすばらしいものの「設定」をする作業みたいに捉えてる人が多いようです。 “カバレッジツールというすごいもの"がエラーを出さない設定値を探る、とか"Railsというすごいなにか"に設定用のコードを書くとよきに計らって動いてくれる、とかとか。

だからRailsやったことある=RailsのControllerを書いたことがある、であると信じて疑わない。もちろん、一からURL設計をしてください、といったことは全くできません。 それどころか、動かないのは自分の責任じゃないのに、といったことをいう人までいてびっくりです。


フレームワークやライブラリのやっていることを理解しない

そんなわけでフレームワークやらライブラリの名前は詳しいのに、本質的なことは全く理解してません。

あるURLに任意の数のパラメータが来る、と聞いて、うわあFormオブジェクト(リクエストパラメータをオブジェクトにマップしてくれる便利な仕組み)が作れないどうしようどうしようなどと意味不明な混乱をした挙句、自分が考えつく全てのキーワードをプロパティとしてFormをつくる、などというバカみたいなコードを埋め込むことになるのです。(そしてもちろんそれ以外のパラメータも来る可能性があるので、そのFormは実用に耐えない)


こういうひとたちは典型として「例外」を全く理解できません。なんのためにあるのかわからず、自分のコーディング作業を邪魔するもの程度の認識しかありません。

try {
...
}catch(Exception e) {
  return false;
}

こういうコードを書いてせっかくのエラー情報を握りつぶしたりするのです。catch節を書いたのは静的解析ツールに怒られるからで、それがなかったら読み捨てるんでしょう。 それで、ずっと後になって「エラーが出たはずなのにどこにも記録されない」なんて事態が起こります。

一応念のため言っておきますが、プロジェクトに例外は最上層で処理するというルールがある状態での話です。


自分たちが役割や機能を意識したプログラムを書かないから、他人のプログラムが役割や機能を提供してるということが把握できないのでしょう。

何百行もある謎のユーティリティが全部ライブラリ機能1行呼び出しで置き換わる、なんてこともありました*1

結局、開発効率化のためのライブラリやフレームワークがあるにもかかわらず、なぜか無意味なコードが大量に生み出されたりするのですが、どうすれば良いのでしょうか。


FizzBuzzレベルのプログラムがかけない

こんなひと本当にいるんだなあと。正確に言うなら、一応動くけど何を書いてあるかさっぱりわからないコードを作り出す、なんですけどね。


文字列Aと文字列Bがあたえられた時、文字列Aが3文字以内なら文字列Bの先頭に付加し、プロパティXに設定する。

英語にすればそのままプログラムになりそうな要件ですが、これがifと3項演算子がぐちゃぐちゃに入り混じったコードになりました。本人曰く、普通に+で結合するとnullの時"null"って文字列になっちゃうからとかいう話を延々としてました。なにが難しいのか全く意味がわかりませんでしたが。


それとか、これ。コードから先にみてください。

String[] bigArray =....

for (int i = 0; i < (int) ((bigArray.length + 99) /100); i++) {
  ....
}

なんのコードかわかりますか?

配列を100個ずつに分割するコードなんですよ。えええええ。なんだこれ。99っていったいどこから出てきた?しかもこのコード、コメントなしなんですよ?このコードがコメントなしで伝わるコードなわけないだろと。

これは心の底から疑問なんですが、彼らは外部仕様書もないような謎モジュールの改修作業や保守作業とかを引き継いで、他人の意味不明なコードを読んでわけがわからなくて悩んで怒る、って経験、たくさんしてるんですよね。われわれなんかよりそういう経験豊富なんですよね?なのに自分のコードにはどうしてコメント書かないの?

ちなみに、このコードは↓をコピペしろといって、なおしてもらいました。最初からこう書いて欲しいというか、これしか書きようないだろ・・・

String[] bigArray =....

for (int i = 0; i < bigArray.length; i+=100) {
  ....
}

スパゲッティコードって、長い紆余曲折を経て作り出されるものだと思っていたのですが、頭がスパゲティな人がいきなりスバゲティを茹でることがあるんですねえ。


平気で嘘をつく

特に技術的な調査事項など。自分が調べた限りはわかりませんでした、と言えばいいものを「ライブラリの仕様上でできません」というような嘘をすぐつく。〇〇のライブラリなのにXXができないなんてありえないだろ、と思って調べると案の定できるとかね。

その間「〇〇さんが調査した結果できないことが判明した」という情報に振り回されていろんな人の時間が浪費されるなんてことはしょっちゅう。


実装完了しました、とか、テストカバレッジX%でした、みたいな試せばすぐわかるような嘘もすぐつく。

特にテストについては本当によくごかます。よく、SIerのExcelスクリーンショットによるテストエビデンスの非効率さが槍玉に上がるが、それはあなたたちがいい加減なごまかしをしてきた歴史の結果じゃないの?と問い詰めたいところではある。

というか、すぐ嘘をつくとか、もう開発者どうこうというより、人としてダメなんじゃないのか。


奇妙なプログラミングスタイルに固執する

たとえば、関数を書くとなると、なにをするにしても、

int process() {
  String str;
  int i, j;
  
  ・・・

  return 0;
}

という書式で書きたがる。まるでそういう決まりがあるかのように。

ここで、変数str、i、jは処理の最中にどんどん意味合いが変わる。intでは表現できない情報を返す必要がある場合は戻り値はStringになる。複数の情報を返す場合は、Stringの中にカンマ区切りで情報を記載すし、呼び出し側でカンマ分割して復元する、なんてことを平気でやる。構造体ってなんのためにあるか知ってますか。


for (int i =0; i < length; i++) {
}

繰り返しもこう書かなくてはいけないという明確な意思があるようだ。

ちなみに、iやjを用いると添え字の取違いが発生する可能性があるし、コード量可読性ともに悪化するので、each的機能がある言語はそれを使うよう明確にルール付けされている。もちろん読まないし恐らく意味がわかっていない。


結局のところ、なんの合理性もないわけのわからないプログラミングスタイルによって可読性は悪化し、ますます保守性が下がることになる。いったい何がしたいのだろうか。

ちなみに、急にモダンなスタイルのコードが出現した場合、それはどっかからのコピペである。コピペコードと自己コードのスタイルを合わせようという努力がなされることはない。


コメントがかけない・ネーミングセンスがない

仕様が説明できない人間がメソッドコメントをかけるかというそりゃ無理なんだけども、それにしたってあまりにもひどいネーミングをしすぎる。


/**
  * 要素に対して加工処理を実行します
  * @param element 処理対象
  * @return 処理結果(int)
  */
function elementProcess(elm) {
}

こんなの、しょっちゅうある。なんにも伝える気がないだろと。加工処理って具体的には何をどう加工するんだ、処理結果ってどういう数字なんだ、加工数か成功失敗のビットかどっちやねん、とか、ともかく「お前以外絶対理解できないだろ」って内容の名前やコメントをつける。なんど指摘してもくりかえす。

ちなみにメソッド名は動詞にするというコーディング規約があるが、それにも違反している。そんなもの一切見ないし、そもそも動詞とはなんなのかわかってないのではないか。


List executeQuery(String sql, Object[] params, int limit10);

void writeToFile(String filePath, String  text,String encodingShiftJis);

それぞれ最大取得数を指定してSQLクエリを実行する、指定エンコードでテキストをファイル出力する、っていうありがちなメソッドだが、なぜかパラメータ名に10とかShiftJisとかの値が入ってる。この、パラメータ名とそこに入れる値が区別ついてないっていうパターンは驚くことにかなり頻発する。なんでそんなところを間違えるか理解不能だ。

一番ファンキーなやつだと、メソッドの中でencodingShiftJis変数が"shiftJis"かどうか確認して、違ったらエラーにするとかいう実装もみたことがある。頭がおかしいんだろうな。


Element searchElement(String name,  boolean isEnabledFalse);

究極最終形はこうなる。DOMエレメントを探す関数で、有効状態のものだけを取得するようフィルタできるようだ。

さて「有効状態のものだけを取得」したい場合、isEnabledFalseにはなにを指定すれば良いのだろうか。だれにもわからない。多分本人ですらわからないんじゃないか。繰り返して言うけど、頭がおかしいんだとおもいます。


/**
  * データアクセッサを利用して、指定された条件でXXXテーブルを検索するSQLを組み立てた後
  * 検索を実行し、取得レコードをステータスごとに分類してマップに格納します
  *
  * @param nameFilter 名前フィルタ
  * @param statuses 対象ステータス
  */
Map<String, List<Xxx>> searchXxx(String nameFilter, StatusFilter... statuses);

これは一応ギリギリ許せる範囲。コメントを見れば何をやればやってるかはわかるからね。でも、ここに書くべきは「結局呼び出し側が何を得られるか」なんだよ。自分のコーディング処理内容を書く奴が多すぎる。見た人はそれを逆算して自分で考えてねって。

Javaでも.NETでもなんでもいいけどさ、中の処理の順番が事細かに書いてあって、結局なにが得られるかはそこから類推してください、なんてドキュメント見たことあるか?っていうね。

最高に「デキる」人間でもこの程度なんです。そして皆がこれを真似てコピペする、と・・・


コードのネーミングやコメントは保守において重要であるにもかかわらず、全くケアする意思がないのは驚きである。ネーミングやコメントはコードじゃないと思ってるのかな。


SQLしかできないマン

能力の全てをSQLを書くことだけに費やしていて、申し訳程度に各言語のコレクションフレームワークとか繰り返し構文とかを把握している、という人材が一定数いる。 これはどうなんだろ。業界の伝統なのかな?とはいえ、そんなニッチな能力でアプリケーション開発者とか言われても困る。

SQLに詳しいと言っても実行計画を見て効率化するといったことはしないし、DBアクセス層の設計を依頼してもまともにつくることはできない。単に複雑な処理を巨大な1SQLで書くことに喜びを見出しているだけ。

このタイプはかなり自己評価が高い場合が多いけど、プログラミングスキルとしてはFizzBuzzレベルのことも多く、だれにも読めないSQLを(これまたコメントなしで)作ってそのままいなくなったりするので禍根を残すようなこともあってぶっちゃけていえば使えない。


まとめ

どうでしたでしょうか。断っておくけれども、これ、最底辺の人間を面白おかしく紹介してるわけじゃなくて、極々平均的な「SIerの下請け」のレベルだから(最底辺レベルはマジで度肝を抜かれる)。何個かの案件で何社かと関わったが、どれもこんな感じ。

興味深いのは同じ会社に頼んでも内製ソフトウェアの業務委託ですって場合と、SIer案件ですって場合とでは、派遣される技術者のレベルに何段も差があること(後者の方が圧倒的に低い)

それはそれとして、個人的には上にあげたようなこと、一個でも引っかかるようなやつは一発でクビにしてよいと思っているが、そんなことしてたらうちからはもう紹介できる人がいませんとか言われるくらいこういうのが「普通」なのです。


結論

総じて言えば、ただコードを書いて動かすのが楽しいという学生みたいなレベルで、仕事として金をもらう状態にないと思う。

しかも30代とか40代とか何10年もキャリアがあるような人でこれ。むしろ若手の方がまだまとも。ずっとコード書く仕事ばかりしてたんですよね?今まで何してたんですか?と問いただしたい。

雇った側としてはどうしてこんな奴らに金を払ってゴミみたいなコードを書いてもらわなければならないのかという気持ちがつよい。


そもそも、こちらとしては難しいことを言っているつもりが全くない。バグをゼロにしろとか、伝えてもいない仕様を実装しろとか、エスパーのように要件を把握して実装に適用させろとか言ってるわけではない。普通にプログラミングして、その妥当性を説明し、重要な情報を未来の他人にわかる状態で記録に残せと言っているだけだ。おかしいですか?


英語の文章書いて欲しいと依頼したら、単語は正しいけど文章として成り立っていない原稿が完成してるようなものだと思ってる。スペルチェッカーはオールクリアだけど、文の意味も分からなければ何を伝えたかったかも説明できませんって。

文章として成り立ってるけどそれは欲しい種類の原稿と違う、ってんなら書き手に第一義的責任はなくて、それをちゃんと伝えなかった要求主の問題だ。何10ページのもの文書を書くのに雀の涙ほどの金額しかもらえないのであれば、それは雇用条件の問題で、ひいては業界の問題なのかもしれない。

でも、文章を書く仕事で意味の通る文章が書けないのは明らかに書き手の問題だ。要求ガーとか業界ガーとか以前の問題だ。


もちろんこんな人たちは開発者とは呼べないし、IT土方とすら呼べないのではないだろうか。だって自分の仕事の内容を自分で説明できないんだよ?そんな仕事人いる?!


*1:jQueryオブジェクトの配下を条件付きで呼び出すユーティリティ。全部jQueryセレクタで表現できる範囲だった。そもそもDOMから目的のエレメントを探し出すがjQueryの主機能なのだから、こんなユーティリティを作ろうと考えること自体おかしい