へっぽこSE奮闘記
あるシステムを請け負った。
どういうやり方をすれば、作れるか、概ね予想はついていた。
だから、割と気軽に引き受けた。
ところが、実際に開発を始めてみると、トラブルに次ぐトラブルの連続。
当初、一気に2週間程度で最後の詰め(デプロイ)を片付けられると思っていたものが、延びに延びて2ヶ月超。
とにかく、昨日、なんとか「機能として目的を果たしている」状況には持ち込んで、システムを稼働させた。
ただ、細かいところを見れば、まだ改善の余地が山ほどある、というよりも、とにかく脆弱で「安定稼働」を保証しきれない、私なりの採点で100点満点のシステムから見ると、30〜40点そこそこの状況で動いている感じ、だろうか。
今、今回経験したあらゆるトラブル、そのトラブルを通じて仕入れた経験と知識、誰にどんな迷惑をかけたかという苦痛、などなどが、全く整理できずに頭の中でトグロを巻いていて、じゃなかった、渦を巻いていて、なんというか、統合失調症状態、昔風に言えば、精神分裂病的なメンタル状況。思考のカーソルが定まらない。
誤解を招かないために、というよりも、万が一、書いている私が誰で、それを知った上でお客様がこのページを読まれた際に「なんだ、粗悪品を押し付けたのか」と思われないために、言葉を補うなら、「とにかく、高速道路を走行できる車」という条件で請け負って、仕上がったのが「ベンツ」「ポルシェ」クラスではなくて、「軽自動車」クラスになっちゃった、という感じで、「金額に見合う程度」には仕上がったのだけれど、という感じかもしれない。
(すみません、国産車メーカーの方、ベンツやポルシェは、私の個人的な憧れ、ということで・・・)
金額、ということで言うならば、経験したこのは技術的な部分だけ、じゃない。予め作業量を見積もる上での要素についての、評価も甘かった。
その甘さが、積もり積もって、おそらく「経験した上で」見積もった時の金額の、おそらく1/5〜1/4程度の工期と金額で「請け負った」ということになると思う。デバイス一つ、構成要素一つ新しいものがあるだけで、一項目あたり一週間見なければならない。それも、初期段階に「あ、つながりますね」で安心していると、システム全体の要件の縛りがかかった時に、突然「その条件では使えない」というのが露呈してきて、大変な騒ぎになる。
工期や金額の見積もりが甘かった結果、一番「赤字」を被ったのは言うまでもなく私自身だけれども、「システム規模」の関係で、営業パートナーさんにもかなりの迷惑をかけたことになる。
「金額」面でエンドユーザさんには迷惑をかけていない、ということが、不幸中の幸。というよりも、ビジネスならそれが当然だな。最初に約束した金額がすべてに優先する。ただ、営業パートナーさんには、ご迷惑をおかけした。
ただ、思う。もし、「品質」ということまで含めて工期と金額を見積もっていたなら、商談が成立していたかどうかはわからない。「ベンツ」には手が出せないけれど、「軽自動車」なら手が出せる、という人は、相当に多いと思うから。いずれにせよ、ビジネスとしてシステムを開発している私、営業を行っている私の営業パートナーさんについては、この金額見積り部分の甘さも、致命的な失敗だと思える。
それでは一体どんなシステムなのか。一言でいうと、IoT(Internet of Things)の制御用Webシステム、ということになろうか。
より具体的には、RS232cという昔のシリアル伝送機器も含めて、直接、あるいは、TCP/IPに接続できる機器を、Wi-Fiに接続したタブレット端末から、Webサーバにアクセスしてワンタッチで操作し、QRコードスキャンなどでワンタッチで制御情報を流し込み、それらの機器の動作状況をほぼリアルタイムにモニタリングできるシステム、ということになる。
これを私は、金融系のSEさんの一人月単価よりも安い金額で、丸ごと一式請け負った。組み込み系のプログラマの人月単価で言えば、2人月程度、だろうか。今改めて思う。安すぎた。そんなに簡単に仕上がるシステムじゃなかった。
要するに私は、30年前の技術で、スタンドアロン型のアプリケーションを作る感覚で見積もってしまった、ということになると思う。工期や金額を出す上で参照していた「過去の経験」が古すぎて、それに自分で気づかなかった、ということになるんだろう。
「軽自動車」を引き合いに出したが、今回の開発費総額では、軽自動車ですら新車購入はできない。2年落ちなら、なんとかなるかな、という見積り金額を出していた。こんな水準の見積りをするSEが、他にいるんだろうかと、かなりの疑問はある。他人の懐事情に、興味はないけれど。ただ、全体の請負金額が安すぎると、いざという時に外に応援を頼めなくなる。
とにかく、昨日稼働させての今日、何をすべきか。「要素技術」についてのアプローチで自分はどうすべきだったのか、「何」の確認を見落としていたのか、技術の「採用」を決める前に、何をすべきだったのか、徹底的に洗い出すこと。そして、可能な限り普遍的な対応策を自分の中で確立すること、だと思った。
考えがまとまらない。だから、言葉にして書き出している。
さて、どんなトラブルを経験したか。ここから先は、しばらく、専門用語の嵐、になる。
RS232cのシリアル接続機器をLANに接続するために、メディアコンバータを採用した。ところが、このメディアコンバータ経由でDTR信号やRTS/CTS信号を適切に検出する部分でつまずいた。ここで数日浪費。信号状態が見えないために、接続先の電源が落ちていても、一切のエラーを吐かずに「送信完了」してしまうか、逆に、準備ができていても伝送が開始できない。このため、有人環境でしか使えない感じになった。ただ、これは今回のケースでは元々が有人環境での操作なので、ある意味でハンドシェークができた時点でOKとした。
WEBシステムのサーバにはLINUXを使う場合が多いが、このメディアコンバータを使うために、ドライバが提供されているWindows Server機を採用した。私自身がWindows Serverには不慣れだったこともあるが、サーバを思い通りに動かせず、一週間以上を浪費。コンテナの設定でエラーを吐いたまま。最終的にdocker desktopを走らせて、かろうじて逃げている。
LINUXの場合、トラブルが起きてもいざとなったらカーネルのソースコードを直接叩いて、本質的な原因の究明がやりやすい。その結果だと思うが、インターネット検索すると、かなりの情報が取れる。ところが、Windows Serverはそうしたアプローチが取れないため、とにかく闇雲に、執拗に、試行錯誤を続けるしかない。公式文書の「エラーコード」の説明が漠然としすぎていて、どこに本質的な問題があるのかの解明は、公式文書に辿り着いた時点で行き止まりになる。
RS232cのシリアル伝送は、伝送速度としてはLANの100万分の一以下。その「とてつもなく遅い」機器の伝送速度に、Webシステムが影響されないために、しかもWebシステムならではの「マルチクライアント」で動作させるために、プロセスフォークを用いて、スレッドを分割した。その「遅い」側からの情報をWEB システムで見るために、channelsという機能を使ったのだけれど、channelsはプロセスフォークされた子プロセスのプログラム部分とは交信できないことが判明。この問題は、小技を積み重ねて解決はしたし、あくまでプログラミングロジックの問題だけだったけれども、試行錯誤にそこそこ時間はかかった。
制御情報は、今回のシステムではQRコードで吐き出したけれども、昔ながらのバーコードで出力された「レガシー・データ」が10万件を超えていて、それらが使えないとならないことになった。それらを活用するためには、バーコードが読めなければならない。ところが、今回採用したpythonのモジュールでは、3/4以上の昔のバーコードが読めない。javascriptのQuaggaを使ったけれども、やはり読めない。実験的に読んだバーコードは10cm程度の幅で印刷し、「とにかく読める」ことは確認したが、現場で使われていたのは幅3cm。読めるデータはどのモジュールを使っても読めた。読めなかったデータは、pythonで処理してもjavascriptで処理しても、どちらでも読めなかった。同じロジックを使っているんだろうか。
普通にカメラにアクセスすると、タブレットが「バーコードリーダ」的な使われ方を想定していなかったためか、処理できるような「画像zoom in」ができなくて、バーコード部分の画素数が絶対的に不足してしまう。直接カメラデバイスをZoomしたり、リアルタイムにフォーカスやzoom in/outを制御してバーコードを抽出しないとならない。プログラミング時に試したMacの内蔵カメラでは、全部OKだったので、実際にタブレットを用いるまで、この問題に気付かなかった。カメラ制御のモジュールは、探したけれど見つからなかった。とてもゼロから書いている時間的な余裕がない。
これに先立って、タブレットで画像を読み込むために用いた技術が、本番環境に近づけた途端に、カメラを作動できなくなった。わかったことは、SSL環境でないとカメラが起動できないこと。例外としてlocalhost(127.0.0.1)からのアクセスならOK、らしく、SSLでなければ使えない、ということが最初に確認した時にはわからなかった。そもそもがイントラネットなので外部に繋がないからSSLは要らない予定だったが、SSLを使わざるを得なくなった。
SSLを使うようにした途端に、今度は、channelsに使っていたdaphneとredisがうまく繋がらなくなった。そこそこ時間を取って調べたけれど、この問題は未解決。私の勉強不足だろう。
もう一つの問題は、SSLの鍵に、Let's Encryptを使うつもりだったけれど、イントラネットに配置すると「鍵の更新」ができない。サーバ証明書の期限は90日だけれど、外に繋がらないから自動更新ができない。結果として自己証明の鍵を生成させて使ったら、今度はchromeが「いかがわしい鍵だ」と指摘して、サイトを表示してくれない。Djangoのrunsslserverの鍵でも「警告」が表示される。最終的に、daphneとredisの問題が解決できず、内蔵カメラの使用を諦めて外付けのバーコードリーダで逃げたため、SSLの採用は諦めた。(問題が解決できなかった悔しさ。)
さらに本番環境に近づけて、イントラネット的に動作させたところが、動作が異様に遅くなった。原因はCDN。bootstrap関連のモジュールが常に外部のCDNからcssやjsのソースを読みにいく。イントラネットではパケットが外に出ていかないから、必然的にタイムアウトを繰り返す。これらは、CDNではなくローカルにコピーを置いて、CDNアクセスの記述に書き換えたら反応が良くなったのに、まだ消えない。なぜだ。
最後まで残ったのは bootstrap-datetimepickerの部分。widgetがやはりCDNにアクセスするのだが、コンテンツとしてFont-Awesomeを使っていて、cssをローカルに置き換えただけではフォント自体へのアクセスを止められない。ここまで追い詰めるのに二日以上費やしてしまった。
加えて、タブレット端末の特性。バーコードスキャンの部分は、内蔵カメラの代わりに(営業パートナーさんの負担で)専用のBluetoothバーコードリーダで逃げたのだけれども、タブレット端末というものは普通に持ち歩いていると、画面のどこに指が触れるかわからない。その都度Focusが移動してしまって、入力Boxの外にフォーカスがあるとバーコードリーダに反応しなくなる。ここは、ロジックというか小技で逃げたけれど、玉突き式に、「入力Box」以外のエレメントが正常に表示されなくなってしまった。(連鎖的なバグ)これは、納入の土壇場で「修正」をかけて、その「修正」の結果現象が起きた。
実運用に備えるために、データベースサーバ内の、旧データを吸い上げて、新データに移行する際にも問題が起きた。Shift-JISではない、PC-98シリーズの固有文字がデータの中に含まれていて、それらの「機種依存文字」が、','などの区切り文字や、文字列を閉じる引用符と結合してしまって、データのダンプが完全にコラプトしてしまった。古いデータのせいで新しいデータが読めなくなってしまった。
ここは、SQLの書き方などの小技をいくつも繰り出して、そして最後は「手作業」という力技で、なんとか、数日で復旧したけれど、化けた文字は復旧できないまま。2週間くらいかければ全部手作業で復元できる、と思って聞いたところ、「そんな古いデータは、もう使わない」とのお返事。でしょうね。
他にも、マイナーなトラブルをいくつも経験しながら、とにかく「機能的には仕様を満たしたもの」を作り上げたけれども、自分にとっての「理想的なサーバ」には程遠い。自動起動の設定もできずにいる。停電が起きてシステムが落ちたら、またセットアップしに訪問しなければならない。情けない。
これら一連の問題は、実はプログラミング上の問題点ではなく、ほぼすべてが、実際に使用する機器の整合性だとか、運用環境だとか、デプロイ時の設定などに起因する。プログラミングについては、技術や「コスト発生」を自分なりに適切に見積もったつもりだったけれど、この「システム構築」や「サーバ構築」に関するコストを、適切に見積もって伝えることをしなかった。営業サイドの方も、私がきちんと説明すれば、こうしたハードウェア絡みの「システム構築」に関する仕様調査に「一定のコスト」が発生することを理解してもらえただろうとは思うが、やはり根底には「一円でも安く」ということはあるかもしれない。
「部分的に安く」済ませるために、全体のコストがどれだけ跳ね上がるかを、知識として関係者で共有できるように、私には説明責任があったと思う。
ただ、前述した通りあまりにも「経験不足」だった。やはり、すべてを試した上でなければ金額見積もりは出せないかもしれない。それも、本番のデータが必要になる。プログラマとしては、自分で言うのもアレですが、ベテランの域に到達しているとは思うが、現在の技術を用いたシステムエンジニアとしては素人並み。サーバエンジニアとしてのSEでは、もはや「ど素人」かもしれないと自覚してしまった。(Linuxなら、ソースが読めるのに、という恨みつらみ)
今回の一連の経験は、私自身にとっても「貴重な経験」になったけれど、ある意味で「反面教師」としての私の経験を整理して、どんな「開発作業」をどのように事前評価すべきなのかも、問題点をまとめたなら、おそらくは他の方々にも「有益な内容」になる、という気がした。
また、玉突き事故的に発生した問題については、インターネットで検索しても「解決策」が出てこないものが少なくなくて、それが結果的に、かなり「納期の遅れ」の原因にもなった。だとしたら、ますます、問題を整理して、「最終的な最適解」も含めて記事にしたなら、おそらく、役立ててもらえる方が多いに違いない、と考えた。
今回の経験は、今の所「失敗の経験」でしかない。でも、転んでもタダでは起きたくない。このページは「無料公開のページ」とするけれど、最終的には、このページの表題(と似たような)タイトルの書籍にまで仕上げることまで視野に入れて(そこまで徹底的にアプローチして)、「問題点」を分解し、一つずつ、技術的な視点や解決策に加えて、コスト算出的な観点なども含めて「有料記事」として書き溜めていきたいと思う。
最低でも、同じ状況で同じトラブルに遭遇した方が、すんなりと問題解決のパスを見つけられる程度には、記事、もしくは書籍として仕上げたい。
技術屋さんに有益なように。あるいは、営業サイドの方や、クライアントサイドの方々にも、「そういうコストがかかるのか」ということを雑学としてご理解いただけるように、あるいは、ある程度「専門用語」も理解できるように、一つ一つの専門用語を噛み砕いて(このページでは噛み砕かなかったが)、「読み物」としても読めるように、書いてみたいと思った。
さてと、宣言してしまった。有言実行。まずやるべきことは、放置せざるを得なかった問題の解決、だろうか。
このページは、頭の中が今のところ、全く整理できていない私が、自分の頭の中を整理するために言葉にして書いている記事であると同時に、将来的には「出版」することも含めて、書き続けることについての「決意表明」でもある。今後の記事の「予告編」にしたいと思う。
この記事が気に入ったらサポートをしてみませんか?