Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

The 2021 State of DevOps Reportが出た

ということでスキマ時間に読み進めていたので、感想と面白いと感じた点をまとめときます。網羅性が高く公平なまとめが必要な方は、3〜4ページに掲載のExective Summaryをおすすめします。

テーマは「中間層からの脱出」

6ページ目を見てもらえれば一目瞭然、今回のテーマは生産性が高くできず中間層で留まっているチームに対する処方箋の発見にあるようです。

近年のレポートは「今更それは無いでしょ」って感じのLow levelが5%強、「リアルチートじゃん」って感じのHighが10%強で、ほとんどのチームがMiddleに属していました。ごく少数の上澄みが高いパフォーマンスを出していて、その鍵となるKPIもベストプラクティスもわかっているのに、ほとんどの中間層は現状から脱出できず指を咥えて見ていた……と言ったら言いすぎでしょうか。この8割を占めるMiddle levelをさらに細分化し、中間層を脱するための働き方を見つけようということです。

f:id:eller:20210726175415p:plain
DevOps evolutionary levels (State of DevOps Report 2021 p.6 より引用)

DevOpsのやり方がだいぶ浸透してきて「何を計測し何をやるか」から「どうやるか」に関心がシフトしてきたとも言えます。同じ6ページにはDevOpsについて語ることよりも働き方について語るチームが多いことが述べられています:

In fact, many of the teams that are “doing DevOps” well don’t even talk about DevOps anymore—it’s simply how they work.

面白いと思ったところ

  • トップダウンによりボトムアップ型の改革を可能にする (p.11)
    • 経営の協力は当然必要というか「DevOpsによる生産性の向上=経営の関心事」という大前提がこのレポートには感じられる
    • 生産性が低い組織はリスクを避けるためにリスクを増大する手段を選択する傾向にある(p.31)が、これも部下を信じられない・Continuous Deliveryの適用をためらう経営なのではと思った
    • executive summaryによれば何でも話して疑問を解消し論点を明確にできる組織が高い生産性を持つわけで、マネジメントやリーダーの日々のコミュニケーションの賜物なのだろうと思った
  • DevOpsチームの存在は組織の進化を助けず、その曖昧な責務が組織に混乱をもたらす(p.13)
    • 開発とオペレーションの間に独立したDevOpsチームを配置するのはアンチパターンとして知られる(p.13)
  • 高度に進化した組織にとって文化は障害にはならず、これこそが高度に進化した理由である(p.14)
  • Team Topologiesという概念の導入(p.17)
    • Fast flow(p.16)実現にとっての障害を取り除くことに注力するものである(p.29)
    • 役割が多く、小規模のチームに当てはめるのは難しそうだと感じた
    • これを実現するための教育はどうやるのだろう?各チームの役割について専門家を探すのも難しそうな気がする
  • internal platformsについて
    • 2020でも触れられたが更に掘り下げて説明している(p.36)
    • 社内向けシステムを構築する際に利用できる認証・認可・デプロイ・保守・監視に使えるPlatformという理解をした
    • データレイクにおけるデータカタログとかも入ってくるんだろうなという理解をした
    • 高度に進化した組織はこうした基盤をinternal customerのビジネスを理解してエンジニアに構築提供している(p.30)
    • こうしたplatform teamがあっても生産性が向上するとは限らないが、DevOps transformationを加速できる(p.30)
    • 標準やルールではなくサービスを提供するということ、すなわち人をチームを信じることが肝要なのだと感じた
  • DevOpsの進化とinternal platformsの利用状況には関連がありそう(p.18)
    • 知識やベストプラクティスを他のチームと活発に共有することが生産性と関連しており、(p.19) これこそがMid levelを脱出するためのとっかかりになる(p.29)
    • だからこそ「でも保守(conservatism)も必要だよね」というCTOコメントが面白い(p.31)
    • 他チームがデプロイの課題を解決したことについて話す事例(p.28)があり、チームの壁を超えて課題解決や挑戦について共有する仕組みや文化が必要なのだと感じた、成果発表会のような季節性の仕組みでは動作しなさそう
    • Chat、金曜のメール、月次学習セッションといった共有手法の一例が共有されている(p.29)
  • 文化を嘆くのをやめて手を動かせ(p.28)
    • これ個人的にはとても気に入った、文化は個人の持ち物ではなくmutabilityを確信できないので
    • 表層の変えやすく失われやすい変化ではなく、5 Whyで組織文化の根っこを変えよう (p.32)
    • 日々正しい方向に組織の振る舞いをnudge(誘導?)していこう(p.32)

