組込み C / C++ プロジェクトの初期の全体感を何とかする

この記事は Akerun Advent Calendar 2022 - Qiita の 17 日目の記事です.

ファームウェアグループの @tarotene です.「組」と「込」の間の「み」はつけない派です 1.昨年も 2 本ほど記事を書いておりました:

akerun.hateblo.jp

akerun.hateblo.jp

今年は技術的な学びも沢山あり,その中からピックアップしてちょっとお硬いテーマにしてみました.せっかくなのでお付き合いください.

TL; DR

一般に Github などのホスティングサービスで新しいコードベース(プロジェクト)を立ち上げる際に検討しておくと良さそうに関して,組込み C / C++ 特有の知見がこの 1 年で溜まったので年末の大掃除がてら共有します.基本的にはプロジェクトレイアウトを大きなスケールでは他人任せにして,一段浅いところではちゃんと考えようねというお話と,ビルドシステムは積極的に使おうという話の 2 階建てで,既存の知見を自分なりの観点で整理してみました.パッケージマネージャの話もちょっと補足してあります.

「C / C++」という括り方に関して

自分で書いていて雑だと思ったので予防線としての断り書きです.ここでいう C++ は C 由来のオブジェクトと相互にリンク可能なオブジェクトを自分自身も生成できる言語,という意味合いです.本来の C++ の機能的サブセットとして捉えて下さい.

「組込み」の指すスコープ

組込みという言葉は相変わらずだいぶフワッとしていると思います.

本記事では「(典型的に)サーバ PC 上で動くような Web アプリケーションとは性質を異にするソフトウェアならびにプラットフォーム全般」としてざっくりと定義してしまいます 2

本題: 自由なプロジェクトレイアウトと柔軟なビルドシステム

そもそも,C / C++ がどこで必要になるかを考えると,筆者の思いつく範囲だと概ね

  • 組込み向けアプリケーション開発(RTOS 含む)
  • PC 向け OS の開発
  • 軽量言語のランタイムの開発

とその周辺に絞られるように見えます(学習・教育・研究目的を除く).その中でも(市場の大きさから)組込み向けアプリケーション開発がボリュームゾーンになるという認識を持っています.

こうした領域ではリアルタイム要求の帰結として CPU やメモリを(仮想化を一切介さずに)直接利用できることが前提のことも多く,近年では Rust による置き換えの実施例も増えてきていますが,C / C++ を完全に置き換えにかかるのはまだまだ難しそうな印象があります 3

しかし,C / C++ はそれなりに長い歴史を持つ言語なので,モダンな開発言語が必ず備えているであろうエコシステムの一部―フォーマッタ,テストフレームワーク,プロジェクトテンプレート―をサードパーティに委ねざるを得ません.特に実務において問題になりがちで,ともすると開発において不便さを認識しづらいのがプロジェクトテンプレートの機能であると筆者は考えます 4

例えば,フォーマッタや静的解析の機能は近年だと LLVM ベースの clang-format や clang-tidy がデファクトスタンダードとして受け入れられつつあり,テストフレームワークに関しては GoogleTest がそれに相当します.一方で,プロジェクトテンプレートに関しては様々な提案がなされてきたものの未決着であるという印象です.

こうした状況に一石を投じたのが Pitch-fork layout です:

api.csswg.org

Pitch-fork layout は,既存の C / C++ プロジェクトを網羅的に調査する中で得られた気付きの蒸留であるという点でも興味深いものです 5

