SI系企業で社内独自のフレームワークを作りたくなる理由について

ITアーキテクトブログ
11 min readDec 29, 2017

--

フューチャーアーキテクト(裏) Advent Calendar 2017 の14日目です。

tl;dr

  • 社内フレームワークは開発生産性を高めるためと言われることが多いが、実際はシステムを守るために産まれる(ことがある)
  • すべては複雑怪奇な業務をシステム化する人が、システムアーキテクチャや非機能面まで全て見れないことに起因する
  • 画期的なハックはなく、業務にもシステムにも詳しい人を増やしていきましょう

はじめに

SI系の大規模な業務システム開発に参加すると、社内独自の重厚なフレームワークに遭遇することがあると思います。ここでいう社内フレームワークとは以下の条件に一致するものを指すことにします。

  • クローズドソースである
  • その社内でゼロベースで開発されたり、既存のフレームワークを拡張・ラップしているなど、独自の背景・思想により開発されている
  • そのため、フレームワーク独自のお作法や制約がある
  • 開発生産性の向上や、非機能的な要件を満たすことを目的とする

社内フレームワークに思いを馳せる

自分が経験があるのはJavaベースのWeb/バッチの両方に対応したフレームワークです。良いところも沢山合ったと思うのですが、クセが強かった記憶が強いです。例えば以下のような開発を行なう必要がありました。

  • 開発者が独自でRDBに対するコミット/ロールバックを行なうことができない
  • apache.commonsのStringUtilsじゃなくて基底クラスのユーティリティメソッドを使うことを推奨
  • よくわからない型の値をreturnする必要があるけど、その意味がよくわらかないので、みんな同じ値をセットする

などなど。

色々困りますよね

社内独自フレームワーク、良いか悪いかはさておき、一人の開発者としては困る点が色々あります。中には社内フレームワークが悪いというよりは、開発体制上の問題であったり、提供者側のモラルの問題な面も多いと思うのですが…。

  • 仕様をググっても出てこないため(当然ながらクローズド技術なので)、有識者に聞くかソースを読むしか無い
  • 仕様にクセがあることが多く、使いこなすまでに時間がかかる
  • 設計思想・API仕様・制約・FAQといったドキュメントが未整備なことが(経験上)多い
  • 仕様を満たせなかった時の対応方法を、メンテナンスチームにお伺いする必要があり、オーバーヘッドが発生する
  • 環境構築が難しい場合が多く、たいていQuick Startといった気がきいたREADMEが無い

あと、特徴として環境変数やシステムプロパティが外部定義ファイル化されている印象があります。便利だろうなと思う半面、項目が多すぎて何を切り替えたらどうなるかわからなかった記憶があります。

今思うとかなりモノリスなアーキテクチャで、かつオンプレミスだったので仕方ない面も多いんですけどね。

開発生産性は高まったと言えば高まったと思うのですが、フレームワークのキャッチアップ時間やハマった時間を考慮すると、劇的に向上したとは言い切れません。例えば、RailsやSpringBootがベースだとすでに開発生産性としては優秀ですしね。

作る側になってどうか

数年後、自分がいざフレームワークを提供する側のチームに入って、色々な立場があることを学びました。

まず、アーキテクチャを設計開発する立場として、非機能的な観点まで考慮した開発規約を作ると思うのですが、大規模開発だとまず守られないということを実感しました。どんな規約かというと、DBや外部サービスに負荷を書けないために、流量調整をしたりバッチ実行できるものはしてね、といったやつです。

いやいや、開発者の自主性に放り投げるのではなくて、コードレビューで担保しようねという話なんですが、フレームワークやアーキテクチャを設計した人がコードを見るのは、UnitTestが完成した後、つまりかなり開発工数をかけた後になります。

どうしてかというと、そもそも大規模だと個別の機能の仕様を、フレームワーク提供者は抑えきれてません。DBのエンティティ数が数百あって、この機能でどのエンティティのどの項目がどのようにCRUDされるべきかはかなり高度な業務的システム知識が求められるので、そもそも、その業務サブシステムを担当するチームしか細かい仕様は抑えられていません。

同時に、非機能まで意識できるレビュアーを大規模開発だと確保しにくいので、各サブシステムチームごとにアサインすることは難しく、多くはもっと広い領域を担当することになります。そのため、彼らは非常に忙しいので、仕様を満たしているかといった機能面のレビューまで担当することは時間的に不可能です。そのため、仕様的・機能的には担保されている状態≒UnitTest後にレビューするのが合理的になります。

つまり、フレームワーク開発者は、UnitTestが作成されたコードを、非機能的な側面にしぼりレビューをするということになります。

どういった観点でレビューするかって?

わかりやすいのは…

  • 大量件数になりうるデータを全件メモリ上に展開するコードになっていないか
  • N+1なSQL発行(マシンガンSQL)になっていないか、またはそれをバッチ化できないか
  • リフレクションなどオーバーヘッドが高い処理を無用に行っていないか
  • 適切な例外ハンドリングを行っているか
  • SQLでデットロックが発生するような操作をしていないか
  • オンライン処理とバッチ処理でデータ競合していないか

などでしょうか。

基本的には開発環境の数件のダミーデータでは顕在化しないけど、プロダクション環境で本格に利用されると顕在化するような、非機能的なポイントを確認します。

ここに上げた内容は割りと基本的なので、実際にはあまり指摘することは無いですが、たまにトンデモナイ状態のコードを見ることもあります。

で、レビューでダメだったらどうするか。

上記の程度であればちょっとした変更で対応可能かもしれませんが、例えば、長すぎるトランザクションを持つので、複数の機能に分割すべきだという結論になることもあります。