過去ログ

2019と2020の感想はTwitterを漁れば出てきます

Gradleのbaseプラグインに書くべきでないconventionとは何か

ひとつ前の記事では「Gradleの設定やコードをどこに書くべきか」のうち、答えが明確な「build.gradleファイルとbuildSrcディレクトリの使い分け」について書きました。この記事ではまだ自分の中でもよくわかっていない「Gradleでbaseプラグインに書くべきでないconventionとは何か」について書きます。

baseプラグインとは

ここで言うbaseプラグインは、plugins { id "base" } で使えるThe base pluginのことではありません。Gradleプラグインの設計手法のひとつとして推奨されている「設定より規約」の文脈で登場するものです。「設定より規約」を実現しつつ、(大部分のケースをカバーするであろう)規約が適用できないケースでもプラグインの機能を使えるようにするため、プラグインの規約(conventions)と基本的な機能(capabilities)とを別のプラグインに定義する設計手法です。

例えば java プラグインjava-base プラグインの場合、 java プラグインが規約を提供し、 java-base プラグインが基本的な機能を提供します。 java プラグインjava-base プラグインに依存することで、java-base プラグインが提供するtaskやextensionを利用します。

なお公式にはbaseプラグイン「ではない」方のプラグインには固有名詞がないのですが、ここでは記載を簡略化するために「規約プラグイン」と呼ぶことにします。

GradleはConventionという用語を多義的に使っている

ではbaseプラグインに書くべきconventionとは何か。この話題に触れるにあたり、GradleがConventionという用語をいつどのように使っているか確認する必要があります。私の知る限り、大きく分けて以下の3つが存在します:

  1. ”設定より規約”の文脈でのconventionのこと。一般的な用法。
  2. プロパティを指定しなかった場合に暗黙的に採用される値。default valueのこと。
  3. プラグイン設定用のconvention
    • 例えばJavaPluginConventionなど。
    • 現時点では非推奨なため、Extensionを利用する必要がある。

こうなるとよくわからないのが「baseプラグインに書くべきでないconventionはどれ?」です。

1のconventionはプラグインが提供する規約そのものでありbaseプラグインに書くべきでないのは明らかですが、JavaBasePluginCargoBasePluginは2と3のconventionを含んでいます。

規約プラグインであるJavaPluginCargoPluginはconventionを持っていることを期待され、実際1や2のconventionを含んでいます。

非推奨となった3のconventionは脇に置くとしても、2の置き場所やそれを決定する判断基準は明瞭に持ちたいところです。

メソッド名に惑わされないのが吉か?

私も2021年7月現在では明瞭な判断基準は持っていないのですが、ポイントはProperty#convention(Provider)というメソッド名に惑わされないことだと思われます。言い換えれば、2のconventionはどこにでも出てくるものだと割り切り、1のconventionを規約プラグインに限定して書くことのみに注力します。そして機能を書く上で必要なプロパティがある場合、baseプラグインでも気にせずにデフォルト値をProperty#convention(Provider)メソッドで設定してしまいましょう。

公式フォーラムに問い合わせてみた

自分的にはわかった気になれましたが、なんかしっくりこないので公式フォーラムに問い合わせてみました。

discuss.gradle.org

返信もらえたらこちらのブログ記事も更新します。

2021年9月29日更新: 公式Slackの方で「JavaBasePluginが異色なだけ、普通は1と2と3は全く同じものでbaseプラグインには出てこないべき」というコメントを貰いました。確かに一番シンプルなまとめ方かもしれません。

GradleのbuildSrcとどう付き合うべきか

Gradleで複数サブプロジェクトをもつプロジェクトを作成する - kdnakt blog を見て、buildSrcディレクトリ周りで混乱した記憶が蘇ってきました。

ということで「Gradleの設定やコードをどこに書くべきか」のうち、答えが明確なbuild.gradleファイルとbuildSrcディレクトリの使い分けについて現時点での見解をまとめておきます。

宣言的か命令的か

Gradleのビルドスクリプトを分割統治する手法として、昔はscript pluginと呼ばれる手法が使われていましたが、Gradle 7.1.1時点ではbuildSrcプロジェクトを使ってimperative logicを抽象化することが推奨されています

