ソフトウェア設計論

まつ本

モダンSW開発

モダンSW開発 -CI/CD-


目次

・CI/CD
・CIで何がうれしいのか?
・Linusの法則

・CIツール・CI環境
・GitHub Actions
・宣言的
・アクション
・演習✍️️

・CIを活用した論文執筆
・CIを活用した実験
・プログラマの三大美徳

CI: Continuous Integration

継続的インテグレーション

継続的にビルドを実行するというプラクティス
ビルド ∈ {依存の解決, コンパイル, テスト, ⋯}

自動ビルドを実行するタイミング

基本はソースの変更時 (git-pushやPRマージ)
定期的に実施するケースもある (毎週や毎月)

CI適用の前提条件

ソースコードがある #09
テストがある #10
ビルドスクリプトがある #11
版管理上で上記リソースが管理されている #12

CIで何がうれしいのか?

バグの早期発見

テストが落ちたら即通知する
バグを含んだ状況を放置しない・させない

🤔💭 先程の変更でテストが落ちた
🤔💭 いつの間にかテストが落ちていた

CIはテスト実行を強制するという側面を持つ

マージ地獄の回避

ブランチがかけ離れるとマージが大変
かけ離れる前にmainブランチにマージする

🤔💭少しのdiffをmainに統合する
🤔💭大量のdiffをmainに統合する

500行のコードレビュー

雑談


https://x.com/iamdevloper/status/397664295875805184

論文でも同じことが言える

雑談



🤔💭 提案手法の図をチェックして下さい



🤔💭 原稿全体をチェックして下さい

CD: Continuous Delivery

継続的デリバリ

自動ビルドに加えてリリースも自動化する
CIをさらに推し進めた考え
CI/CDとまとめられることが多い

適切なタイミングで自動リリースする

必ずしも世界に公開しなくても良い
開発チームや顧客だけが対象でも良い

関係者が常に最新の実行バイナリを取得できる

開発者の利点

フィードバックを得やすい
要求との齟齬も発見しやすい







"Given enough eyeballs, all bugs are shallow"

Linus's Law

リリースの研究

雑談

Adopting CD in AAA Video Games


https://www.youtube.com/watch?v=8hXRvvFDztg

モダンSW開発 -CI/CD-


目次

・CI/CD
・CIで何がうれしいのか?
・Linusの法則

・CIツール・CI環境
・GitHub Actions
・宣言的
・アクション
・演習✍️️

・CIを活用した論文執筆
・CIを活用した実験
・プログラマの三大美徳

CIツール・CI環境

様々な選択肢がある

GitHub Actions / CircleCI / Jenkins / ⋯
組み合わせるという使い方もあり

GitHub Actions (GHA)

GitHubは版管理だけでなくCI環境も提供している
CIは版管理が前提になっているため合理的

ワークフローファイルをリポ内に配置するだけ

ワークフロー (WF)

CI上で自動処理させる作業のまとまりのこと
例) 1WF = Javaソースのコンパイルとテスト

GHAのワークフロー定義

ファイル名

.github/workflows/compile-and-test.yml

内容

まずはトップレベル要素のみを抜粋

name: Compile and test

# トリガ定義:いつワークフローを実行するのか?
on:
  ...

# ジョブ定義:ワークフローは何をするのか?
jobs:
  ...

参考:構文の定義

ワークフローファイルの全体

name: Compile and test

# トリガ定義:いつワークフローを実行するのか?
on:
  push:       # git-push時

# ジョブ定義:ワークフローは何をするのか?
jobs:
  compile_and_test:         # ジョブの名前
    runs-on: ubuntu-latest  # ジョブの実行環境
    steps:                  # ジョブを構成するステップ
      - uses: actions/checkout@v6     # git-pull
      - uses: actions/setup-java@v4   # install java
        with:
          distribution: 'temurin'
          java-version: '21'
      - run: ./gradlew build          # gradle build

宣言的 (Declarative)

雑談

命令的と宣言的

命令的:処理の手順を記述するパラダイム
宣言的:対象の性質を記述するパラダイム

命令的なプログラムの例

