組み込みミドルウェアエンジニアの仕事例紹介と、Web系に対するギャップ

## はじめに

私は今まで主に組み込みのミドルウェア層での業務に携わっており、その中でHTTPサーバー周りのことも色々触っていました。
ただ、そこでの感覚と、QiitaやTwitter等のWeb系の方が話されているHTTPサーバー周りのこととギャップがあったんですよね。
4月からWeb系の現場に入ってみてギャップがなんとなくはっきりしてきたので、組み込みミドルウェアとはって話とともに記録しておこうと思いました。
後は組み込みって言ってもあまり伝わらないので、言語化しときたいなってのもあります。

### 本記事の想定読者

- ハードバリバリとは異なる組み込みエンジニアの生態に興味がある人
    - 補足: ×ハードに関わらない組み込み業界がある　〇組み込み業界の中の担当として、ハードに関わらない領域があるである。です
- Web系以外でHTTPプロトコルを触る層に興味がある人
- 組み込みミドルウェアエンジニアの生態に関する例が欲しい人 (私)

## 自己紹介：組み込みミドルウェアってなに？

### 組み込みってなに？
組み込みとはなにか？Wikipediaより

> 組み込みシステム（くみこみシステム、英: embedded system）とは、特定の機能を実現するために家電製品や機械等に組み込まれるコンピュータシステムのこと。