imperative logicというのはつまり”命令口調”なビルドスクリプトのことですね。ビルドスクリプト自身が極力宣言的(declarative)になるように、命令的なスクリプトをビルドスクリプトとは別のところに書いておこうということです。ビルドスクリプトを宣言的に保つことは、Gradleベストプラクティス堂々の一位に位置づけられており、その重要性が伺えます。

そしてimperative logicを隠しビルドスクリプトを宣言的に保つことは、プラグインの説明に書かれているように、プラグインの設計意図そのままです:

What plugins do (omit) Encapsulates imperative logic and allows build scripts to be as declarative as possible

自分が最近書いた例でいうと、チェックサムをGitHub Releasesに掲載するためのタスク定義はTHE・命令的でした。この定義、あるいは抽象化した定義をプラグインとして書いておいてビルドスクリプトに適用することで、ビルドスクリプトそのものを宣言的に保てるということです。

命令的なコードを置くためのbuildSrcディレクト

通常プラグインはGradle Plugin Portalにpublishして使いますが、プロジェクトごとにpublishしていたらキリがありません。そこでプロジェクト固有のローカルな"命令的"スクリプトを置くための場所として buildSrc プロジェクトが存在します。プロジェクトルートに buildSrc ディレクトリを置くと、中のコードをコンパイルしたものをビルドスクリプトのCLASSPATHに置いてくれるのです。

以上のように、全体像がわかってしまえばbuild.gradleファイルとbuildSrcディレクトリどちらを使うべきかは見えてきます。 宣言的なコードはbuild.gradleファイルに、命令的なコードはbuildSrcディレクトリに置きましょう

buildSrcプロジェクトの書き方はmike-neckさんのブログに詳しいのでオススメです。プラグインテスト手法も確立しているので、ビルド性能だけでなくビルドスクリプト管理の生産性も上がるといいですね。

mike-neck.hatenadiary.com

GitHub Actionsのworkflow_runイベントでテストを回すときの要点

Dependabotの作ったPRがSecretsにアクセスできないためにことごとく失敗していたのを修正しました。

github.com

SecretsにアクセスできないのはKeeping your GitHub Actions and workflows secure: Preventing pwn requestsで説明されているようにセキュリティ向上のためです。workflow_run イベントでCheckを回すとワークフロー定義は常にデフォルトブランチのものが使われるため、PRでワークフローファイルが悪意を持って変更されてもマージしなければ悪影響を受けません。ので今後、基本的にはSecretsを必要とするワークフローはworkflow_runイベントで回すことになります。

上記securitylab.github.comの記事で色々説明されていますが、わりと限定的なユースケースについて述べているので、ここでは自分のケースで必要だった知見についてまとめます。

actions/checkout ではrefプロパティを指定する

ソースコードをチェックアウトする場合、どのrefをチェックアウトするのかを明示的に示す必要があります。何も指定しない状態ではデフォルトブランチをチェックアウトしてしまうため、PRで変更する内容をテストできません。

on:
  workflow_run:
    workflows:
      - build
    types:
      - completed
jobs:
  integration-test:
    runs-on: ubuntu-latest
    if: github.event.workflow_run.conclusion == 'success'
    steps:
      - uses: actions/checkout@v2
        with:
          ref: ${{ github.event.workflow_run.head_sha }}

Pull RequestのChecksを登録する際もshaを指定する

この「何もしなければデフォルトブランチの最新refが対象になる」のが曲者です。例えばChecksに結果を反映する際も、明示的にshaを指定する必要があります。

      - uses: LouisBrunner/checks-action@v1.1.2
        if: always()
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          name: integration-test
          sha: ${{ github.event.workflow_run.head_sha }}
          conclusion: ${{ job.status }}
          details_url : https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}

Secretsなしでもテストできるようにする

すべてのテストをworkflow_runの方に寄せても良いですが、Secretsなしでも実行できる単体テストや静的解析はpull_requestで実行してしまったほうが良いかもしれません。 その場合は、./gradlew buildnpm run all がSecretsなしでも正常ステータスコードで完了する必要があります。

JUnitならassumptionsでTokenがあるか確認して無ければテスト実行をスキップすればいいでしょう。Jestではうまい方法が見つからなかったので、Tokenの有無でtesttest.skipを呼び分けることにしました。

const token = process.env.GITHUB_TOKEN || ''
const integrationTest = token ? test : test.skip