for (int i = 0; i < textContents.length; i++)
    if (!textContents[i].startsWith("//"))
        count++;  // コメントではない行を数え上げ

宣言的なプログラムの例

count = textContents.stream()
                    .filter(s -> !s.startsWith("//"))
                    .count();

ループをどのように回すかは一切気にしない

ワークフローファイルは宣言的

雑談
on:
  push:       # git-push時

「このWFはgit-push時に実行する」と宣言する
git-pushをどう検出するかは一切意識しない

宣言的の利点

細かい処理ではなく本質だけを記述できる

  • 処理の隠蔽化 & 読みやすい & バグが減る

具象レイヤと抽象レイヤの切り分け

宣言的パラダイムが広く浸透している

Javaは命令型言語だが宣言的要素もある

  • Streamやラムダ式等 (関数型言語から由来)

命令的な記法であらゆる処理は実現できる

雑談

最後は機械語という命令的表現で動作するため

しかしSW開発は複雑になりすぎた

この複雑さを減らすためには適切な抽象化が必須
Streamを用いた配列操作はまさに抽象化
配列の操作方法をStreamが隠してくれる

count = textContents.stream()
                    .filter(s -> !s.startsWith("//"))
                    .count();

宣言的な仕組みを積極的に使おう

ビルドツールはmake / AntよりGradle / Maven

機械学習ライブラリはまだ命令的な傾向が強い
PyTorch / TensorFlow

アクション

ワークフロー内の再利用可能な作業のこと

jobs:
  compile_and_test:  # これはjob
    steps:
      - uses: actions/checkout@v6     # これがaction
      - uses: actions/setup-java@v4   # これもaction
        with:                         # ↑の設定
          distribution: 'temurin'
          java-version: '21'
      - run: ./gradlew build          # これはnot action

GHA固有の仕組みなので注意

アクションにより典型作業を宣言的に記述可

actions/checkout:作業対象リポの内容を取り出す
actions/setup-java:javaをインストールする

actions/checkoutの中身

actions/checkoutのソースコード

https://github.com/actions/checkout

宣言の舞台裏で何が起きているのか?

uses: actions/checkout@v6 で隠蔽化された処理は?
gitの内容を取り出すという操作はどう実現する?
単に git-clonegit-pull するだけではないのか?

舞台裏

src/git-source-providers.ts#getSource
計200行 & 様々な条件分岐を含む
checkout操作をあらゆる状況で動かすため

actions/setup-javaの中身

(詳細は略)

Javaインストールは環境依存が強い

CPUアーキテクチャ (x64 / x86 / aarch64)
プラットフォーム (win / mac / linux)
Javaディストリ (temurin / oracle / adopt)
Javaバージョン (23 / 21 / 17)

setup-javaは上記の条件分岐を隠蔽化する

利用者は環境依存に頭を悩ませなくて良い

CI上でトラブルが発生した際に
「Javaインストール作業」が容疑者から外れる

演習 ✍️️ (10m)

python-dotenvのCI上での処理内容を読み取れ

https://github.com/theskumar/python-dotenv/
※python-dotenvは環境変数ファイルを読むライブラリである
.env 等のファイルから自動的に key=value の中身を読み取る

提出方法

以下書式のテキストをCLEに提出すること

# 1
???
# 2
<ステップ1の処理内容の要約>
<ステップ2の処理内容の要約>
...
# 3
???

0. テストのワークフロー (WF) ファイルを開け

WFのパス:python-dotenv/.github/workflows/test.yml

1. test ジョブが実行される条件を調べよ

(ヒント) on: の内容を読み取れば良い

2. test ジョブの内容をステップ毎に説明せよ

(ヒント) uses:run: を確認すれば良い

3. 自動テストが実行されるステップを特定せよ

4. 自動テストの実行環境を特定せよ

複数のOSと複数のPython verの組でテストされる
これはマトリックス戦略と呼ばれる

(ヒント) テストWFの実行結果を見ても良い

5. テストの実行環境が非対称な理由を考えよ

Ubuntuでは複数のPython verでテストしている
しかしWindowsは2つのverのみである

