あらまし
組み込み機器のプロトタイプ開発にかかわって、炎上も幾度となく経験し、開発時に本当に必要だと感じたことを自戒の意味も込めてまとめようと思う。技術的ではなく、遅々として進まない開発をどうやってうまく乗り切ったかというプロジェクト運営と組織運営とメンタルコントロールを話の主軸をしたい。
製品と組織の概要等
- B2C製品
- シングルコア/100MHz程度のマイコンを利用した組み込み機器
- 開発メンバー:最大時プロパー5名/協力会社・派遣社員15名程度
- 社内の関連する他部署:たくさん
- 開発期間:1~3年程度
- いったん試作部門でプロトタイプを作ってから量産品に向けてはプロセスにのっとった開発を再度実施する
- ただし、プロトタイプ末期には市場と同様の使われ方を想定して、開発を行う
- 会社の規模はいわゆる大企業の分類に入るが、組織体制は非常に未熟
- 開発体制も人員・技術・プロセスのいずれの面でも十分とはいえない
開発したものの扱い
日夜、開発を進めるうえで、様々な評価結果やソフトウェア等が作成される。その中には、評価目的のみに作られたもの、量産品を見越して作られたもの、謎の機能を提供するものが玉石混在である。また、これらは機能面のみならず、ソースコード品質でも大きな差がある。同時に、機能を確認するためのWindowsAppが担当者の独自の判断で作成されたりもする。一言で言って、カオスである。
これらの玉石混在しているソフトウェア群の取り扱いを誤ると、無用なメンテナンスコストや、異常に品質の低い機能が組み込まれることとなる。これらをどう扱うかは非常に難しいが、いろいろやってみて、以下のような線引きが、比較的ましな結果に落ち着くのではないかと思った。
著しくソースコードの可読性が悪いもの
多くの場合、非常に単機能かつ、規模の小さいものであった。ただし、担当者がそこそこは動作確認しているケースが多かった。こういったものは最終的に別のモジュールで置き換えられることが多かった。そこで、リファクタリングやドキュメント作成は実施せず、コメントアウトに各関数の簡単な説明を追記し、稀に動作のワークフローやポンチ絵(死語)を作成し各処理のなかで参照する構造体や実行する関数を明示するようにした。
ただ、変数名や関数名a
,b
,c
,temp_1
,temp_2
等は最低限修正するべきだったと思う。
糞コードだからといって、即修正ではなく、そこそこ以上の品質で動くものは最低限の修正を行い、取り込むことを前提とする。
複数の独立した機能を内包するもの
本来なら複数のモジュールに分けるべき機能が1つのモジュールに内包されている場合、機能間の依存関係がどれだけ密かによるが、最低限はcのファイル単位で分離するように作り直し。
ファイル単位の分離が困難な場合、他モジュールに悪影響を与えない場合はぐっとこらえて修正は先送り。
ひどいケースだと、Appがシリアルコンソールにデバッグ情報を送信する機能で、Appのソースとシリアルドライバが完全に1つのcソースの中に実装されていたというケースがあった。このケースでは結合時に他の開発者がシリアルコンソールを使えなくなるので現状維持は困難。最終的には大幅な変更はせず、全箇所にコンパイルスイッチを挿入し、機能を無効化できるようにしたと記憶している。
こちらも、糞コードだからといって、即修正ではなく、そこそこ以上の品質で動くものは最低限の修正を行い、取り込むことを前提とする。
大量のリソースを消費するもの
大量にリソースを消費するものとは、おおよそ以下の特徴を持つことが多かったように思う。
- 各関数の実行時間が長い
- RAMを大量消費
- ROMを大量消費
- 割り込み禁止時間が長すぎる
各関数の実行時間が長い場合は、そのモジュールの実装そのものが悪く、while(!flag)
等の外部のステータスが変わるまで無限に待っているケースや、Callしている外部のAPIでの実行時間が長いケースや、扱うデータ量が多くmemcpy()
やmemcmp()
等の実行時間が伸びているケースが大半であった。
項目 | 場当たり的な対策 |
---|---|
while(!flag) で無限に待つ |
一部、Statusが短時間で切り替わることを前提にしても設計したが、短時間で切り替わることが保証されていないケースがあるが、その場合は設計からのやり直しが理想出来であるが、while(count){ if(flag) { (処理) } count-- } の様に一定時間待つことは許容するが、上限を設ける処理に変更し、その関数が定期的に呼ばれる実装に変更した。諸般の事情によりむつかしい場合は、while(!flag) を持つ関数が他のタスクの動作を阻害しないように低優先度タスクに割り当て。 |
CallしているAPIの実行時間が長い | 多くの場合はAPIがブロッキングモードで動作していることが原因である。ノンブロッキングモードのAPIが提供されていないか確認。ノンブロッキングモードをサポートしていなければ、個別に対応を検討。 |
memcpy() やmemcmp() の実行時間が長い |
理想的にはZero Copy Bufferに実装を変更すべきケースが多かったように思われるが、様々な原因でそれができない場合がある。こういったケースでは、過剰にデータをバッファリングしてしまっているケースが多いため、データのバッファリングを抑制する。また、標準関数のmemcpy() は使わず、マイコンのメモリ境界を意識したコピー関数を独自に実装する。 |
ROM/RAMを大量消費しているケースは、これらの枯渇が現実的になってくる時期まで先延ばし。long int
型をint
型に変更するだけでRAMが数Byte削減できるという爪の垢に火を灯すような修正は基本的に行わない。
割り込み禁止時間が長すぎるケースは、他の動作を著しく阻害するため、基本的には修正する。結合時に動作不良を起こす原因の一つに、割り込み禁止・許可の処理が誤っているということが多かったように思う。ただし、Startup等で他のモジュールが動作していないことが保証されているなら修正は行わない。
基本的に、時間リソースを大量消費し、他の機能の動作の妨げになるケースを除き、積極的な修正は行わない。
非常に動作が不安定
多くの場合、結合時に他のモジュールの動きを阻害するため、この部分にリソースを注ぎ込む。綺麗なコードを書くことより、機能を動作させることを重視する。
ドキュメントがありません
過度なドキュメント作成は、プロジェクト後半にメンテナンスコストとして跳ね返ってくるので、ドキュメント作成は最低限にとどめるか、その段階になって、ドキュメントを破棄する。
日程が間に合いません
マイルストーン上には日程が定義されているが、本当に守るべき日程はごく一部であったように思う。
内製ソフトにするか、ベンダー製ソフトにするか
実績のある内製のソフトウェアを採用するか、社内で採用実績のあるベンダー製ソフトを採用するかの決定は大まかには以下の思想で実施した。100発100中ではないのはお察しください。
特に、内製ソフトは過去に利用した製品で必要な機能を実現することのみを目的に開発されたケースが多く、他製品への再利用が非常に困難であった。汎用性や、ソースコードの再利用性という幻想にとらわれない判断が必要と痛感した。
状況 | 方針 |
---|---|
社内で実績のある内製ソフト vs 社内で採用実績のあるベンダー製ソフト | ベンダー製ソフトを採用 |
社内で実績のある内製ソフト vs 世の中で採用実績のあるベンダー製ソフト | 社内実績は別製品のユースケースに対応できたというだけで、開発中の製品に利用可能かどうかは保証されないことが多いように思う。基本的にはベンダー製ソフトを採用。 |
ベンダー製ソフト(1) vs ベンダー製ソフト(2) | より多くの世の中で実績がある方を採用。機能が満たされているか、ベンダーの言う実績が嘘でないか、使い方が比較的容易か、開発中の製品のユースケースにどれだけ類似しているか等を判定根拠とする。 |
担当者が独自に作った謎のWinApp
積極的には試験システムへの採用やそのための修正は行わず、参考程度にとどめる。
同様のことがフリーソフトやOSS等で可能なら、そちらに切り替えることも検討する。
どのぐらい作り直すか
基本的にはプロトタイプ開発の初期では、簡単な動作確認すら通らないレベルのバグ以外は修正しない。
中期では、バグの修正や未実装のエラーハンドリングの開発等を実施する。
末期では、市場での利用を想定した試験を行うケースもあるため、必要であればソースコードのリファクタリングを含む開発を実施する。
末期に実施するリファクタリングは遅すぎるという意見もあるが、初期にリリースされたソフトウェアに対するリファクタリングは最終的にその成果が製品に生かされないことが多く、末期のリファクタリングは日程的に厳しいケースが多く、「え、今からやるの?」というケースもあった。はやらないよりやる方がよかったように思う。
余談だが、初期から再利用性の高いコードや、可読性の高いコードを作成することが理想的ではあるが、開発が複数年にまたがる中・長期的なプロジェクトの場合は、初期に開発したコードが製品までに利用されないケースが多く、初期段階でのソースコードの品質はプロジェクト全体への影響は非常に限定的であったように思う。
ここでも、糞コードだからといって、即修正ではなく、そこそこ以上の品質で動くものは、最低限の修正を行い、取り込むことを前提とする。
完成とはなんなのか
永遠の課題です。むしろ、教えてほしいです。開発期間終了か、予算がなくなった日が、完成の日かなって。。。。。
組織・個人とのかかわり
協力会社メンバー・派遣社員とのかかわり方
当時、正社員数名、派遣社員10名程度、協力会社3社(4社だったかも)の体制で開発を行っていた。多くの開発シーンがそうであるように、容易に統制が取れない状態になり、プロジェクトが炎上することは日常であった。
メンバー間の信頼関係が厚ければ、多少の炎上も問題ではないため、各メンバーとの信頼関係の構築は非常に重要であったように思う。ただ、信頼関係に依存した開発や組織の多くがうまくいかなかったのは残当。信頼関係は構築するもので、依存したり利用したりするものではないので。
働き蟻の話ではないが、メンバーが増えると、アウトプットのないメンバーが必ず出没するが、無理にアウトプットをもとめず、できる範囲でやってもらう方が、組織全体が回ることが多かったように思う。アウトプットのないメンバーに無理やりアウトプットを求めると、周囲の足を引っ張るケースが散見されたため、やむを得ない選択ともいえる。
また、能力の低い派遣社員や協力会社もすぐには契約解除にせず、周りの足を引っ張らない限りは続投の判断をした方が開発が進んだように思う。
ただし、予算が潤沢でない場合はこの方法は使えないので、比較的予算が潤沢なプロジェクトばかりだったのは不幸中の幸いかもしれない。
開発していた機能は複数に分かれており、メンバーを機能単位で複数のサブチームに分け、チーム内で調査・要件分析・実装・テストまで行うこととした。ソフトウェアのレイヤーでチームを分割する方法も採用したこともあったが、プロトタイプ開発の場合、要件が目まぐるしく変化することや、ドライバ・APPともにアップデートが頻繁に行われることから、チーム間の連携がうまくいかず、開発が回らなくなるケースが多かったように思う。
そのうえで、各チームには必ず最低限2人のプロパーを配置するようにした。機能間の連携や依存関係がそれほど大きくなかったため、チーム間の連携が問題となることは少なく、開発は進めることができたのは幸いだったのかもしれない。
やらかした記憶
余談だが、開発委託先の方と個人的な関係を深く持ちすぎてやらかした話を書きたいと思う。当時は、2重派遣はすでに違法であったが、2重請負は日常であった。当時のテンプレとしては、発注元のA社は委託開発会社のBと契約しているが、Bはそれを個人事業主Cさんに再委託しているという状況であった。ひどいケースでは、当時は1人月80万~90万が業界の標準であったが、B社が40万円程度マージンを取り、そこからもろもろの雑費や税金を取り除くとCの手元には30万も残るか残らないかというありさまであった。
委託開発先のCさんと仕事上がりに飲みに行った際に、その事実を聞いて、ちょうど人手不足が叫ばれ始めたタイミングであったこともあり、Cさんはもっと条件のいい他社の仕事を探そうとしているという話を聞いた。話を聞けば、今の仕事内容が嫌なわけではないとのことなので、マージンが非常に低いD社を紹介し、Cさんが単独で行っていた仕事はD社に委託し、D社がCさんに再委託する流れとなった。直接契約せずにD社を間に挟むことになったのは、当時A社では社内規則で個人事業主との契約が認められていなかったため。
派遣社員の場合、派遣業法に抵触する可能性が非常に高いが、業務委託契約だったので、CさんにD社を紹介したことも、CさんがD社に移ったのはCさんの判断だし、D社がCさんに再委託するのもD社の判断だし、コンプライアンス上も法律上も問題ないと考えていたし、CさんとのWin-Winの関係を築けたのでみんなハッピーと考えていたが、ここから、驚きの糞展開に。法律的にNGな部分があればどなたか教えてください。
後日、どこから聞きつけてきたのか、まさかのB社の営業が乗り込んできて、曰はく「おたくのせいで、当社の売り上げがXX万円低下した。この補償はどうしてくれる。」とのことだった。法律的にもコンプライアンス的にも何も悪いことはしていないし、仕事の発注先をB社からD社に変えたのは社外からとやかく言われる内容ではなしい、D社がCさんに再委託することも何の問題もない理解であっため、非難されるいわれはないと考えていたが、なぜかここで謎の「商習慣的にそれは認められていない」というパワーワード炸裂で、会社対会社の係争に発展してしまう事態に。
その後の経緯は記憶があやふやなので割愛するが、最終的に自分と自分の上司が始末書(何に対する始末書なのかいまだに理解できていない)を提出し、B社に詫びを入れることで事態を収束させたと記憶している。
ちなみに、B社とは後ほどすべての契約を解除した。B社の営業も異動になったらしい。どうも、方々で似たようなことをやっていて、相当、社内外から嫌われていたとかなんとか。
それ以外の社外とのかかわり方
協力会社やその他のベンダーとは、可能な範囲でつかず離れずの関係を構築した。特に、協力会社には実力ある人員のリソースを割いてもらうために、以下に気を付けた。
- 十分なアウトプットアある限りは、支払える金額は支払う
- 食事会(要するに接待)のオファーがあった場合は、可能な限り受け入れる
- 季節の挨拶等も可能な限り日時を合わせて参加する
- できるだけガチャガチャ(委託開発の場合、契約はそのままに人員を入れ替えることをそう呼んでいた)は避ける
すごく無駄なことのように思われるが、規模がそれほど多くない開発の場合、社外に「売り上げは大きくないが、中・長期的にある程度の売り上げがあがる」と思わせておいて、実力ある人を割りあててもらいやすい関係性の構築が必要であった。ただし、あまりにひどすぎるときは、(お察しください)。怒鳴り込むのは最後の手段ということで。
社内政治的な何か
ある程度、開発が進むとメンバーも増え、かかわる社内の部署も増えてくる。こうなると、社内の以下のような謎の組織・メンバーがどこからともなく現れる。
- 過去のトラブルをベースに懸念を展開してくださる方
- 進め方変更の提案をしてくださる方
- 現状の開発品に対する品質不足へのダメだしをしてくださる方
- コストメリット追求のための提案をしてくださる方
- 追加人員の提案をしてくださる方
いくつかまじめに取り合ったこともあったが、これらの提案のうち、1割も合理的な提案はなかったように思う。おそらく、割合は組織や製品、次期等によりぶれると思われるが、1割を抽出するためにすべてを検討するのは効率の面からもナンセンスなので、基本的には検討の台上に乗せることはしなかった。
社内政治に敗れてひどい目にあった記憶
1つ、忘れられないエピソードを書き残したいと思う。
ある日、社内の類似の製品を開発している他部署Aから、追加人員の提案があった。曰はく、「開発規模を縮小しているので協力会社・派遣社員の方を減らす必要があるが、一度減らすとその人は別のところへ行ってしまう。実力がある人なので、会社につなぎとめておいて、将来的にまたいつでも一緒に仕事をできるようにしておきたい。なので、人員不足なら、一度、そちらと契約してみないか。」という内容であった。この発言そのものが法律的にNGでは?という話もあるが、こういうことは日常茶飯事であった。
当時は人集めに苦労していたこともあり、契約(たしか、業務委託契約だったと思う)を行ったが、数か月間、何もアウトプットアがないのである。
後日わかったことだが、どうやら、他部署Aは派遣会社Bの営業と結託して、他の部署にアウトプットがない(言ってしまえばAからもBからもお荷物な)メンバーを契約させ、部署Aに実力あるメンバーを集めていたようだ。
当然、ある程度見守った後に、契約を解除しようという話になる。が、突如、派遣会社Bの営業が打合せで「部署Aにいいメンバーを集めていて、そちらは社としては赤字である。今契約しているメンバーの契約を解除するなら、トータルで売り上げが立たないため、部署Aのいいメンバーも引き上げてC社(競合)等に営業をかけることになります。」と。
結局、社内の権益関係の政治に負けて、契約は続行し、数百万円/月×数か月のムダ金をむしり取られることとなった。
類似のケースは頻発され、他部署からの横やりで子会社に発注をかけた案件で数百万円もかけたアウトプットが、満足いくものではなく、部署の固有のメンバーが本気を出して2Wですべて作り直したというケースもあった。
このように、組織が巨大化すると、社内の権益関係が複雑になり、組織の機動力が失われるケースが多々あった。そのため、チームの独立性を確保することの重要性を痛感した。
自分の内面とのかかわり方
おそらく、誤字脱字のチェックすらしていない、メンヘラポエムにも近い駄文をここまで読んでくださった方の多くは同様の経験をされているとは思います。次に、自身がどうやって殺伐とする組織で形だけでも生き延びれていたかを記したいと思う。
割り切りは必要
一般的に開発は課題と必要なリソースを明確にし、予算・人員を確保し、開発のマイルストーン等を明確にするのがよい開発を言われているが、少なくとも教科書的なよい開発に巡りあったことがなかった。これからもないと思う。日数が経つにつれ、マイルストーンに対する遅れや、社内外に公表可能な成果が上がらない、小さな失敗やトラブルが散見され開発が思うように進まないという現象は常に自然に発生していた。これらは自身の努力では解決不可能か一部しか解決できないというケースが大半であった。以下のように割り切ることで、ある程度は精神のバランスを保つことができたように思う。
- 期日遵守の精神を捨てるもしくは、その優先度を下げる
- 成果が上がらないことに悲観的にならない
- 小さな失敗にはとらわれず、大局的視点を持ち続ける
- 自身の努力では解決不可能な問題にとらわれない
特に、成果に関しては、予算の都合上、上期の成果・下期の成果という話は常に付きまとうが、開発計画が数年間に及ぶため、ほぼ成果のない半期があっても自然なことと考えることとした。日程もかなり細かく定義されていたが、本当に守るべき日程はごく一部であったように思う。
また、開発が進むにつれ、他の開発にも成果を生かしたいという話が出るケースもあった。一例をあげると、企画部門は開発の成果を他の製品にも使いたいと考えている。ただ、開発の初期段階では想定されておらず、リソース的にも他製品の使いまわしを考慮した開発は非常に困難。また、他製品の概要も不明瞭でリソースが確保されていても、開発側に反映ができない。心無い人は汎用性を意識して開発を進めれば可能というが、そもそも汎用性が定義されない状況では。。。。
組織の中での生き方
開発が進むにつれ、関わる他部署や、社外の組織も多くなり、非常に組織が重くなる。その中で、最低限気を付けていたこと示す。
- 間違いは許容されるが、嘘は許容されない
- 他者の失敗に最大限寛容になる
- 他人の目を気にしない
特に、短絡的に嘘をついて乗り切ると数か月後に自身に跳ね返ってくるというのをよく見たため、嘘をつかないように注意した。ここでいう嘘とは、相手が嘘をつかれたと感じるケースも含む。
また、社内政治的な面で、いわれのない非難を受けることも多かったが、多くのケースでは非難する人は非難することで自己を肯定し満足していたため、結果的に気にする必要がなかったように思う。また、原因はそれだけではないと思うが、他人の目を気にしすぎたためプロジェクトが失敗に終わったケースが社内には多くあったように思う。
休暇の取り方
一般的に言われることだが、自分の存在が絶対に必要というケースは本当に稀で、どれだけ重要な人物でも数日休む程度では、どれだけ未熟な組織でもなぜか組織はとりあえずは回っていく。逆に、休養を取らなさ過ぎて、精神のバランスが崩壊し、キーマンが途中離脱したプロジェクトは最終的に失敗に終わったケースが社内で見受けれらた。無事之名馬という故事があってな。
おそらく、炎上しがちなプロジェクトに従事する人が考える無茶な休養でも、最低限の休養にすら届いていないケースも多いのではないかと思う。
- 休養は無理にでも取るぐらいがちょうどいい
- 体調が悪い日は問答無用で有給もしくは半休
- 徹夜、だめ、絶対
まとめ
思い出しながらだらだらと長く書いてしまったが、最後にまとめとしたい。結局は、「何事もバランスですよ」という話に収束してしまって、ここまで根気強く読んでくださった方には申し訳ない限りである。
- 開発したものの取り扱い
- 開発したものは、品質が悪くても、他の機能への悪影響がない限りは、動作実績や機能が実現されていることを重視して作り直しは実施しない
- 特に、開発初期段階では、機能の実現性と、その安定性を判断の主軸とし、リリースが見えた時に作り直しの判断を行う
- メンバーとのかかわり方
- 信頼関係は構築するもので、利用・依存するものではない
- アウトプットの低いメンバーに無理にアウトプットを求めると周りの足を引っ張りだすので注意
- アウトプットの低い派遣社員・協力会社も予算があり・周りの足を引っ張らない限りは契約を続行する
- 委託先の社員、派遣社員と必要以上に個人的なかかわりを持たない
- 社内外の組織とのかかわり方
- 社外 (特に開発委託先)との良好な関係を築き、中長期的に売り上げが立つと思ってもらうための努力は必要
- 社内の権益関係にとらわれると身動きが取れなくなるので注意が必要
- 組織の独立性を維持するためには、人員・予算の確保が必須
- 自分の内面とのかかわり方
- 期日遅れや成果の不足や小さな失敗は気にしない
- 自身の努力で解決不可能な問題にはとらわれない
- 嘘はつかない
- 他人の目を気にしない
- 休暇は無理にでも取る