integrationTest('fork() does nothing if the forked repo already exists', async () => {
  ...
})

MRJAR (Multi-Release JAR)を使っているOSS一覧

参考

SLF4JとLogbackは2021年現在では積極採用しない方が良い(2023年12月 追記)

SLF4JとLogbackの中の人はここ数年活発ではないのでLog4j2などを代わりに使いましょう。

SLF4Jの活動は最近活発ではない

SLF4JはVCSとしてGitHubを利用しています。最後の変更が2020年2月最後のリリースが2019年12月となっていることからも、あまり活発ではないことが伺えます。

またBTSとしてJIRAを使っていますが、こちらもメンテナンスされていません。昨夏SLF4J-209が既にクローズ可能な状態であることSLF4J-186が修正可能であることなどをコメントしましたが、1年近く経った今もすべて返信がない状態です。

2020年12月にイシューを閉じていたりするので全く動きがないわけではないのですが、年間で22つ作成されたのに対して2つしか閉じられていないので、充分にメンテされているとは言い難い状況です。

2021年5月31日時点での過去360日のイシュー消化状況

2021年6月2日追記:Java9リリース以降期待されていたJigsaw対応が入っている2.0(元々1.8だったもの)の安定版がずっと来ていないことも課題です。初回リリースである 1.8.0-alpha0 が2017年04月だったので、4年は経過しています。最新の 2.0.0-alpha1 は2019年10月のリリースで、未だα版ですが、モジュールを利用する場合は1.7は使えない(複数のモジュールが同一パッケージを提供できない)ため使わざるを得ない状況にあります。

メンテナーを増やすつもりはない?

2020年8月14日に ceki@qos.ch にメールを送り、メンテナーを増やすつもりはあるか、あるなら自分はこういった貢献ができますという意思を伝えたのですが、こちらもまだ返信がありません。

少数のメンバーがリリース権限を握っており、かつプロジェクトリーダーが連絡を取れない状態……と考えると、かつてのFindBugsプロジェクトの最後に非常に近い状況にある気がしています:

blog.kengo-toda.jp

Log4j 2が活発に活動しているのが幸い

ではSLF4JやLogbackに頼れないとして、どういった移行先があるのか。ロギングファサードないしロギングライブラリとしては、以下のような選択肢があります:

個人的にありがたいのはLog4j 2が活発なことです。Logbackを採用する理由として実行性能があったと記憶していますが、Log4j 2はLogbackと比べても高い性能を示しているとされています。lazy loggingflow tracingなども備えています。あと地味にLoggerインスタンス作るのが楽です:

// SLF4J
// http://www.slf4j.org/faq.html#declaration_pattern
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

// Log4j 2
// https://logging.apache.org/log4j/2.x/manual/api.html#Logger_Names
private static final Logger logger = LogManager.getLogger();

ログライブラリはプロジェクトによって要件も異なるでしょうし、必ずしもLog4j2が最適な選択肢とは限りませんが、一度試してみても良いのではないかと思います。

2021年6月2日追記:既にあるプロジェクトのSLF4JやLogback依存を今すぐに切らなければならない状況ではないと考えています。これから始めるプロジェクトでは積極採用するべきではないと思いますが、そうではない場合、特にモジュールを利用する予定がない場合(Java 8利用中など)はそのまま使い続ければいいかと思います。新規プロジェクトでモジュールを利用する場合は、更新頻度の低いα版に依存するリスクを受容できるのかどうか検討する必要があるでしょう。

2021年12月11日追記:CVE-2021-44228の1件でLogbackが注目されているようなので、ここ半年の状況を整理します。

まずSLF4Jが更新されていなかったという点。6月から8月にかけていくつか更新が入り、ResolvedがCreatedを上回った時期がありました。

2020年12月〜2021年12月におけるチケットの遷移(SLF4J)

Logbackも同様で、6月から8月にかけて更新が入っています。

2020年12月〜2021年12月におけるチケットの遷移(Logback)

ちょうど6月にEclipse FoundationからSLF4Jがabandoned projectなんじゃないかと言われているのでこの集中的な更新との関係性を疑いましたが、関係がないそうです。個人がリードするプロジェクトなので更新にムラがあるのは理解できます。

ちょっと信じがたい脆弱性を作り込んだもののセキュリティポリシーが明確で有事の対応が期待できるlog4j2と、非活発だがログに理解の深い開発者が見ているLogback。どちらを選ぶのかは組織のポリシーによって変わってきそうです。