ここで結構困るのが、すでにある程度の工数を費やした上でUnitTestまで作られており、仕様的・機能的には正しく開発されているということなんですね。

それをほとんど作り直しに近い命令を下すのは、フレームワーク提供者側にとっても中々難しいものです。すでに工数をかけて開発していて、追加で作業する時間は正直厳しい、なんとかならない?と相談されるわけですから。

最低限の修正で応急処置をして、抜本的な修正はPJのバッファ期間に対応しよう、みたいな落とし所ですね。

持論ですが、PJのバッファ時間がそれに適用されることはないです。

そして技術的負債が産まれる

バッファ期間に回収されず、技術的負債な機能はフレームワーク提供者側にとっても目の上のたんこぶです。なんやかんや性能テストやロングランテスト、もしかするとシステムがカットオーバーされプロダクションに乗った後に不具合が生じ、運用に文句を言われる場合もあるでしょう。

非機能はアーキテクチャやフレームワークで横串で達成すべき項目なので、一つでも未達成な機能があると、関係者への説明に困ってしまいます。

もうこんなことを起こさないようにしたい。しかし、開発規約は守られないし、実際の所レビューまで来てしまったあとに大きく突き返すことは不可能。そうすると、フレームワークで悪さができないようにしよう!という思考になるわけです。

そうなのです。何も意地悪で機能を制限している訳ではないのです。前述のトランザクションを開発者自身の判断でコミット・ロールバックできないのも、きっと過去のだれかが不具合を生じさせた結果うまれた、フレームワークが課せた制約だと思います。

ある意味、フレームワークのなぜこの機能を封印しているんだ、使いにくいよっていうのは、自由度を狭めるための楔なので仕方ないのです。受け入れましょう。楔があるからには、その楔がなぜ生まれたに思いを馳せたほうが得るものがあるかもしれません。それがバットノウハウであったとしても何かを改善しようとした人たちの思いが詰まっているのです。

そうはいっても別の方法があるんじゃ?

ええ、わかります。

例えば、開発規約を作ったのであれば、それを自動チェックするLinterをCIでチェックすれば良くて、もっと細かなフィードバックを各開発者に送るべきでは?といった意見ですよね。その通りだと思います。

これが社内フレームワークの罪深いところで、お作法や制約がある割に、それをサポートする開発支援ツール(Linterやサジェスト)が貧弱であったり準備されていないことが多いです。わたし自身、フレームワークそのものの改修作業に手一杯で、Linterを作るという発想が無かったです。

このあたり、ファイル保存フックでLinterを起動し、社内フレームワークのお作法を守れているかチェックが出来れば、非常に闇が晴れるでしょう。むしろ社内フレームワークを正当性が薄まり、そもそも作らない方が良いよね、という話にすら繋がるかもしれません。

懸念として、社内フレームワークを取り巻く環境は闇が深く、Linterでチェックしても無視する人がおそらく出てきそうだなということがあります。その場合は、Linterのチェックに合格しないとリモートブランチにプッシュ出来ないといった開発フローを整備する必要が出てくるでしょう。

ここまで来ると、こんな対処療法的な本質じゃ無い整備は辛いので、非機能的な観点でシステムを守る立場からすると、ランタイムの開発フレームワーク側で変なコードを動かなくしようか..、みたいなテンションになります。

消耗戦みたいだねって誰かがつぶやいてました。

そもそも、そういう人がいる時点で

わかります。みなまで言わないで…。

まぁ、でも、例えば100人とか200人の開発者を揃えようとすると、個性的な人材も集まるわけで、色々なことが発生するんですよね。

やったことないですが、30人とかでも急に集めるのは今のエンジニア不足のご時世、とても大変だと思います。

どうすれば?

社内フレームワークが産まれる理由を考えると、各開発者が非機能的にシステムに不整合や負荷を書けないようにすることが、達成したい大きな目的の一つにあるのは間違いないと思います。

そのため、フレームワークという開発ランタイムで担保させるのではなく、別の手法で担保させれば、フレームワークからお作法や制約を消すことが出来ます。

例えば、

  • 静的・動的なコード解析で臭うコードを早めに検知し、的を絞りレビューする
  • 本番想定のシステムテストを自動化してCIを回しシステム的な不整合を検出
  • 開発環境のデータセットの精度と量を増やす

などです。しかしこれらを準備は、これはこれで大変な作業です。

結局のところ

一番てっとり早いのは、業務サブシステムのリーダーがシステムの非機能面までに精通することかもしれません。仕様的・機能的に正しいというレビューをし、同時に非機能的なこともレビューできれば文句ないです。もちろん、逆に技術的に精通した人がもっと業務詳細まで踏み込んでいくことも必要でしょう。

無論、人力で各々のスキルアップに期待しましょう、なんてお花畑で終わらず、Linterや開発規約(Whyまで説明できている)やLinterやCIなどを整備し、開発環境を機械化・自動化する仕組みで取り入れる所は取り入れていくというのが現実解ではないかと思います。

その間に、静的解析技術が進み、より高度なコンテキストを抑えたLinterが発達することに期待したり、それらLinterそのものの開発に投資したほうが、社内フレームワークに投資するより実りがあることかもしれません。

まとめ

  • 社内フレームワークは開発生産性の向上というよりは、非機能要件を守ることを目的に産まれることもある
  • それらの品質は、開発フレームワークでのを除くとテスト・レビュー・Linterなどで担保するしかないが、本番さながらのテスト準備は難易度が高く、レビューとLinterなどで担保するしかない
  • Linterでチェックできることの上限があるので、Linterを作るフレームワーク技術の発達が求められる

--

--

ITアーキテクトブログ

エンタープライズ系の開発についてTipsやポエムを中心に書きます