家電等の装置内で動くシステムのことを言います。業界の話でいうと例えばTwitterで見かけた雁人さん[@karito_tate](https://twitter.com/karito_tate)の記事が丁寧でわかりやすかったです。
[組み込みって何それ？美味しいの？](https://tatekarito.hatenablog.com/entry/2019/03/27/235939)、[組み込み業界ってどんな業界？](https://tatekarito.hatenablog.com/entry/2019/04/03/211653)

### 組み込みはみんなハードゴリゴリなの？⇒そういうわけでもない

組み込みといえば、皆さん「ハードウェアに精通しているんだな」ってイメージを持たれているかもしれませんが、実はそうとも限らないです。
~~例えば適当にググって見つけた[日本OSS推進フォーラム](http://ossforum.jp/node/1062)というサイトの図II-25-1. 携帯電話では組み込み製品はこんなソフトウェア構成になっていました。~~　非公開になってたので、自作
例えばこんな感じにレイヤーが分かれていて、それらが全て装置に乗って動作する為全て「組み込み」のカテゴリになります。

<img width="700" alt="layer.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252277/568093c6-1dec-0e1f-d0b3-a24b1b3e3d68.png">

上記例のように、組み込み製品のシステムには階層があり、ユーザーが触る**アプリケーション**と、ハードゴリゴリのデバイスドライバ/OSやそれらを扱う**ハードウェア制御部**、そしてその仲介役となる**ミドルウェア**が存在します。
(図はデバイスドライバ、OSで分かれていますが、後の話がしにくいのでハードウェア制御部でまとめちゃいます。)

|階層|解説|用途の例|
|:---|:---|:---|
|アプリケーション|ユーザーが触るやつ|Web制御画面、常駐アプリケーション|
|**ミドルウェア**|ハードウェア制御部を利用してシステム制御する部分。ユーザーが触る一歩手前になることが多いかも|HTTPサーバー本体、動画配信みたいな制御をするところ|
|ハードウェア制御部|ハードウェアをシステムで動かす為に動作するもの|無線LAN、ethernetを認識するとか。ネットワークならL2周り|

IoTをイメージすると分かりやすいかもしれませんね。装置から情報を吸い上げたり「冷房ON!」みたいな指示が出せたりする装置。そこでいうと、

- ユーザー操作を受け付ける部分→アプリケーション
- 裏で動くHTTPリクエストや通信プロトコルを捌く→ミドルウェア
- 最終的な「冷房ON!」を実行する本懐→ハードウェア制御部

みたいな感じ。このミドルウェアやアプリケーションの担当者の場合、電気制御やマイコンは触らないし、ドライバ周りを見ることも稀です(無いとは言わない)。
ミドルウェアエンジニアの場合は**Linux上で動作するデーモン(常駐ソフトウェア)の開発エンジニア**って感覚が近いかも。

組み込みらしい縛りとしては、大抵PCよりも小さな基盤で動かすため、**メモリ・ディスクの容量やCPU性能が制限されている**という縛りがあります。
(といっても自分の知っている世界では、Linux上でベース開発や単体テスト⇒本番環境は実機でARM Linuxなので、必要最小限なLinux OSで動作しているという感覚です。)

### 組み込みミドルウェアエンジニアって例えばどんなことをやるの？

私を実例にして解説します。あくまで一例なので全体がこうってわけでもないのであしからず。
簡単に言うと、以下のような機能実現の仕事をしていました。

- 起動時に自動で色々設定
- HTTP経由で設定変更
- リアルタイム制御の操作

細かい話だとHTTPリクエストを捌いたり、設定値や証明書を管理してみたりと色々。具体例行きます。

#### 例1. 無線ルーター研究開発

2009年から6年ほど、無線系のデバイスを積んだ装置の開発をやっていました。これは製品開発ではなく、とある研究者の実証実験を請け負うみたいなスタイルのお仕事。
[これ](https://qiita.com/developer-kikikaikai/items/5026d391ae2fb9427d18)に似た感じのソフトウェア構成でした。

![構成イメージ](https://camo.qiitausercontent.com/a6bee0e53ba64a1ac66b6b7aa1ccab62f1f85eac/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235323237372f63633433613233322d393233372d393437642d666236662d3537353135366366363638622e706e67)

上記は自分で一から設計実装したもので、実際に作ったものはもっと複雑で多機能・高性能だったはず。
Wi-Fiメッシュを乗せてみたり(最近ヨドバシに並んでてビビった)、WANに色んなデータ通信カードが出てきたり。色々な用途で流用・拡張してました。

ここで私が対応した作業を一部抜粋するとこんな感じでした。

- 起動時設定
    - スマホでいうと最初にWi-Fiを探して、見つからなければ4Gで通信がはじまるみたいな制御をする。設定するのは無線LANのessidとかをイメージしてもらえると。
    - 認識した各通信デバイスに対してIPを振ってルーティング設定。
- HTTP経由で設定変更
    - WebページからのHTTPリクエスト契機での設定変更
- リアルタイム操作
    - Webページ/サーバーからのHTTPリクエスト契機での通信切り替え

デバイスドライバを介した通信デバイス制御はwpa_supplicant/hostapdのようなOSSを使ったり、ハードウェア担当チームとのインターフェースをライブラリAPIとして定義・実装してもらったり。
例えば上記構成で説明するなら、Lan_routerが丸々ミドルウェアエンジニアの担当で、pluginにあたる部分をライブラリにしてハードウェア担当者 or OSSで作る感じですかね。

#### 例2. 監視カメラ

上記の次は監視カメラ開発を4年ほど。監視カメラって、映像の配信、カメラの設定(ウイーンって動かして向きを変えたり)、その他もろもろ沢山の機能をHTTP通信で実現してるんですよね。
中身のイメージはこんな感じ。ハードウェア制御は専任がいて、私らはその人達とioctl or socketメッセージ通信でお話しするだけでした。

<img width="800" alt="無題.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252277/3432e9e4-ae53-de6e-090d-f709d4b83891.png">

こちらで私が対応した作業を一部抜粋するとこんな感じでした。

- 起動時設定
    - 自動起動で色々設定できるよう、起動設定・シーケンスを制御する
- HTTP経由で設定変更
    - 撮影設定とか、ユーザーやHTTPSの設定とか、色々
- リアルタイム操作
    - ウイーンって動かしたり、映像配信したり(ブラウザ上で映像が見えます！再生プレイヤーでリアルタイムストリーミング配信も出来ます！)

また、OSSを沢山使っていたのでバージョン管理が大変でした。脆弱性ェ

## Web系と呼ばれるお仕事とのギャップ

例に挙げたように、組み込みシステムではHTTPサーバーで何かしたり、自分で勝手にハードウェアをウイーンと動かしたりします。
このHTTPサーバーの部分、Web系も対して変わらないと思ってたんですが結構ギャップが。

というわけで、ここからはそのギャップを感じた点について話して行きたいと思います。
Web系では普通以下のようなパターンが多いそうですが、組み込みの世界ではどうでしょう？

- HTTPの制御はフレームワークを利用する。
- HTTPの処理でマルチスレッドを使うことは滅多にない
- 操作対象は最終的にDB

### HTTPの制御はフレームワークを利用する？⇒OSS+最小限のアプリケーションってパターンもある

監視カメラの例にも出しましたが、自分が組み込み現場で触ったことのあるHTTPサーバーの構成は以下のような感じでした。

- OSSのHTTPサーバー × プラグインでCベースの自作処理を追加
- 画面は素のHTML/JavaScript
- URLハンドリングは設定ファイルとプラグイン
- 速度がいらない処理はcgiやスクリプト言語の組み込み機能で対処
    - shellで頑張ったり、LuaやmRubyを使ったりしてました。

なんでこうなっていたかは定かではないですが、多分最小限のリソースで速度も品質(脆弱性に強いって意味)も上げつつってなるとこんな構成になるのかなと思います。
(各社製品のHTTPヘッダを覗いても、同様にapacheやnginx、lighttpdを使っていたと記憶しています。)

技術的な設計アプローチだったり、開発のスピード感だったり、結構違うな～って感じます。

### HTTPの処理でマルチスレッドを使うことは滅多にない⇒ミドルウェアは普通に使う

ミドルウェアはハードウェアを制御する部分とやり取りするんですが、そういったハードに関わる部分って処理の稼働時間に厳しいんですよね。なので、一旦処理受付で終了⇒結果を後で通知みたいなパターンが結構あります。
<img width="400" alt="multi_image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252277/680c55f3-d1c7-17b9-6115-2a7eaa5dc986.png">

Wi-Fiがイメージしやすいですかね。通信悪い所で接続！ってやると、画面が固まらずに接続中マークに変わる⇒ちょっと経って接続マークに変わるみたいな
同じようにHTTPを受けた後の処理を、HTTPサーバーがブロッキングされないようスレッドで実施させるなんてこともあります。
(やりたいことが終わるまで応答を返さない作りをブロッキング、一旦応答を返して後で結果を通知する作りをノンブロッキングと呼びます。場所によっては同期/非同期って言い方をしたり。)

<img width="800" alt="HTTP request thread.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252277/f47aabe5-ca5b-b4f7-7409-e2b2e3785435.png">

こんなケースでマルチスレッド・マルチプロセスを利用するのはよくあります。
また、実現方法もメッセージ送信したりコールバックだったりと色々あるので、「これはブロッキング？ノンブロッキング？」、「ノンブロッキングの場合はどうやってやり取りするの？」辺りが設計時のポイントになったりします。

#### 結果を後で通知って実際どうやるの？

せっかくなので書いときます。まずイメージするのがメッセージ通信だと思います。矢印がそのままメッセージキュー等を利用したメッセージ送受信に変わる。
[Linuxのプロセス間通信](https://qiita.com/MoriokaReimen/items/5c4256ef620499a88bb3#%E3%82%BD%E3%82%B1%E3%83%83%E3%83%88%E9%80%9A%E4%BF%A1)等サンプルを参照ください。

もう一つはコールバックを利用する方法。
例えばこんな感じです。`request_action`ってのがなんか要求する為のAPIで、引数の関数ポインタが結果通知代わりになります。

```C:callback_sample.c
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

//要求APIの引数で渡す関数(コールバック)の型定義。
typedef void (*notify_event_cb)(const char *result);
//要求用API。引数のeventが要求処理後に呼ばれる
static void request_action(notify_event_cb event);

/****要求を受ける側の処理****/
//メイン処理
static void * actor_main(void * arg) {
        notify_event_cb event = (notify_event_cb) arg;
        sleep(1);
        //処理が終わった想定。関数をコール
        event("Result OK!!");
        return NULL;
}

//要求APIでは実処理をせずに関数だけ渡してあげる。処理が終わったら関数を呼ぶ
static void request_action(notify_event_cb event) {
        pthread_t pid;
        pthread_create(&pid, NULL, actor_main, event);
        pthread_detach(pid);
}

/****応答で呼ばれるコールバックの中身****/
static void notify_event(const char *result) {
        printf("Receive result![%s]\n", result);
}

int main() {
        //コールバック形式にしたので、request_actionはすぐ終了して後でnotify_eventが呼ばれる。
        request_action(notify_event);
        printf("API request_action is called! Let's wait result!\n");
        //sleep中に要求を受ける側が処理を終えてコールバックを呼んでくる
        sleep(3);
        printf("Exit!\n");
        return 0;
}
```

実行結果はこんな感じ。

```
$ ./a.out
API request_action is called! Let's wait result!
Receive result![Result OK!!]
Exit!
```

### 操作対象は最終的にDB⇒ハードウェア操作だったり、設定保存もDB使ってなかったり

例を見返してみると、例1での操作対象は通信デバイスだったり、例2もウイーンって動くところだったりするので、操作対象はハードウェアだったりします。
また、設定をどこで持つかはハードの仕様に依存していて、ものによってはハードウェア(の制御装置)で覚えることも。
なので、HTTPリクエストに対する操作対象はDB以外にも色々あったりします。

## 最後に

他ジャンルのエンジニアが経験したことって、見てて面白いですよね。どれがいいとか悪いとかは私にはわかりませんが、色々な人の特徴や文化を知ると、それだけで得られるものがある気がします。
今感じてるWeb系とのギャップも、「はえ～、こんな色々違うんだな。色々学ばないとな」といった刺激(と焦り)になっています。
最近の製品に組み込まれたシステムって本当に多機能なので、組み込みといっても色んなことがあるんだな～というのがこの記事で伝わってくれたら嬉しいですね。

また、私が書いた内容もあくまで私の経験内の話ですので、これが組み込みミドルウェアの全容だ！みたいな話ではないのでご了承ください。

## 参考

[組み込みって何それ？美味しいの？](https://tatekarito.hatenablog.com/entry/2019/03/27/235939)
[組み込み業界ってどんな業界？](https://tatekarito.hatenablog.com/entry/2019/04/03/211653)
[日本OSS推進フォーラム II-25-1. 組み込みアプリケーション開発事例](http://ossforum.jp/node/1062)

---------------------------------

### おまけ

参考までに例で書いた要件の担当職務で得たスキルセットはこんな感じになりました。

例1:

|区分|内容|
|:---|:---|
|OS|Linux (arm/Fedora/Ubuntu etc)|
|言語|C/C++, ShellScript|
|構成管理|svn|
|その他|net-snmp, wpa_supplicant, hostapd等のOSS利用|

例2:

|区分|内容|備考|
|:---|:---|:---|
|OS|Linux (arm)|実機に寄らない処理はCent OS上で開発|
|言語|C, Lua, Ruby, Python, Shell Script|Rubyは主にPCシミュレーターと一部mRuby, Pythonはテストツールで使用|
|構成管理|Git|ローカルに立てたgitlabリポジトリで管理。サーバー管理者|
|その他|lighttpd(HTTPサーバー), OpenSSL, SQLite, RTP, FFmpeg等のOSSを利用|HTTPサーバー差し替え担当したり、FFmpeg出力のJPEG/H.264ヘッダー解析したり色々やりました。|

どっちも基本設計～評価。たまに要件定義。チームリーダー、プロジェクトリーダーもやってました。