2023年12月15日追記: 2023年末時点での情報に関する記事を書きました。

blog.kengo-toda.jp

内製化をすすめる知人へのアドバイス

ソフトウェアエンジニアとしての働き方を探求してきた経験と、駐在員として文化の狭間でうろちょろしてきた経験、OSSエンジニアとして多数の多様な人材と交流してきた経験をもとに、果敢にも内製化に挑戦する知人へのアドバイスを気持ちまとめます。

前提

  • 主な利用技術にはJavaSpring Framework)やTypeScriptを想定
    • FaaSを始めとしたManaged Serviceは(いまのところ)積極採用しない構え
  • Digital Transformationを推し進める一環としての内製化に、エンジニアリングの観点から挑む方を読み手として想定
    • 内製化のターゲットは決まっているか心当たりがある状態
    • 既存の開発チームはほぼ無い想定

1. チームビルディング

1.1. スーツとギークの対立を避ける

我々が若かった頃は"スーツ"と"ギーク"の対立を煽る風潮にありました。Rockstar Engineerという、ひとりで27倍の生産性を持つエンジニアを称賛する動きもありました。Being Geekという本の表紙がまさに象徴的です。

それから時は流れ、ギークとスーツは消えました。チームマネジメントが再評価され、Rockstarよりも多様性が重視され、Stallmanが批判され、Linusが変わりました。我々は生産性27倍のSPOFをありがたがることをやめ、ソフトウェアエンジニアリングを組織に適用し業務効率を高め、サイロを克服しドメインを深く理解することによってビジネスを加速化することが求められるようになりました。組織にとって選択肢でしかなかったソフトウェアエンジニアリングは、Lean Software Developmentの確立や端末の市民への普及によって、すべてのビジネスに溶け込んでいます。

現代においてDDDやプロジェクトマネジメント、品質管理やサブスクリプションに関する本を手に取ると何が書いてあるでしょうか。科学的に仮設を検証し高速に市場を創出するための手法として、いかにビジネスとテクノロジーを融合するかという一点に関心が割かれています:

  • ドメインに注力することでビジネスの専門家とソフトウェアエンジニアリングの専門家が同じ用語で議論できるようになり、またソフトウェアをビジネスに追随させやすい状態を比較的保ちやすいことが知られるようになりました。
  • Project Managerはプロジェクトマネジメント手法としてAgileを学ぶことを求められています。
  • 品質とスピードがトレードオフではないことも広く知られ、スピードのために品質に関心を払うことがQAだけではなくProject Managerや経営層の関心事になりました。
  • 多くの企業がサブスクリプションに移行しているのは、収入の予測可能性が高まることに加え、顧客とのつながりを確保しテクノロジーを通じて多様な顧客を理解するための役割を期待しているところもあるようです。

しかし、Digital Transformationのための開発組織を構築する際は、かつての対立が再現されやすいような気がします。 特に"ギーク"が"エイリアン"として振る舞い"スーツ"がそれを"受容"する……という空気を作ってしまうと容易にハマります。

無用な対立を避ける意味で最も良いのは、「ビジネスとテクノロジーが融合する重要性」という内製化の背景を経営層が理解することです。そのきっかけ作りとして私はソフトウェア・ファーストを経営に読むことを勧めたりしていますが、打率はあまり高くない印象です。たぶん長すぎるんでしょう。

読者(ソフトウェアエンジニアリングの責任者)がビジネスの文脈を理解できている場合は、経営との対話を通じて少しずつ意識を変えていくことも効果的かもしれません。
このとき、相手は内製化の背景をまだ共有できていない、ビジネスのスピードを高める必要性を理解していないということを意識する必要があります。相手の語彙で対話し、相手にその必要性を再発見させなければなりません。でもこういう誘導する話し方って、焦っているときほど難しくなるんですよね。他社事例をストックしたり、スピードが出せていないことによる機会損失を試算したりと、普段から道具を収集しておくと助けになります。また話している文の主語を省略せず、常に明確にしましょう。これだけで誤解を避け、相互理解を進められる場合がけっこうあります。

1.2. 目指すアウトカムについて開発チーム内外で合意し文書化する

経営側の意識を変えにくい場合でも、内製化をする理由・テクノロジーに期待するアウトカムを議論し、文書として共有すると良いです。明確な目的は今後のコミュニケーションに役立つでしょう。