詳細は類書に譲りますが,C / C++ では(インクルードやマクロなど # から始まるプリプロセッサ命令を全て消化した後の)翻訳単位と呼ばれるソースファイルを個別にオブジェクトファイルに変換(コンパイル)し,それらをリンクすることでより大きなオブジェクトファイルや実行形式を作るのが通例です.したがって,任意の(ビルド可能な)C / C++ のプロジェクトにおいて,下記の 2 つが機械的に定義されます:

  • (プロジェクトの)ディレクトリ構造 =: プロジェクトレイアウト
  • (プロジェクトの)翻訳単位の集合

一方,ソフトウェア設計においてはこうした機械的な内部境界とは別に(抽象度が高めな)モジュール分割というものをよく考えると思います.ここで言うモジュール分割というのは,要するにヒトへの認知負荷の軽減されたドキュメントレベルのアーキテクチャのことです.

ここで,「ディレクトリ構造もしくは翻訳単位の集合は常にモジュール分割の良い表現たり得るか」という問題が自然と提起されます.なぜなら,異なる複数の設計情報を脳内に留めながらソフトウェア開発を行うのはそれ自体が大きな認知負荷であり,万難を排して避けたいことだからです.

Pitch-fork layout は,あるべきプロジェクトテンプレートの形を提示することで,こうした問題を部分的に解決してくれます.詳細は本家を眺めてみて下さい.

一方で,プロジェクトテンプレートの形を決めるのが開発の最初期の話であるとすると,開発の中期くらいまでは大規模なリファクタリングの一環でディレクトリ構造を転換させたくなる場面が多く発生します.つまり,プロジェクトとしては動的ディレクトリ構造を受け入れざるを得ません.しかし,こうした動的なディレクトリ構造を受け入れる仕事は,基本的に CMake のようなビルドシステムに任せてしまえば良いと考えます:

cmake.org

つまり,結論としてはざっくりと

  • プロジェクトレイアウトに関しては大規模なところと細かい命名規則は一旦 Pitch-fork layout で形だけ整えてしまおう
  • Pitch-fork layout で吸収しきれない動的なプロジェクトの構造変化は CMake で吸収してあげよう

ということになります.

こうした(プロダクトの価値とは本来独立な)技術的意思決定を一部肩代わりしてくれる言語経験者で C / C++ の大規模なプロジェクト(e.g., 組込み開発)に改めて参入予定の方の参考になれば幸いです.

閑話休題: C / C++ 用パッケージマネージャ conan の話

CMake には,開発環境の OS や CPU アーキテクチャを自動的に判別して起動させる C / C++ コンパイラを明示的に切り替えたり,組込み開発で必須とされるクロスコンパイラを指定する機能が搭載されています:

こうした機能は使いこなせば使いこなすほど利便性が身に沁みて分かるものですが,とはいえ複雑は複雑です.

また,CMake はそれ自体がプロダクションコードと同等の品質で書かれるべきという話 6 もあり,やたら滅多に CMakeLists.txt の改訂を行うのも避けたいです:

更に,例えば組込み Linux の開発では開発環境の PC 向けに動作させたいテストビルド(開発用 PC が x86_64 なら x86_64)とターゲットデバイス向けビルド(ターゲットが armhf なら armhf)を分けたいといったニーズがしばしば発生します.しかも上手くやれるなら,アプリケーション層は一切取り替えずに,低レイヤのドライバだけ(互換性がないので)ごっそり取り替えたい.そうしたニーズを世の中のソフトウェアエンジニアはどうやって解決しているのでしょうか.要するにパッケージマネージャはないんでしょうか.

残念ながら,プロジェクトテンプレートのケースと同様,C / C++ 向けのパッケージマネージャに純正品は存在しません.しかし,ある程度広く受け入れられた便利なサードパーティは存在します.それが conan です:

conan.io

C / C++ 向けのパッケージマネージャには,他にも vcpkg といったモノもあり,conan がデファクトスタンダードかどうかは難しい問題ですが,conan を初手で検討するのは悪くない判断だと筆者は考えています 7

考察〜結論

CMake や conan のような「動的な何かを吸収するエコシステム」が存在しない世界線を考えてみましょう.

仮に CMake がなければ,Makefile 直書きプロジェクトで Makefile を頻繁に変更することを強いられるでしょう.こうしたことは Makefile をバージョン管理せず独自に持つという危険なインセンティブに繋がります.

また,例えば conan のようなパッケージマネージャがなければ,開発者はおそらく git submodule を積極的に利用して外部ライブラリを導入するでしょう:

git-scm.com

しかし,git submodule もまた頻繁な変更を躊躇ってしまう対象です 8

要するにこれらはプロジェクト全体の変更コストを安くするための仕組みと言えます.しかし,導入することでプロジェクトのメンテナンス対象となるレイヤーが 1 つ多くなることにも気をつける必要があります.こうした事例は何でもトレードオフで,開発の初期に決めるべきことでもあるので,より多くの事例を知った上で普段からよく悩んでおくことがいざという時に最適な意思決定に導いてくれると筆者は信じています.


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com


  1. 付ける派の人の記事はこちらです.
  2. 少なくとも記事の趣旨としてカバーしたいのが組込み Linux 環境と(RTOS 含む)ベアメタル環境の 2 つであるという意図です.
  3. 長年に渡って蓄積されてきた開発資産の利用や既存のエコシステムとの共存を考えると
  4. プロジェクトテンプレートというより,プロジェクトレイアウトの方が用語としては適切かも知れない.テンプレートは,何らかのレイアウトの鋳型というニュアンスである.
  5. 調査の経緯は提案者のブログ記事 vector-of-bool.github.io に詳しく書かれています:
  6. https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1 を参照.
  7. このあたりは usagi.hatenablog.jp に詳しくまとまっています.
  8. submodule は git 本来のよく用いられる機能に比して表立って取り扱われないことが多く,ある操作(例えば submodule add)に対してその逆操作がアトミックなワンライナーで行えなかったりする点が不便である.

社内勉強会 (e.g. Next.js) のフォーマット

この記事は Calendar for Akerun | Advent Calendar 2022 - Qiita の 16 日目の記事です。

どうも、 daikw - Qiita です。

たまに社内勉強会を思いついたように企画していまして、企画したフォーマットの一つが少し気に入っています。それを紹介したいと思います。

前提・課題意識・活動

Photosynth 社では、 Akerun 実機の開発で利用する物理的なツールを一般に「治具」と呼んでいます。治具の中でも、シングルボードコンピュータ (Raspi) とディスプレイが搭載されたものが最も多く使われています。Raspi 治具と呼びます。

Raspi 治具は、施工対象と利用者に対するインターフェースをそれぞれ備えた、普通の Linux サーバと考えることができます。最近のゲームやコンテンツ系サービスのようにアクセスが多いわけでもないので、一見普通の web サーバより簡単そうに見えますね。

ただ、メンテナンスにはかなり横断的な知識を要求されます。実機との通信のための比較的低レイヤの仕込みや、web バックエンド・フロントエンドの知識が必要です。特に Web アプリケーションフレームワークの Next.js を採用したことで、FW 開発グループで扱うには少々ハードルが高い状態でした。

そこで、それなりにちゃんとした勉強会を企画し、属人化の回避とチーム全体のスキル向上を狙いました。

シープディップトレーニングと勉強会の工夫

学びとは、「人に対して」行われることではない。「人が」行うことである

シープディップトレーニン*1 という言葉があります。

羊の毛についた寄生虫を落とす目的で、滅菌用の薬品に漬けることをシープディッピングと呼ぶそうです *2

このシープディッピングに似たような、情報を浴びせるようなトレーニングをシープディップトレーニングと言います。一般には詰め込み教育とか言ったりするでしょうか。

この言葉は英語でも日本語でもあまり流行っていないようなのですが、「学び」の本質を突いているように思います。例えば、もくもく会はシープディップトレーニングとは対局にあって、参加者全員が自主的です。「学ばせる」のは間違いで、自ずから「学ぶ」のが正しいわけです。

僕はシープディップな「勉強会」や「授業」を憎んでおり、全てなくなれば良いと思っていまして、今回開催した勉強会も僕のアレルギーが出ない内容にするために工夫をいくつか入れました。

  • 参加者のモチベーションに合わせた複数のコースを用意し、完了目安時間を設ける
  • 全てのコースに「座学」と「ハンズオン」を用意する
  • LT の時間を作り、その日に完全に理解したことを発表してもらう

参考実装

web アプリケーションを要件から作ってみるトレーニングの一環として、実際に利用されている治具ソースコード 以外の 参考実装を一つ作りました。

https://github.com/daikw/file-uploader-nextjs

参考実装を使った「学び」の方法を、後述のフォーマットに含まれる内容から抜粋して示します。Progate などのように手順通りに作っていくタイプの勉強サイトだとフィードバックを得にくいようなタイプの「学び」だと思ったので目玉コンテンツのつもりでしたが、ほとんど誰もここまで辿り着けませんでした。 もし次回があれば、ボリュームに気を使おうと思います。

## Next.js を使ってアプリを作ってみる: OPTIONAL

- 正直どんなアプリでも良いが、何か目標があるとわかりやすい。
- 簡単なファイルアップローダーを作ってみる過程で、web 開発の一部を体感する
- セキュリティは一旦気にしないが、[セキュア・バイ・デザイン輪読会で勉強](https://akerun.hateblo.jp/entry/2022/12/06/000506)しましょう

### 取り組み方

1. まず後述の要件通りに作ろうとしてみる
1. 参考実装 (https://github.com/daikw/file-uploader-nextjs) を読んでみる
1. 参考実装か、自分で作ったものに対して改善を加えてみる

### 要件

- 機能要求
  - 3 つのページ・2 つの HTTP-API からなる web アプリケーション
    - ページ数・API 数は守らなくても良い
  - ファイルを保管し、ファイル名か何かをキーとしてダウンロードできる
    - 保管方法は任意・適当でいい・メモリ上でも最悪構わない
- 実装要件
  - フロントエンド
    - index ページ(静的なページ)
      - 他のページへのリンクを含む
    - 動的なページ 1
      - input 要素を 1 つ持つ(1 つはファイル入力・1 つはファイル名)
      - 入力をバックエンドに POST できる
    - 動的なページ 2
      - input 要素を 1 つ持つ(ファイル名)
      - GET で ファイルがダウンロードできる
  - バックエンド
    - `POST api/files`
      - 受け取ったファイルを保存する
    - `GET api/files`
      - パラメータにあるファイル名に合致するファイルを返す、なければ 404 を返す

### 本来あるべきアーキテクチャを構想する: CHALLENGING

このアプリを作る前に、いろんな部分に ? がつく

- ファイルはどうやって保管されるべきか?
- ファイル名はキーとして妥当か?
- そもそもこんなもん作らなくても Google Drive あるやん??
- etc ...

何か特に気になる課題を見つけて、それがビジネス設計上・アーキテクチャ設計上どのように改善されるのか議論してみる

実施風景

参加者

3 つのコースを用意し、参加者に選んでもらいました。 🎋 ばっかりになるかと思いましたが意外とばらけました。

  • 🌸 :cherry_blossom: 初級コース: 3 人
  • 🎋 :tanabata_tree: 中級コース: 1 人
  • 🎍 :bamboo: 上級コース: 2 人

reacji での参加アンケート

実施中

毎日夕方に LT の時間があり、全員が「完全に理解した」と言っている和やかな時間が流れました。

当日に完全に理解したことを共有する時間

結果

チームの実績解除を言語化し、情報共有・コラボレーションのベースラインを作りました。

解除した実績とリワード

勉強会のフォーマット

以下、社内固有の情報を除去し、再利用可能なフォーマットにしてみました。

毎年 4 月になると、非常に質の高いエンジニア新卒研修スライドが大量に公開されてすごいなと思います *3

とてもいいなと思いますが、僕はスライドよりマークダウン派です。僕は文章のスタイリングを編集しやすい文字列以外のメタ情報に含めるな過激派、アンチ WYSIWYG 代表取締役(仮)なので、社内で共有するコンテンツもほとんどマークダウン形式のテキストです。よって勉強会フォーマットもマークダウン形式です。アトラシアンは早くマークダウン対応してください *4

# 概要

## 契機

- 最近の治具アプリケーション では、Next.js を採用して実装しているため、メンテナには必須の知識である
- Next.js に限らず、 FW 開発者は web アプリケーションフレームワークに馴染みがない

## 目的

- 属人化回避
  - 治具メンテナに属人化している知識を敷衍する
- スキル向上
  - web アプリケーション開発に入門することで、web グループとのコミュニケーションを円滑にする
  - 治具アプリケーションのメンテナンスができるようになる

## なぜ Next.js か?

チケットへのコメントより、

> 治具には、最低限のフロントエンドとバックエンドの共存、zero-config 性が(他のフロントエンドフレームワークよりも)ややイケてるので、 Next.js を使っています

面倒なビルドツール周りの問題に煩わされることなく、ほぼ全部入りの web アプリケーション開発をサクッと始められるところが良い by @daikw

参考: [Next.js を使うべき 5 つの理由 + 実装 Tips - Qiita](https://qiita.com/Yuki_Oshima/items/5c0dfd8f7af8fb76af8f)

# 勉強会のフォーマット

## 基本

- 常時オンラインであることを要求せず、 [もくもく会](https://web-camp.io/magazine/archives/89540) のような雰囲気
- カリキュラムは、オーガナイザーが提供する後述の自習コンテンツから選択する
- オーガナイザー( @daikw ) にいつでも質問して良いし、周りの人に質問するのも OK

## ざっくりカリキュラム

### 梅コース :cherry_blossom:

- Next.js の チュートリアルをゆっくりこなす
- 治具を手元で動かしてみる
- どれかの治具に変更を追加してみる

### 竹コース :tanabata_tree:

- Next.js の チュートリアルを爆速でこなす
- 治具を手元で動かしてみる
- お題のアプリを作る
- オプション課題( OPTIONAL と表記のあるもの)をこなす

### 松コース :bamboo:

- Next.js の チュートリアルを事前に終わらせてくる
- お題のアプリは作らない
- 自分が作りたい要件を持ち込む & 実装 & 発表

# 自習コンテンツ

## Next.js のチュートリアル

### 目安時間

- :cherry_blossom: : 6 ~ 8 時間程度
- :tanabata_tree: : 4 ~ 6 時間程度
- :bamboo: : 事前に完了済 / 3 時間程度

### やること

- [Introduction | Learn Next.js](https://nextjs.org/learn/foundations/about-nextjs) から開始して、順番に章をこなしていく。
- クリアすると、ポイントが貯まって楽しい

実施する必要のない章もある。 :cherry_blossom: の人は `REQUIRED` を、 それ以上の人は `OPTIONAL` まで含めてやると良い。 `SHOULD NOT` は、FW グループで勉強する意味はあまりない。

| chapter                    | title                           | level      |
| -------------------------- | ------------------------------- | ---------- |
| FOUNDATIONS                | \*                              | REQUIRED   |
| CREATE YOUR FIRST APP      | Create a Next.js App            | REQUIRED   |
| CREATE YOUR FIRST APP      | Navigate Between Pages          | OPTIONAL   |
| CREATE YOUR FIRST APP      | Assets, Metadata, and CSS       | OPTIONAL   |
| CREATE YOUR FIRST APP      | Pre-rendering and Data Fetching | OPTIONAL   |
| CREATE YOUR FIRST APP      | Dynamic Routes                  | OPTIONAL   |
| CREATE YOUR FIRST APP      | API Routes                      | REQUIRED   |
| CREATE YOUR FIRST APP      | Deploying Your Next.js App      | OPTIONAL   |
| SEARCH ENGINE OPTIMIZATION | \*                              | SHOULD NOT |
| EXCEL                      | TypeScript                      | OPTIONAL   |

## 治具を手元で動かしてみる

### 目安時間

- :cherry_blossom: : 6 ~ 8 時間程度
- :tanabata_tree: : 4 ~ 6 時間程度
- :bamboo: : 4 時間程度

### ドキュメント等

`dfu-jig` を動かす前に、以下ざっと目を通すと好ましい。特に `docs/techstack-explain.md#治具開発コマンド` はよく使うスニペットが書いてある。

- `README.md`
- `docs/techstack-explain.md`

### `dfu-jig` を Mac 上で動かす: REQUIRED

#### やること

- クローンしたレポジトリで `yarn install`, `yarn dev` を実行する
- 画面を表示する
  - `http://localhost:3000` にアクセスする
  - [DevTools を開いてみる](https://developer.chrome.com/docs/devtools/open/)
- API Routes を叩いてみる
  - `curl http://localhost:3000/api/echo`: hello と返ってくるだけ
  - `curl http://localhost:3000/api/test/mqtt`: mqtt メッセージが送信される。メッセージを別の方法でキャプチャしてみるとか

### `dfu-jig` を Raspi 上で動かす: OPTIONAL

#### 必要なもの

ポートフォワードでアプリケーションを手元に引き寄せるので、ディスプレイや周辺機器はなくても良い

- Raspi x1
- 16GB microSD x1
- 施工対象 x1

#### やること

- `dfu-jig/README.md#Recipe` にある内容を Raspi 実機に対して操作する
- Raspi のホスト名を変更しておく(他の人と衝突するため。必須ではない)
- `ssh pi@$target -L 8080:localhost:8080 -L 80:localhost:80 -L 3000:localhost:3000` でログインし、ポートフォワードしておく
- 手元の PC 上で治具アプリケーションにアクセスする
  - 小細工なし -> `http://localhost`
  - dev サーバ(`yarn dev` で起動)を実行中 -> `http://localhost:3000`
- ログを流してみる
  - `journalctl -u dfu-jig.service -f`
- 起動した `dfu-jig` を使って、手近な製品の一つをアップデートしてみる
  - 色々触ってみましょう
- API Route を叩く
  - `curl htpp://localhost/api/dfu?device_id=A12XXXXX`: 治具バックエンドに、 `A12XXXXX` のアップデートを指示する
- `mosquitto_sub` を実行してみる(治具の `history` を見るとあるかも)

### どれかの治具に変更を加えてみる: REQUIRED

Mac 上で実行した治具アプリケーションに対して変更を加える。
dev サーバは `yarn dev` で起動できる。

起動中の治具に変更を加えて、動作を変える。
見た目をちょっと変えてみたり、レスポンスの内容を変えてみたりして動作を確認する。

変更推奨のファイル:

- フロントエンド: `dfu-jig/src/pages/index.tsx`
- バックエンド: `dfu-jig/src/pages/api/echo.ts`

## Next.js を使ってアプリを作ってみる: OPTIONAL

- 正直どんなアプリでも良いが、何か目標があるとわかりやすい。
- 簡単なファイルアップローダーを作ってみる過程で、web 開発の一部を体感する
- セキュリティは一旦気にしないが、[セキュア・バイ・デザイン輪読会で勉強](https://akerun.hateblo.jp/entry/2022/12/06/000506)しましょう

### 取り組み方

1. まず後述の要件通りに作ろうとしてみる
1. 参考実装 (https://github.com/daikw/file-uploader-nextjs) を読んでみる
1. 参考実装か、自分で作ったものに対して改善を加えてみる

### 要件

- 機能要求
  - 3 つのページ・2 つの HTTP-API からなる web アプリケーション
    - ページ数・API 数は守らなくても良い
  - ファイルを保管し、ファイル名か何かをキーとしてダウンロードできる
    - 保管方法は任意・適当でいい・メモリ上でも最悪構わない
- 実装要件
  - フロントエンド
    - index ページ(静的なページ)
      - 他のページへのリンクを含む
    - 動的なページ 1
      - input 要素を 1 つ持つ(1 つはファイル入力・1 つはファイル名)
      - 入力をバックエンドに POST できる
    - 動的なページ 2
      - input 要素を 1 つ持つ(ファイル名)
      - GET で ファイルがダウンロードできる
  - バックエンド
    - `POST api/files`
      - 受け取ったファイルを保存する
    - `GET api/files`
      - パラメータにあるファイル名に合致するファイルを返す、なければ 404 を返す

### 本来あるべきアーキテクチャを構想する: CHALLENGING

このアプリを作る前に、いろんな部分に ? がつく

- ファイルはどうやって保管されるべきか?
- ファイル名はキーとして妥当か?
- そもそもこんなもん作らなくても Google Drive あるやん??
- etc ...

何か特に気になる課題を見つけて、それがビジネス設計上・アーキテクチャ設計上どのように改善されるのか議論してみる

## 自分が作りたい要件を持ち込む & 実装 & 発表: CHALLENGING

比較的自由になんでもやっていいが、なるべく以下は守って実施する。

- 事前に、`Next.js のチュートリアル` を終わらせてくる
- 事前に、何か作りたいもののトピックを温めてくる
- アプリが動作しなくても、やりたかったことと解決法が発表ができる状態を目指す
- @daikw と相談するしないは自由

なお、発表に関するレギュレーションは当日相談して決める。想定は以下の通り。

- 10 min 発表, 10 min 質疑応答。発表にデモが含まれる
- スライド 10 枚以内
- 発表内容には制約なし

参考記事


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Pro の購入はこちらから akerun.com

バックエンドエンジニアが AWS の資格取得を決意した話

この記事は Calendar for Akerun | Advent Calendar 2022 - Qiita - Qiita の15日目の記事です。

こんにちは。AWS の資格を取ると決意した(取得したとは言っていない)、バックエンドエンジニアの ps-yu1129 - Qiita です。

今回は資格取得しようと思ったきっかけ等々について書いていきます。

AWS の資格を取ろうと思ったきっかけ

開発プロジェクトにて、 SRE の方、開発リーダーの方、私でインフラ構成についてミーティングする機会がありました。 ミーティングに参加した時点の私の AWS に関する知見は、動画教材を参考に EC2 で WordPress を立ち上げたりしたことがある程度の経験値でした。

当然、当時の知識量でミーティングで話している内容についていけるはずもなく、自分の無知を痛感し、AWS のサービスについての知識をつけようと決心しました。

なぜ AWS の資格取得なのか

ググったり本を読んだりすれば知識自体は身につくため、当初は AWS の資格を取得しなくても良いかなと思いました。

しかし、後述するような理由で資格取得することを決めました。

理由1:資格取得はわかりやすいゴール設定のため

資格取得をゴールにすると勉強の区切りが明快です。 終わりが見えないと、モチベーションを維持したまま勉強を続けるのは難しい(と私は思っています)ため、わかりやすいゴール設定があることでモチベーションを維持できます。

また、第三者に対して AWS についての一定水準の知識を有することを明示できますし、資格を持っていない友人に自慢もできます笑

理由2:資格勉強をすることで網羅的に知識をつけられるため

ググって先人たちの記事を読んで知識をつけることはできると思いますが、どうしても網羅性に欠けてしまいます。

また、アプリケーション開発の際に AWS のサービスを使うという選択肢を視野に入れられ、プロダクトに合わせた適切なアーキテクチャ設計ができるようになると思います。(例:定期実行の処理を行う際に Lambda を使用する、ECS のタスクスケジューリングを使用する等)

勉強を継続的に続けるために

私は一人で勉強を開始しても三日坊主で終わりがちだったりします。 そのため、どうしても勉強せざるを得ない環境をつくることで、継続的に勉強を続けるようにしています。 具体的には週に3日、AWS の SAA 取得に向けてのもくもく会を同僚のエンジニアと行なっています。

もくもく会の流れとしては下記のようなシンプルなものです。

  1. 時間になったら Google Meet に集合
  2. 今日やることを簡単に共有し、Google Meet から退出
  3. もくもくタイム
  4. 終了時刻になったら再度 Google Meet に集合
  5. どんなことを勉強したか、新たな発見の共有等を行う
  6. 解散

共有タイムでこれは知らないだろうと思ってドヤ顔で共有しますが、他の参加者はすでに知っているということが多々あって一瞬で真顔になります😐

また、実際にもくもく会をやってみて感じたメリットとしては下記の通りです。

  • 毎週決まった時間に始まるため、嫌でも勉強時間を確保できる
  • 自分以外の参加者に負けまいと勉強のモチベーションが上がる
  • もくもくタイム終了後の口頭共有で知識の定着度アップ
  • 雑談ができる(リモートワーク中心で雑談が生まれにくいため、嬉しい副産物)

特に、もくもくタイム終了後の共有タイムでアウトプットすることで知識の整理がされるため、これはすごく良いと感じています。 地味に雑談も楽しかったりします。(最近だとサッカーW杯の話をしたりとかしてます笑)

一人で勉強継続するのが苦手な方は、周りを巻き込んで一緒に勉強してみると良いかなと思います。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com

nodeJS初心者がレガシーコードのnodeJSに単体テストを入れてCIしてみた

この記事は Akerunのカレンダー | Advent Calendar 2022 - Qiita の 14日目の記事です。 はじめまして、nodeJS初心者の Esperna - Qiitaです(2022年6月からnodeJS触り始めました)。

背景

自動テストがない(手動の実機テストのみの)レガシーコードで、ちょっとした修正をするのにもバグが出やすく、 リファクタリングをするのが大変という状況ってありますよね。 そのような状況で今年自分が取り組んだことを書いてみます。 nodeJSにはJest*1があるのでそのチュートリアルを見ながら 次の2つを意識して単体テストを書きました。

  • 単体テストを書くことで既存のソフトウェアの仕様を明確にする
  • 単体テストをCIに組み込むことで仕様が明確な部分に関しては振る舞いが変わった時は直ちに検知できるようにする

やったこと

実際にやったことは以下です(いわゆるテスト駆動開発)。

  • 主要なロジックや過去に不具合が出た箇所に関して、仕様を調べた
  • 上記を元に単体テストを書くことで既存の振舞いが変わったを検知できるようにした(ソフトウェア万力)*2
    • 現行のソフトの振る舞いを明らかにした
    • 後述のCIと組み合わせることで既存の振舞いが変わった場合にテストがFAILするようにした
  • 新規ソースコードを書く際は失敗するテストコードを書いてからそれをPASSさせるようにした(Red Green Refactor)*3
    • 先にソースコードを書いて、後からテストコードを書くとテストがFAILした場合にデバッグしているという感覚になるのでできるだけ避けたい
    • 逆に先にテストコードを書くと(テストファースト)*4、テストがFAILした場合もテストをPASSさせるためにソースコードを書いているという感覚を維持できる
  • 最低限のCI(Continuous Integration)ツールを設定した
    • eslintの実行(lint, formatterの設定)
      • 可読性の観点からチーム内でソースコードのフォーマットが共通になるよう強制した
      • 実動作上問題がなくてもソースコードにwarningがある状態になっているとバグが入り込み易く・見落とし易くなるのでwarningがない状態を維持した
    • レポジトリへのPushをトリガに単体テスト(リグレッションテスト)を実施した

CIの設定抜粋

image: node:xx.x.xx

stages:
  - lint
  - test

cache:
  key:
    files:
      - package-lock.json
  paths:
    - .npm/

lint:
  before_script:
    - npm ci --cache .npm --prefer-offline
  stage: lint
  script:
    - npx eslint src

test:
  stage: test
  script:
    - npm ci --cache ../.npm --prefer-offline
    - npm run test test
  • Jestを実行しカバレッジを出力した
    • カバレッジは数値そのものよりもどのパスが通ってないか知ることを意識した。通ってないパスにバグが潜んでいる可能性があるため
  • 依存関係が複雑でテストが書きにくいものに対してJestによりmockを設定し、test及びmockフォルダをsrcと分離した(テストダブルによる依存関係の分離)*5
  • 単体テストを書くためにrewire*6__set__を使ってconst(再代入できない変数)を書き換えた
    • constにしているものを無理矢理書き換えるのはコードの複雑さやバグを招くため一般にアンチプラクティスである
    • constにしているものがファイルパスであったため、今回は一種のテストダブルのような扱いで変数の書き換えを行った
    • constを参照するのをやめて、テスト対象のメソッドの引数に参照先を追加するというリファクタリング方法が考えられる
  • nock*7を使ってhttpレスポンスをmockした

テストとソースコードの典型例は以下です。

ソースコード

class Sample {
  constructor() {
    this.client = null;
  }
  method1() {
    const res = {
      isSuccess: false,
      body: "",
    };
    if (this.client === null) {
      res.isSuccess = false;
      return res;
    }
    res = doSomething();
    return res;
  }
  method2(a, b) {
    return a + b;
  }
}

module.exports = new Sample();

テストコード

const target = require("./sample");

describe("Sample Class test", () => {
  //Single function test
  test("func1 shall return when client is null", () => {
    target.__set__({ client: null });
    const result = target.method1();
    expect(result.isSuccess).toBe(false);
  });

  //Parameterized test
  it.each([
    ["method2 shall return sum if A,B are default", 10, 10, 20],
    ["method2 shall return sum if A,B are more than default", 20, 20, 40],
    ["method2 shall return sum if A,B are less than default", 5, 5, 10],
    ["method2 shall return sum if A is more than default and B is less than default", 20, 5, 25],
    ["method2 shall return sum if A is less than default and B is more than default", 5, 20, 25],
  ])("%s", (testcase, A, B, want) => {
    const result = target.method2(A, B);
    expect(result).toBe(want);
  });
});

テストの結果の例は以下です。 Uncovered Lineから通ってないパスが分かると思います(もちろんvisualizeすることも可能です)。 今回の場合はclientがnullでない場合のreturn resです。ここでは書きませんが実際はここのパスを通すテストを追加していきます。

% npm test           

> test
> jest --runInBand --coverage

 PASS  ./sample.test.js
  Sample Class test
    ✓ func1 shall return when param is null (1 ms)
    ✓ method2 shall return sum if paramA,B are default
    ✓ method2 shall return sum if paramA,B are more than default
    ✓ method2 shall return sum if paramA,B are less than default
    ✓ method2 shall return sum if paramA is more than default and paramB is less than default
    ✓ method2 shall return sum if paramA is less than default and paramB is more than default

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |    87.5 |       50 |     100 |    87.5 |                   
 sample.js |    87.5 |       50 |     100 |    87.5 | 15                
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       6 passed, 6 total
Snapshots:   0 total
Time:        0.572 s, estimated 1 s
Ran all test suites.

今後の課題

  • 現行のソフトの振る舞いが明らかになったがエラーチェックなど仕様として足りてない部分がある
  • テストの書き方が洗練されていない
    • テストコードが長く複雑で読みにくくなってしまうことがあった
  • テストの量が増えてくると実行時間がボトルネックになるのが目に見えているので並列化なども追々考えたい

所感

こうして書いてみると、当たり前のことばかりで、技術的に地味ですね。 でも、当たり前のことを当たり前にやることが難しく、 一見地味でもやっていくと効率が上がると思うので続けていこうと思います。

参考文献

jestjs.io www.shoeisha.co.jp shop.ohmsha.co.jp yshibata.blog.ss-blog.jp xunitpatterns.com www.oreilly.co.jp github.com github.com


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proの購入はこちらから akerun.com

*1:Javascripとのテストフレームワーク

*2:「レガシーコード改善ガイド」に> 変更を見つけるためにテストを用意することは、コードを万力で固定するのと同様の効果があるという記載がある

*3:テスト駆動開発」にRed Green Refactorに関する記載があるが、「テスト駆動開発による組み込みプログラミング」で知った

*4:テスト駆動開発」にテストファーストに関する記載があるが、そちらの内容よりは柴田芳樹さんのブログに記載されている内容を意識している

*5:「xUnit Testing Pattern」で提唱された用語だが「テスト駆動開発による組み込みプログラミング」で知った

*6:nodeJSの単体テストにsetter/getterを追加するパッケージ

*7:nodeJSでhttpサーバをmockするライブラリ

組み込み界隈のセキュリティは俺が守る!

はじめに

この記事は Akerun Advent Calendar 2022 - Qiita の13日目の記事です。

組み込みエンジニア(?)の @ishturk です。

「組」と「込」の間の「み」はつける派です。

組み込みのセキュリティ

IoTという言葉が流行り始めて最早数年。組み込み界隈もセキュリティリテラシーが求められるのが風潮になってきました。 たとえば id/passがデフォルトのままのセキュリティカメラとか世の中に溢れてますね。

www.keishicho.metro.tokyo.lg.jp

ですが、インターネットにつながらない組み込み機器でも、セキュリティは非常に重要です。 リッチなOSが搭載されてるIoTデバイスは、もはやサーバーみたいなものなので、インフラ職人さんの領域味が強いです。

この記事では、より組み込みに特化したセキュリティの話を書いていきたいと思います。

よくある構成

超ざっくり組み込みシステムを描くとこんな概念です(雑

Lv.1 言語・ライブラリの脆弱性対策

Applicaitonで使用している言語・ライブラリに脆弱性があった場合、システム全体が驚異に晒されることになります。ただし、組み込みシステムの場合、外から入力するI/Fが限定されている場合が多いので、実際に驚異になるかはシステム次第です。

例えば、キー入力を受け付ける、カメラで画像を読取るなど外部のデータを取り込むようなUIがある場合、脆弱性を悪用するI/Fとなる可能性があります。

脆弱性を含まないライブラリ・バージョンを使用する、外部からのデータをバリデーションし意図しないデータが流入しないようにするなどの対策を講じる必要があります。

Lv.1 バス通信の暗号化

MCUから外部メモリにデータを読み書きする場合、SPIなどの通信を用いることが多いですが、データを平文にしていませんか? 平文で通信すると、通信ラインの電圧をオシロスコープロジックアナライザで観測することでデータを抜くことが非常に容易にできてしまいます。 エンジニアの皆さんはオシロの1台くらい自宅にあると思うので、非常に危険ですね。

近頃のオシロって波形から通信データに変換して出力してくれるんですよ?(最近知った

暗号通信するためには

  • 暗号化ライブラリを使う(HE-CRYPTOなど)
  • MCUに搭載されたHW暗号化を使用する
  • SecureElementを使用する

といった方法があります。 多くの暗号化で鍵の管理が課題になるので、鍵を含めてセキュアに管理できるセキュアエレメントを使用するケースが増えています。またMCUにセキュアな領域が用意されているものも多いです(ARMのTrustZoneなど)

Lv.1 バイナリの難読化

万が一、ソフトウェアバイナリが流出してしまった場合、disassemble することでソースコードを再現することができてしまいます。すなわちソースコードが流出するのと同義です。 これを防ぐために、ソースコードを難解にしておく方法があります。つまり意味不明なロジックの羅列になった状態でソースコード再現されるようにするということです。 たとえば

void unlock_door() {
    do_something();
}

というコードが再現されると、なんとなくドアを開ける処理だというのが推測できます。これを

void nfjuqkk3k6,k() {
   ju89jgggmln();
}

という実装にすると何もわかりませんね? ただ、Wikipedia先生も言っているとおり、難読化はプログラムのリバースエンジニアリングを不可能とするものではなく、時間稼ぎです。実装者やレビュアーの負担も大きいのでメリデメ考えて採用しましょう。

Lv.2 ソフトウェア(バイナリ)ダンプへの対策

多くのMCUは、開発中はメモリを自由に読み書きできるようになっています。開発中はそれで良いのですが、その状態で製品になってしまうと、外部から バイナリの読み出し・改ざんが自由にできてしまいます

対策:多くのMCUが、外部からのアクセスをロックする機能をもっています。ReadProtect、WriteProtectと呼ばれるものです。このロックをかけるとデバッグポートからMCUのメモリにアクセスできない(2度と書き換えできない)状態や、アクセスするとハードウェアでメモリをすべて消去する動作をします。こういった機能がないMCUは趣味専用なので製品には使わない方が良いですね。

ちなみにJTAGなど多くのMCUで使われているポートから読み出すデバイスはaliba○aとかで数百円から買えます

Lv.3 セキュアブート

最近のPCでは割と当たり前になっている機能です。 HWに近いレイヤーで、bootloaderやOS・ドライバーの署名を検証し、不正を検知したら起動しないという仕組みです。 ハードウェアに依存しており、低機能なMCUでは実現できないことも多いです。

Lv.4 自壊プログラム

文字通り、実行したら自分で消してしまうプログラムです。実行後にメモリから消去してしまえば読み取られることも、実行されることもないですね。用途は限られます。

「なお、この記事は自動的に消滅する。健闘を祈る。」(消えません)

Lv.5 物理防御

MCUからの読み出しをブロックしたり暗号化したりしても、攻撃者はあらゆる手段でデータの抜き取りを試みます。あらゆる信号を観測したりMCUをスライスしてアクセスしたり。 絶対に破壊できない筐体で基板を保護してしまえば、こういった攻撃からも守ることができます。シンプルですが、もっとも安全かもしれません。絶対に破壊できない筐体が存在すれば。

セキュリティリスクの考え方

組み込みシステムのセキュリティリスクを計算する際のパラメータの一例です。*1

  • 攻撃に要する時間
  • 攻撃者のスキル(素人で可能〜エキスパートのみ)
  • 必要な知識(公開情報のみ〜クリティカル情報)
  • 攻撃できる機会
  • 装置 (標準品〜オーダーメード)

所要時間や装置の入手性など、簡易であればあるほどリスクは高まります。絶対にゼロにすることはできないですが、要求にあわせて必要なレベルで対策することがものづくりでは必要ですね。

広く世の中で使われる製品であれば、ペネトレーションテストなどで安全性を評価しておくことも重要です。

何より大事なのは、関わる人全員がセキュリティに興味関心を持つことです(どやっ


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com

*1:※引用 安藤 英里子 組込みシステムの定量的なセキュリティリスク評価手法の提案

AndroidアプリのレスポンシブUIを確認するにはVRヘッドセットが最適という夢を見た

この記事は Calendar for Akerun | Advent Calendar 2022 - Qiita の 12 日目の記事です。

こんにちは、Webエンジニアのohioshirt - Qiitaです。
主にAndroidアプリの開発を担当しています。

今回はView-BasedなAndroidアプリの話です。
Composeの話はほぼ出てきません。また別の機会で書きます。

まずはレスポンシブUI・マルチフォームファクタの話

Androidアプリ開発において、今年になってForm Factorsの話がよく見られるようになった印象があります。
Form Factorsの話とは、ざっくりと言えばスマートフォン以外のデバイスにも対応することを指します。
Android OSはスマートフォンだけに搭載されるものではありませんからね。

これについてAndroidデベロッパーサイトを探すと、以下のようなページが見つかります。

また、YouTubeでも多くのセッションが観られますので、ぜひ探してみてください。
www.youtube.com

AkerunアプリでレスポンシブUIに対応してみる

さて、AkerunアプリではレスポンシブUIに対応しているのかというと、
ご覧の通り最適化の余地がありそうです。

Akerun Androidアプリのトップ画面(折りたたみ)

せっかくなので、この場で折りたたみデバイスへの対応を試しましょう。

まずは折りたたみデバイスに対応するとはどういうものか、
こちらのトレーニングコースを参考に見てみます。
https://developer.android.com/codelabs/basic-android-kotlin-training-adaptive-layouts
https://github.com/google-developer-training/basic-android-kotlin-training-sports

このアプリでは、2画面への対応としてリスト / 詳細パターンを採用しています。
左の画面にリスト、右の画面にその詳細を表示するレイアウトはよく見るパターンですね。
https://developer.android.com/codelabs/basic-android-kotlin-training-adaptive-layouts#3
iOSアプリ開発でもUISplitViewControllerの名前で見たことがあるかもしれません。
https://developer.apple.com/documentation/uikit/uisplitviewcontroller

Akerunアプリでもリストを表示する画面が存在するので、導入としてちょうどよさそうです。
このAkerunアプリのリストはドロワーのような表示ですが、
先ほどのサンプルに合わせてレイアウトを変更します。

Androidでドロワーを実現する標準的なコンポーネントは以下、
https://developer.android.com/jetpack/androidx/releases/drawerlayout
レーニングコースではSlidingpanelayoutを使用しています。
https://developer.android.com/jetpack/androidx/releases/slidingpanelayout
レイアウトの詳しいところは省略しますが、上記を参考にするとこのような構成になります。
一般的には左側にリストを置きますが、今回は既存の画面構成をそのまま踏襲するということでご容赦ください。

<Slidingpanelayout>
    <ドア(レスポンシブなwidth) />
    <ドアリスト />
</Slidingpanelayout>

それでは表示を確認しましょう。
折りたたみに対応したスマートフォンの実機を使うには金銭面でのハードルが高いですが、
Android Studio Electric Eelからはリサイズ可能なエミュレーターが使えます。
https://developer.android.com/studio/preview/features#resizable-emulator

折りたたみデバイスの表示
タブレットサイズでの表示
どうでしょう、それらしく見えませんか?
※個人の感想です。操作性など全然考慮できていません。

ようやくVRヘッドセットの出番

このようにスマートフォン、折りたたみ、タブレットと3種類のレイアウトを確認することができました。
さらに多様なサイズに対応できているか確認したくなるかもしれません。
そんな時におすすめなのが、Meta QuestやPico 4などのVRヘッドセットです。
AndroidベースのOSを搭載するVRヘッドセットでは、Androidアプリを動作させることができます。
Androidスマートフォンと同様に開発者モードを有効にしてUSBデバッグしましょう。
(apkファイルをインストールできるようになりますが、Androidスマートフォンと同様にリスクが生じます)
このようにウィンドウサイズも自由に変更できます。

動かしているサンプルアプリはJetNews。

私がVRヘッドセットを使うときは大抵Immersedでバーチャル作業空間に引きこもっていますが、
こうした使い道もあるので、積極的に活用してみようと思います。

Immersedでの作業風景。黄色の枠線で囲まれたウィンドウが27インチディスプレイのサイズ相当です。これで右のウィンドウの大きさがわかるはず

VRヘッドセットの出番はない

1つ言い忘れましたが、 AVD(エミュレータ)の中には、デスクトップアプリの動作を確認するためのものもあります。
つまり、VRヘッドセットでなくても柔軟なウィンドウサイズ確認ができるのです。

VRヘッドセットを社内に広めるネタを探して行き着いたのが今回の話でしたが、
結局VRヘッドセットは必須ではなかったというオチになってしまいました。
次のネタ(バーチャル空間での会議?)を用意できたらまた投稿しようと思います。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com

入社してから取り組んだ、細かい業務改善

この記事は Akerun Advent Calendar 2022 - Qiita の11日目の記事です。

今年の6月より入社しました、Web開発グループの小森と申します。 主にiOSアプリケーションの開発を担当しています。

この記事では、タイトルの通り、入社してから取り組んだ細かい改善について書きました。(SwiftUI関連の記事を書く予定でしたが、入社したてということもあり、SwiftUIについてはまた別の機会でかけたらと思います。)

プログラミングをして改善を行うようなハードルの高いものではなく、単純なツールの使い方や方針を少し見直す、取り組みやすそうな改善になるので、是非お立ち寄りいただければ幸いです。

(1)Slackのチャンネルの分割

業務のコミュニケーションツールとしてSlackを活用していますが、普段iOSチームでメインでやり取りをしているチャンネルに、SlackのGithubチャンネル連携によるの自動メッセージ(主にPRの作成/PRのコメントなど)も流れるような状態が続いていました。

PRの作成頻度によってはチャンネルで共有されたPR以外の内容を見落としやすそうな懸念があり、チャンネルを分割(新たにチャンネルを作り、そのチャンネルで必要な会話をするように移行)しました。

具体的に取り組んだこと

チャンネルを分割すること自体は特段難しくないですが、普段のチームのコミュニケーションのルールを大幅に変えることになるので、少々神経質ではありますが分割する上で下記のように行いました。

  • 2つのチャンネルにどういった会話が期待されそうか方針を決める。その際検討していた方針は下記です。
    • PR(Github関連のデータ)を流すチャンネルを既存のチャンネルにとどめ、それ以外の会話を別のチャンネルにする
    • PR(Github関連のデータ)を流すチャンネルを既存チャンネルでない、新規作成したチャンネルにし、それ以外の会話を既存のチャンネルにする
  • チャンネル名を決める
  • 誰を招待するかを確認する
  • 招待する方に、上記をテキストベースで共有する
  • 実行

結果

チャンネルを分割したことで、チームメンバーからも使い勝手良さそうな前向きな意見が伺えたのでよかったです。具体的には下記のような効果を感じました。

  • PR以外の普段の会話が埋もれそうな状況は発生しなくなった
  • 受け取ったメンションを追いやすい
  • 会話を後からたどりやすい

上記なpositiveな効果を感じた一方で、導入時にチャンネル名に起因した運用上の認識齟齬があったため、チャンネル名が適切かどうか(目的にあった理解しやすい名前かどうか)の確認はもう少し丁寧にやれたらと思います。

(2)プルリクエストのテンプレートを作成する

私が普段携わるGithubリポジトリには、多い時で5人のエンジニアが開発するという状況があり、プルリクエストのテンプレートがない状態がありました。PR作成者は各々で似たり寄ったりな独自のテンプレートを持っており、私自身も毎度コピペし、手間でした。

それに加えて、アプリの表示確認にPRに添付する画像サイズが、各人が出力したその大きさのままプルリクエストに添付される状況もみられ、レビュアーにとっては少々負担になりそうに見受けられました。

PRのテンプレートを作ることで、上記の問題の解消を試みました。

具体的に取り組んだこと

こちらに記載の通り、pull_request_template.md と言う名前のテンプレートを、対象リポジトリ.github 配下に作成します。

## 概要

### 詳細

<!-- 
概要で伝えきれない内容記載
-->

## リンク

<!-- 
資料
-->

## レイアウト

|  改善前 ❌  |  改善後 ⭕️ |
| ---- | ---- |
|  <img src="" width="240">  |  <img src="" width="240"> |

### 動作

## TODO

レビュアーが効率よくレビューできるように、下記の項目を追加しました。自明な箇所は省きます

  • リンク : 修正の根拠 / 妥当性を理解する補足資料のリンク
  • レイアウト : iOSアプリケーションの表示を変更した時の、改善前改善後のキャプチャ(改善前のキャプチャも添えることでレビュアーとしては変更箇所が認識しやすくなるので、改善前のキャプチャを項目として追加しました)
  • 動画 : 挙動の変化のある場合の動画。レビューする際にローカルで確認する手間を省く
  • TODO : そのPR自体に含まれても良さそうな修正だが、含めなかったもの

結果

こちらも基本的にはpositiveな効果が得られたように思います。

PR作成者視点

  • 毎回ローカルから自分のテンプレートをコピペする必要がなくなった
  • 項目の妥当性についてはそこまでフォーカスしなくて良く、項目を入力することに注力すればよくなった

PRレビュアー視点

  • 対応者によって内容の文脈を切り替えなくて済む
  • 画像サイズが大きなPRに直面することもなくなった

PRの画像については各人のローカルで毎度スクショを準備していただいているため、BitriseなどのCIツールを使って自動化できないのか、こちらの調査もしていきたいです。

(3)KPTのTryテンプレートの作成

私が所属するチームでは振り返りの方法として、KPTという振り返りのフレームワークをベースにした振り返りをしています。ツールはTrelloを使用して、オンラインで完結します。 巷で行われているKPTと大きく大差ないと思いますが、下記のようなフローで行なっています。

  1. 所定の時間で、Keep / Problemを記載
  2. Keep / Problem を各人で発表
  3. 2の内容をもとに必要に応じてTryを作成する
  4. 次の週のKPTでTryを確認

3のTryを作成する中で、Tryしたいことだけ記載されているカードが多く、どういった経緯でTryが記載されたのか、どうすればそのTryが達成することになるのか、後から見づらくなっている状況がありました。

その結果、先週発生したTryがどういう目的で作成されたものか分かりづらくなっており、4のタイミングで、このTryが何かを確認する会話が発生することが何度かありました。 効率よくイテレーションを回すには、もう少しTryに関する情報を記録して4における時間を減らせるように思うので、ここでもテンプレートに頼りました。

具体的に取り組んだこと

下記のようなTryのテンプレートを作成しました。

## Tryしたいこと

## モチベーション

## 具体的な次のアクション

項目は下記のようなものです。

  • Tryしたいこと : 項目名の通り、やりたいことを簡潔にかく
  • モチベーション : Tryしたい動機を書く。現状の説明なども必要に応じて記載
  • 具体的な次のアクション : そのTryが達成するための完了アクション。Tryしたいことよりも詳細に踏み込んだ内容を記載。

結果

こちらはまだ導入したばかりなのでそこまで大きな効果を確認できてない状況はありますが、Tryに関する情報が増えたので、以前よりも4におけるTryを捌く時間が早くなりそうな予感がしています。まだ運用上チームに浸透してないところもあり、Tryで書くべき内容として多くないかの検討など、これから見ていきたいと思います。

感想

上記三つほど小さな改善に取り組み、特に大袈裟なことをせずとも改善できることは多分にあるなと感じました。入社時点では前の現場との違いを捉えやすくなっていることもあり、改善しても良さそうな部分に気付きやすいかもしれませんが、システムやツール等に長期で慣れすぎると問題点に気づきにくくなることもあると思います。

そうならないためにも、常日頃から問題意識や目的に合った使い方がなされているかなど、考える姿勢を持ちたいです。

お読みいただきありがとうございました!


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com