次の疑問への答えを探すか考察せよ

  • なぜWindowsのみ2verなのか?
  • なぜその2verなのか?

(ヒント) テストWFの実行時間はどうか?
(ヒント) WFファイルにヒントはないか?


CI/CDが単純な作業の自動化ではなく,
様々な戦略に基づく自動化である点を認識せよ

Marketplace

誰かが作成したアクションを検索できる

https://github.com/marketplace?type=actions

WF内の作業は手で実装する前にまず検索すべき
命令を書くよりも宣言する
車輪を再発明しない

面白そうなアクション

ChatGPT CodeReviewer
super-linter
OpenCommit
Metrics embed
generate-snake-game-from-...

モダンSW開発 -CI/CD-


目次

・CI/CD
・CIで何がうれしいのか?
・Linusの法則

・CIツール・CI環境
・GitHub Actions
・宣言的
・アクション
・演習✍️️

・CIを活用した論文執筆
・CIを活用した実験
・プログラマの三大美徳

CIを活用した論文執筆

1. 原稿の各種リソースを版管理する

ソースコード .tex .bib
リソース .sty .bst .svg .png
ビルド方法 .latexmkrc

原稿の最新状態だけでなく執筆過程も記録する
複数人で執筆するなら適宜ブランチを使う

ただしPDFファイルはコミットしない

版管理しないほうがよいデータ

  • 生成可能なデータ
  • バイナリデータ

リポジトリの肥大化 & 履歴の邪魔 & 衝突の原因に

2. CI上でコンパイルする

.github/workflows/build-latex.yml

name: Build LaTeX document
on: push
jobs:
  latexmk:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: xu-cheng/latex-action@v3  # latexmk実行
      - uses: ... # TODO: 生成したPDFをどこかに設置

PDF公開先はGitHub Pagesや研究室のサーバなど

行儀の良く版管理しつつ最新のPDFを常に公開
"Given enough eyeballs, all bugs are shallow"

Q. Overleafではだめなのか?

CIを活用した実験

1. 実験リソースを版管理する

実験スクリプト .py
依存関係の宣言 requirements.txt
実験の入力データ .txt .json .bin
ビルド方法 (実行方法) .sh .bat pyproject.toml

実験データが巨大な場合 (>100MB)

小さいテスト用データを版管理内に登録
これはスクリプトの検証に使う

本番データは研究室のWebサーバやAWS等に設置
httpでアクセス可能にしておく http://.../x.txt
(機械学習のモデルも同様)

2. GitHub Actions上で小実験を回す

git-push時にスクリプトを回す
小さなテストデータで検証する
あくまでスクリプトの検証が目的

3. CircleCI上で本実験を回す

2が成功したらCircleCIで本実験を動かす
GPUも使える https://circleci.com/docs/using-gpu/

本番データはCIからhttp経由で取得させる
(機械学習のモデルも同様)

実験結果は研究室サーバへ転送 & Slackへmsg

計算コストが高い場合は3に実行条件を加える

特定ブランチにマージした場合のみ実行する等




There are three virtues of a programmer; laziness, impatience and hubris


Larry A. Wall





by Randal Schwartz from Portland - Flickr

プログラマの三大美徳

Laziness, 怠惰

楽をするために努力する
(同じ作業の繰り返しはサボりたい)

Impatience, 短気

使いやすいプログラムを作る
(使いにくい状態に苛つく)

Hubris, 傲慢

誰も批判できないプログラムを作る
(強い自尊心がある)

モダンSW開発 -CI/CD-


目次

・CI/CD
・CIで何がうれしいのか?
・Linusの法則

・CIツール・CI環境
・GitHub Actions
・宣言的
・アクション
・演習✍️️

・CIを活用した論文執筆
・CIを活用した実験
・プログラマの三大美徳

CIの本質は作業の自動化

SW開発だけに特化していない

論文執筆にも役立つ

CIのような自動化の感覚を持っておくと良い

あらゆるところで役立つ
同じことを手で繰り返さない

最初だけ頑張る・後はサボる
楽をするために努力する

ミスも減る

エンジニアは怠惰で短期で傲慢であれ

怠惰であればCIを使うべき