アウトカムを明確にすることは、組織がテクノロジーを融合する重要性を理解する助けとなるだけではなく、ソフトウェアエンジニアがビジネスを理解する助けにも、ソフトウェアエンジニアが目先のノイズに囚われないための助けにもなります。この時点では定量的でなくても良いので、チームを越えた錦の御旗として使うに値する明瞭な目標を持つようにします。

1.3. Agileでなくとも構わないが、学習できる組織を目指す

アウトカムを明確にしたくても、そもそも目標や目的の明文化に抵抗がある組織もあります。その場合、その文化を変えることがDigital Transformationよりも重要な課題だと認識する必要があります。なぜなら、目標と目的の明文化は経験主義に立脚する今日のソフトウェア開発において頻出するからです。たとえば:

ここでのキーワードは「学習」です。Scrumやself-organizing team、組織論について学ぶと必ず出てくる言葉です。組織に人によって教えられる”正解”はなく、試行錯誤が必要です。我々がDigital Transformationを目指すのも、この試行錯誤のサイクルを速めたいからだったはずです。よって個人や組織が学習できる環境を作ることが求められます。

ではどうすればいいのか。中原淳氏の研究(2010年)によれば、職場で人が育つためには「業務支援」「内省支援」「精神支援」が必要だそうです。ソフトウェアエンジニアにとっては「OJTや技術教育」「1-on-1を通じた振り返りの促進」「日々のコミュニケーションで励まし褒める」ことになります。

目的が明確であれば、OJTの内容も、1-on-1で振り返る方向性も、褒めるポイントも明確になります。また失敗をした際に意味のあるPostmortemをすることもやりやすくなるでしょう。目標や目的を明文化し、個人と組織が学習できる組織を作ることを心がけましょう。

1.4. 専門職を設けるべきか

今回の想定事例のような新しいプロジェクトで、ビルドやテスト、運用について専門職を設けるべきでしょうか。個人的には否定的です。 人材の流動性が高く既存資産も多くない状況であれば、全員が開発から運用まですべてのプロセスに関わる方が開発高速化の恩恵を受けられるはずです。

ビルドスクリプトやパイプライン定義、プロビジョニング手順はファイルで定義してGitで管理するようにします。 これにより属人性を下げるだけでなく、変更内容がレビュー可能になり信頼性も向上します。

2. 技術選定

とりあえず↓に目を通すのがおすすめです:

qiita.com

その上でいくつか具体的な話を。

2.1. 目指したい「品質」の合意を作っておく

ビジネスの専門家はもちろん、ソフトウェアエンジニアにとっても「品質」の定義はゆらぎがちです。人によって違う定義を使っていたり、品質保証に幻想を抱いていたりすることもあります:

一応ISO/IEC 25010:2011でモデル化されているのでMECEに考えること自体はやりやすいのですが、全部重要に見えてきて「これローンチなんて何年も先になるのでは?」みたいなことにもなりがちです。もちろんそんなことはできないので、優先度をつけなければいけません。

今回の想定するケースでは、少ない資産で早急にプロダクトを作り検証を通じて学習し成果を出さなければならない状況のはずです。であれば、私としてはMaintainabilityを重視します。コードをどんどん書き、どんどん捨てられることが何よりも重要です。そのためにコードが疎結合であること、テスト可能であること、目が届き把握できることを優先します。

なおMaintainabilityは、今回の想定事例以外でも重要視されている認識を持っています。ビジネスなどの変化が速く、すぐに「最適」が変化するためです:

一方でPerformance EfficiencyやCompatibility、Usabilityは脇に置いても良いと考えます。MVPによって正しい仮説を掴むまでは、これらの判断をしようがないためです。Webアプリケーション開発のようにインストール先が管理下にある場合は、Portabilityも不要かもしれません。さすがにSecurityが低優先とは言いませんが、ある程度のリスクは受容する判断があってもいいでしょう。

2.2. ビルドパイプライン

パイプラインファーストを志向するべきです。ソフトウェアプロジェクトを始める際は、まずパイプラインを構築します。

Gitを使ったPull Request(PR)ベースでの開発をする場合は、デフォルトブランチへの直接pushを禁止し、ビルドを壊す変更が導入されない状態をパイプラインによって保ちます。

CIがあればPRは不要だとする意見もありますが、今回の想定では新設チームであることも鑑み、いきなりデフォルトブランチへのpushを解禁することは危険だと判断します。あと、あんまり直接pushを是とする組織は現状多くないと思うんですよね。長いもの(industry standard)に巻かれておくことは、組織外の資源を有効活用するためのひとつの知恵です。

なおビルドパイプラインがどうあるべきかは、以前ブログに書いてますのでご参考まで。

2.3. まずはテストケースから書く

先述の通り、品質としてはMaintainabilityを最優先にします。そのためには、まずテストケースから書き始める文化を醸成します。新機能開発にTDDを適用したり、バグ修正時にバグを単体テストで再現したりといったところから着手します。

このプロセスを不要あるいは非効率と主張された場合は、品質とスピードがトレードオフではないことを根気よく伝えていく必要があります。プロダクトが高速に変化・成長するためには、既存機能が壊れていないことを機械的に検証する手段である自動テストは非常に重要です。またテストケースから書くことには、目的や目標の明確化をチームに促す効果もあります。

なお勘違いしてほしくないのですが、作成したテストケースは削除して構いません。実装や要件が変わり、既存テストが不要と判断された時点で削除しましょう。不要なテストが多く残ることでビルドやデプロイのパイプラインが遅くなっては元も子もありません。もちろんテストの並列実行のような技術的な解決方法はありますが、不要なテストを実行する理由にはなりません。
一応テスティングフレームワークには実行をスキップする機能もありますが、あれを多用すると好ましいスキップと悪しきスキップとを判別するコストが上がるので、VCSを信じてサクッと消すのが吉です。*1

また自動テストケースがあれば手動テストが不要、というのもよくある勘違いです。テスト自動化の8原則にも書いてありますが、手動テストはなくなりません。手動テストすべきところにコストをかける手段として自動テストがある、くらいの理解がちょうどいいかもしれません。

2.4. プロジェクト固有ルールを作らない

コミットコメント、コードレビューのやり方、ラベルの扱い、ビルド用コマンドやリリースノートの書き方など、ソフトウェア開発にはオレオレルール策定のチャンスが多く潜んでいます。これらを早めに潰すことで、新しくプロジェクトに参入する人の参入障壁を減らし、特定プロジェクトでのみ行うべき配慮をなくすことができます。既存資産がなく人材の流動性が高くレベル感もあわせにくい状況では、これは大きな助けになるでしょう。

例えば以下のような、一般化され公開されている知見を流用します:

逆に個人の裁量を認める部分としては、エディタやOSがあります。これらの選択を自由にするための技術として、というか開発環境の差を最小化する技術として、以下のようなものがあります:

なお新しい手法をまず小さく試すために一部プロジェクトに適用する、というのはありです。堅苦しく”管理”することは本意ではありません。必要なのは検証中という状態をずるずると伸ばさないことで、これも前述の学習する組織の構築や目的の明確化によって達成可能です。

2.5. KubernetesとかService MeshとかMicroserviceとか、他にもなんかエッジなやつ

チームが小さいうちは考慮しないでいいです。こまめにデプロイしリリースできることが重要です。 将来的にチームが増え、チーム間の協力体制をどう築くか?が組織の関心事になってからで良いでしょう。

3. 忘れてはいけないこと

実行こそが最重要です。ぐだぐだと基礎や知見、歴史を語ることは必要かもしれませんが、実行だけが世界を変えます。

つーか「明瞭な目標を設定しよう」とか、言うだけならタダなんですよ。それを現実のものとするのに、一体どれだけの傾聴と対話と勉強と失敗と思い切りが必要なのかって話ですよ。頑張ってください。

まとめ

  • ビジネスの専門家とともに目的と目標を設定し、継続的に学習するチームを作る
  • 求めるアウトカムと品質について、チームと議論し共有する
  • パイプラインとテストを最初期に導入する
  • コードを書け、検証しろ、振り返りをしろ、実行がすべてだ

あわせて読みたい

いただいたフィードバック

学習できる組織とはそもそもAgileでは?という疑問に対して、Agileという用語を避けることでビジネスの専門家に受け入れやすくなることを期待していると返答したことに対していただいたフィードバック:

内製化そのものに関してはあんまり触れらてないのでその辺をもっと聞きたい、という意見への私の考え:

*1:この点ではLaunchableにはちょっと期待していまして、スキップすべきテストが自動的に選択される未来が一般化するのかもしれません。