出力を入力へ

プログラミングに関する自分が考えた事を中心にまとめます

EC2インスタンスIDを取得するec2idをリリースした

AWS EC2インスタンスのインスタンスIDをNameタグから逆引きするCLIツールec2idを作ってリリースした。

github.com

インスタンスIDを取得したい

AWS EC2インスタンスを一意に識別する情報はインスタンスIDであり、AWS SSMセッションズマネージャーでログインするときなどでインスタンスIDを指定する必要がある。 例えば、aws cliを用いてSSMセッションズマネージャーで接続するには以下の通り。

$ aws ssm start-session --target <instance-id>

docs.aws.amazon.com

このようにインスタンスIDを指定する上で、インスタンスIDを取得する必要がある。 インスタンスIDはユーザがEC2に割り当てることはできず、EC2インスタンスを構築する度にランダムに決定する。このため、EC2インスタンスを頻繁に再構築している場合、事前に値を記録する運用も難しい。 インスタンスIDを利用する直前に動的に取得する仕組みが必要である。

インスタンスIDの取得方法

マネージメントコンソールから取得する

一番直感的なのはWebのマネージメントコンソールから取得する方法である。

マネージメントコンソール画面からインスタンスIDを参照する

一方で、EC2インスタンスIDを取得するために、わざわざマネージメントコンソール画面を開きたくない。 また、大量のEC2インスタンスIDが稼動している場合に目当てのインスタンスを探すのは手間だし間違いが生じやすい。 より簡単にインスタンスIDを取得する方法が必要である。

aws cliを利用する

aws cliでSSM接続するためにインスタンスIDが必要なのであれば、同じくaws cliでインスタンスIDを取得できれば話は早い。 当然aws cliにはそのためのサブコマンドが提供されており、describe-instancesを利用することでインスタンス情報一覧を取得できる。

awscli.amazonaws.com

一方で、この方法ではquery/filterオプションを覚えるのが面倒という問題がある。 EC2インスタンスが1台しか存在していないのであれば問題ないが、複数インスタンスが稼動している中で目的のインスタンスを取得するには、queryおよびfilterオプションを指定する必要がある。 query/filterで、インスタンス名sampleのインスタンスIDおよびその起動時刻を取得するコマンドが以下の通り(以下の例では該当するインスタンスが2台ある場合)。

$ aws ec2 describe-instances --filters Name=instance-state-name,Values=running Name=tag:Name,Values=sample --query 'Reservations[*].Instances[*].[LaunchTime, InstanceId]'
[
    [
        [
            "2022-12-31T10:02:33+00:00",
            "i-0691a69ff0914bae1"
        ]
    ],
    [
        [
            "2022-12-31T11:24:57+00:00",
            "i-0acd9f178c934caea"
        ]
    ]
]

このように、これだけでもquery/filterはそれなりに複雑で覚えておける気がしない。 特に同名インスタンスがある場合には出力結果を人の目でパースする(いわゆる目grepする)か、追加のsortフィルタ等を加えて適切なインスタンスを選ぶ必要がある。

ec2id

こういった課題を解決するためのcliツールとしてec2idを開発・リリースした。

github.com

専用CLIの実装

やりたい事はインスタンス名からインスタンスIDを取得すること。なのでその用途に特化したCLIがあればよい。 無駄なオプションを実装せず単目的に利用することを想定することで、シンプルなツールを実現した。

これを利用することで簡単にインスタンスIDを取得できる。

# 引数を指定しなければ全インスタンスから最後に起動したインスタンスのIDを取得する
$ ec2id
i-0691a69ff0914bae1

# 引数を指定すればそのインスタンス名の中から最後に起動したインスタンスのIDを取得する
$ ec2id sample
i-0acd9f178c934caea

go言語による実装

利用時に依存パッケージの問題を発生させたくないのでシングルバイナリで利用できることが望ましい。 Linux(Ubuntu) / Intel mac / m1 macで利用することは見えているので、マルチOSサポートが容易が言語にしたい。 そういった事を考えるとgo言語が適切だと判断した。

わざわざgo言語で実装しなくてもシェルスクリプトなどでも実装可能かもしれないが、フィルタやクエリが複雑になりメンテが大変になりそうだった。 また、別のツール用にgo言語のCLIを作りたいとも考えていたので、go言語のナレッジ蓄積をしたかった。 go言語の技術検証用にシンプルな仕様のツールがあると都合が良く、ec2idはこの条件に合っていた。

作ってみて

検証時に思った通り、テストまわりが難しく感じた。 AWS APIをモックにする必要があり、インタフェースやモックコードの生成などもからむので、多少複雑にはなった。 これはgo言語に慣れれば解決するのか、今のところ感触はあまりよろしくない。

シングルバイナリやマルチOSサポートが容易なのは大きなメリットと感じる。 このあたりリリースまわりが楽なのは嬉しい。

2022年のふりかえりと2023年の抱負

2022年のふりかえり

目標に対してはあまり上手くいった年ではなかった。

できたこと

テスト

ものすごく上手くいったわけではないが、いろいろ取り組むことができた。 IaCに対しては静的解析やPolicy as Codeに、ソフトウェアに対しては特にgo言語を中心に、システムとしてはE2Eテストを試すことができた。 1つ1つはまだ入門レベルではあるが、やっとひと通りそろってきた。

健康増進

技術まわりとは関係ないけれど、健康増進に向けて運動習慣を身に付けることができた。 テニスは再開(これは正確には2021年だが)して1年以上継続することができた。 それ以上に、zwiftを始めてかなりのめり込むことができた。最初は20分がやっとだったのに、今では60分を倍近いパワーで軽く走れるようになった。このおかげで減量にもなったし体力がついた。 リモートワークで運動機会がなく危機的だった状況は脱することができたので、これは2023年も継続したい。むしろやり過ぎに注意した方がよいくらいか。

できなかったこと

個人成果の追求

これは良い面と悪い面でできなかった。

良い面とは結局組織をリードする取り組みは止めなかったということ。 これは社内のエンジニア組織およびインフラチームの拡大を通して、自分がEMおよびリードエンジニアとしての動く必要があった。また、より良いプロダクト開発のためにも、あえて組織まわりの課題を無視する・手を出さないという選択肢は自分には取れなかった。 ある程度割り切ったところもあるが、当初考えていたよりも組織寄りの行動が多かったかなと思う。

悪い面は単に個人開発に投入する時間が減ってしまったこと。 業務においても他の人の開発をフォローする時間は多かったし、プライベートでも技術以外に時間を使うことが多かった。1番の課題は個人開発のモチベーションが夏頃にゼロになってしまったこと。結局秋には自然と回復したものの、個人開発をここまで止めたことがなかったので軽い危機感があったがそれでもモチベーションが出ない状況だった。 興味に合わせて取り組む技術を選び過ぎて継続も完結もできなかったし、結局開発を楽しめたかというと疑問。このあたり、自分がどう開発と向き合いたいのか考えるか、それとも何も考えずに興味のままに取り組むか選択する必要がある。

成果のアウトプット

アウトプットもあまり満足できるものではない。

  • 登壇: 0件
  • 個人ブログ: 5件
  • Qiita+Zenn:10件
  • 会社ブログ:1件

登壇は増やしていくつもりが、結局機会を得ることができなかった。 ブログ投稿数は2022年と同水準で、これも増やしていくつもりがまったく増えなかった。実は下書きはいくつかあり、これを公開までもっていけなかったことが大きい。 勢いで書き切ること、計画的に書くことが必要。

xR技術

2021年始めに少し手を出しただけで、ほとんど取り組めなかった。特に動画まわりは何もできなかった。 会社ではこのあたりの技術が着実に前に進んでいて面白いフェーズにあり、自分はインフラエンジニアとして1歩引いた位置で取り組めずにいる。このもったいない状況はどうにか解消したい。

低レイヤ技術

低レイヤもほとんど取り組めなかった。 ECS活用は拡大しているものの、k8sはまったく触れられておらず、GPUやLinux Kernel/ディストリビューションもほとんど触れていない。多少トラブル対応しただけか。

このあたり、もったいないので手を出したい気持はある一方で、今自分がやりたい領域ではないとも感じている。必要に迫られれば対応すると思うので、どうにか機会を捻出したいところ。

2023年の抱負

2023年は好奇心と実用性をテーマにする。

2022年は目標は意識しつつも、興味を持ったものに手を出すことはできた。しかし、興味だけでは開発を継続することはできなかったし、当初定めたゴールまで辿りつくことはできなかった。 2023年は興味に応じていろんな技術に手を出すことは継続しつつも、それを自分の役に立つこと・実用性を考えて継続することを意識する。

実用性を意識した個人開発

テストもxRも低レイヤも、興味だけでは成果につながらなかったしアウトプットにたどり着けなかった。 これではどこまで開発を進めても知的好奇心を満たすことしかなかったし、ある程度取り組むと満足して手が止まってしまう。

スタートは興味でよいので、その後は実用性を意識して開発を継続するようにする。 もちろん業務やOSSコミュニティに価値を提供できればそれが一番だが、少なくとも自分の役に立つ開発になることを意識したい。

細かなアウトプット

2022年は変にアウトプットに拘ってしまった。新規性が、正確性が、充実度が、と考えて結局記事を公開できないことも多かった。 2023年はもっと細かくアウトプットする。他の人の二番煎じになって、箇条書きでも、検証不足な点があってもよい。アウトプットしない状況より小さくアウトプットすることを意識していく。

社外登壇となると難しいところだが、やはり他人とネタ被りを恐れるくらいなら考えずにCfP応募できるようにしたい。LTならそれこそ考え過ぎないでよいはず。 どちらかというと日頃のアウトプットを積み重ねて社外登壇にもっていけるようにしたい。

腕力で実装する

個人開発もアウトプットも、当初のゴールまでやり切れずに止まったことが大きな課題。 開発やアウトプットに着手したとき、始めた勢いである程度の成果にたどり着けるかがポイントだと感じており、それができればある程度継続もできる。

これは書籍「事業をエンジニアリングする技術者たち」で技術的負債の返却には腕力が必要という言葉で表現されており、これが技術的負債の返却以外にも通用すると感じた。 かっとなって開発を始めた・ブログ記事を書き始めたときに、ある程度の形になるまでもっていけるかは腕力が重要。この腕力を鍛えていきたいし、自分の腕力では解決できない課題はきちんと分割して取り組みたい。

データと仲良くなる

2023年は今まで以上にデータの扱いが重要になりそう。 いわゆるRDBだけでなくNoSQLだったり全文検索だったり、ログだったり画像だったり。

データストアの使い分けや取り扱いを上手くできるようになりたいし、システムをきちんと運用できるようになりたい。 また、システムだけ理解してデータの扱いを別のエンジニアにまかせるだけでなく、自分でもデータ操作できるようになりたい。

GoでSDK呼び出しをモックできるコードを書く

AWS SDK for GoなどのSDKを利用する場合のユニットテストの書き方およびプロダクトコードの実装方法が難しい。 AWS公式には Unit Testing with the AWS SDK for Go V2 にて解説があり、モックで差し替えられるようにAPIのインタフェースを利用してテストで差し替えることができるように推奨している。 一方で、このケースにおいてプロダクトコード側をどのように実装すればよいかわからず、またテストも複雑でどのようにテストを増やせばよいかわからなかった。

いろいろと検討して自分の中である程度納得できたのでそのまとめ。とはいえわからないことも沢山あるのでまだまだ検証が必要。 ベースとなるコードは Unit Testing with the AWS SDK for Go V2 から、検討結果のコードはこちらのリポジトリにある。

プロダクトコードの実装

インタフェースの暗黙的な実装

一番最小限の方法。 Goのインタフェースは暗黙的に実装される (implemented implicitly)ので、オブジェクトを代入する変数の型として S3GetObjectAPI 型を宣言すればよい。 これにより変数 apiS3GetObjectAPI 型 (実態は s3.Client)になり、GetObject 関数を呼び出すことができる。また、テスト時にはAWSドキュメント記載の通りモックで差し替えればよい。

func CallGetObjectFromS3Direct() {
    var bucket = "sample-bucket"
    var key = "sample-object-key"

    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        log.Fatal(err)
    }
    var api S3GetObjectAPI = s3.NewFromConfig(cfg)

    objectString, err := GetObjectFromS3(context.TODO(), api, bucket, key)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(objectString))
}

ただし、これでは GetObjectFromS3 関数を呼び出す側はawsに強く依存したままだし、S3GetObjectAPI 型のインスタンスを生成するときにその実装は s3.clientであることを知らないといけない。 単体テスト時にSDK依存部分をモックで差し替えることが目的で、SDKに依存することを隠蔽したいわけではないのでこれで十分かもしれないが、インタフェースで実装は分離できていない。

コンストラクタによる生成の分離

AWS SDKに強く依存すること、インスタンス生成に関する知識が求められることが問題であれば、コンストラクタを使えばよい。これによりインスタンス生成に関する知識を分離できる。 S3GetObjectAPI インタフェース型のインスタンスを実装するための構造体として S3GetObject を定義し、そのコンストラクタとして NewS3GetObject を定義する。 これによりGetObjectFromS3 を呼び出す側もAWS SDKに依存せず、apiの生成に関する知識にも依存しなくなった。

type S3GetObject struct {
    Client S3GetObjectAPI
}

func NewS3GetObject() (*S3GetObject, error) {
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        return nil, err
    }
    client := s3.NewFromConfig(cfg)

    return &S3GetObject{
        Client: client,
    }, nil
}

func CallGetObjectFromS3Interface() {
    var bucket = "sample-bucket"
    var key = "sample-object-key"

    api, err := NewS3GetObject()
    if err != nil {
        log.Fatal(err)
    }

    objectString, err := GetObjectFromS3(context.TODO(), api.Client, bucket, key)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(objectString))
}

ただし、ユニットテストでAWS APIをモックしたいだけなら過剰に見える。 また、呼び出し側が api.Client を渡す必要があるのも違和感がある。どうすればよいかはわからなかった。

モックを用いたテストの改善

モック定義の分離

Goのテーブルテスト手法 を考えると、オリジナルのテストケースごとにモック関数を定義する方法はわかりにくいし差分を意識することが大変。 モック関数の定義はテーブルの外で行い、各テストケースはこれを参照するだけにしたい。

func TestGetObjectFromS3(t *testing.T) {
    mockClient := func(t *testing.T) S3GetObjectAPI {
        return mockGetObjectAPI(func(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error) {
            t.Helper()
            if params.Bucket == nil {
                t.Fatal("expect bucket to not be nil")
            }
            if e, a := "fooBucket", *params.Bucket; e != a {
                t.Errorf("expect %v, got %v", e, a)
            }
            if params.Key == nil {
                t.Fatal("expect key to not be nil")
            }
            if e, a := "barKey", *params.Key; e != a {
                return nil, errors.New("NoSuchKey")
            }

            return &s3.GetObjectOutput{
                Body: ioutil.NopCloser(bytes.NewReader([]byte("this is the body foo bar baz"))),
            }, nil
        })
    }

    cases := []struct {
        name string
        client func(t *testing.T) S3GetObjectAPI
        bucket string
        key string
        expect []byte
    }{
        {
            name: "return content",
            client: mockClient,
            bucket: "fooBucket",
            key:    "barKey",
            expect: []byte("this is the body foo bar baz"),
        },
...

これで、複数のテストケースを追加した場合でも見通しがよくなる。また、テストケースにテスト名(name)を加えることでよりテスト内容をわかりやすくできる。 ただし、テストケースごとに期待する挙動が異なるのでテストケース中に定義した方がよい場合もありそう。上記の例だと比較的汎用的な動作をするモックを作成しているのでテーブル外定義でよさそう。

モック用の構造体の定義

S3GetObjectAPIはインタフェース型として定義されている一方で、mockGetObjectAPIは関数型として定義されている。 個人的にはこの対応関係がわかりにくかった。プロダクトコードとテストコードで対応関係が取れていて欲しい。 (ただし、この方法には課題がある。詳細後述)

type MockGetObject struct {
    MockGetObjectAPI func(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error)
}

func (m *MockGetObject) GetObject(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error) {
    return m.MockGetObjectAPI(ctx, params, optFns...)
}

func TestGetObjectFromS3(t *testing.T) {
    mockClient := func(t *testing.T) S3GetObjectAPI {
        return &MockGetObject{
            MockGetObjectAPI: func(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error) {
                t.Helper()
...

ポイントとしては2つ。

1つ目はMockGetObjectのレシーバとしてGetObject関数を定義しているところ。この関数内部ではテスト用の MockGetObjectAPIを呼び出しており、MockGetObjectAPIをテスト時にモックで差し替えることでテストに応じた動作を実装することができる。 ただし、テスト時にGetObjectをモックとして直接差し替える方法があればもっとシンプルになる。このように段階を踏む必要が本当にあるのか疑問。

2つ目はMockt生成時に*testing.T を引数とした関数を介しているところ。 テストテーブルにて直接 &MockGetObject{...} を返さず *testing.Tを引数の関数を返すようにしている。これにより MockGetObjectAPI のモック実装時にテストのヘルパー関数を利用できる。 ヘルパー関数が不要であれば直接mockGetObjectのインスタンスを返した方がよいだろうか。

まだよくわかっていないところ

テストで繰り返し定義が必要

MockGetObject構造体定義、GetObject関数定義およびインスタンス生成時のMockGetObjectAPI実装時の合計3回、GetObjectに関する引数を持った型定義が必要。 これが非常に煩雑で面倒に見える。 今回はGetObjectだけだからよいが、GetObject以外の関数もモックが必要になると大量の定義が必要になる。 これをどうにかならないか、もっときれいな実装がないか疑問。 このあたりを解決するのがgomockなどの自動生成ツールなのか、という疑問もありそれは別途検証する。

プロダクトコードとテストコードの対応関係

このブログ記事を書きながら考えを整理していたら、S3GetObject 構造体と MockGetObject 構造体は全然対応できていないことに気が付いた。 S3GetObject 構造体のフィールドとして Clientを利用しているところがたぶん上手く理解できていない。

参考

デスクトップ環境をUbuntu22.04にアップデートした

日頃利用するデスクトップ開発環境としてUbuntuを利用しているが、これをUbuntu 20.04→Ubuntu22.04にアップデートした。

旧環境の課題

原因不明の動作不具合がいくつかあり、これを解消したかった。

音声入出力の不安定

映像出力は問題ないが、音声入出力が不安定という問題を抱えていた。

音声入力はボリューム設定が度々リセットされて自分の設定より小さくなった。多くの場合はサスペンド&解除するとリセットされ、たまに画面ロックしただけでリセットされることもあった。このせいでwebミーティングのマイク音声が小さくて自分の声が届いていないことが多々あり、ミーティング開始時に毎回音声入力ボリュームをチェックする必要があり面倒だった。

また、音声出力も不安定だった。音楽をかけていると急にボリュームが小さくなったりノイズが載ったりしていた。断線等を疑ったが結局GPUがおかしいのでは?という結論で改善できていなかった。音声出力の問題はUbuntu 18.04のときから発生していたのでOS設定が原因ではなくハードウェア的な問題だろうと(症状からしてそう)、GPU交換待ちだった。ただし、GPUの高騰のせいでなかなか交換を試せないでいた。

さらに、firefoxなど一部アプリが指定のスピーカーを利用してくれないという問題があった。システム設定を無視して別のスピーカーを利用してしまう。これを回避する方法がわからなかったのでfirefoxではweb会議や動画再生ができないという制約があった。

起動時のNFSマウントエラー

デスクトップ起動時にNASをNFSマウントする設定だったが、これが上手くいかない問題があった。

起動処理で/etc/fstabの設定を反映してくれず、毎回手動で sudo mount -aする必要があり面倒だった。また、libvirtまわりでもNFSマウントしている設定があり、これが原因でデスクトップ起動時にVMも起動してくれないとうい問題を抱えていた。 こちらはOSをUbuntu20.04にアップデートしてから発生したのでOS設定まわり(特にsystemdのブート順序まわり)を疑っていたが結局解決できなかった。OSクリーンインストールすれば解決するだろう、くらいの感覚だった。

フルディスク暗号化

既存のシステムディスクは暗号化を適用していなかった。

デスクトップ環境であり自宅外に持ち出す機会はないものの、暗号化できていないという事実には気になっていた。主要なデータはクラウド管理・バックアップしているが、個人情報の塊なので。

ハードウェアアップデート

以下のハードウェアについて更新した。

GPU更新

音声入出力のトラブルのうち、少なくとも出力についてはGPUのトラブルだろうと推測できていたのでGPUを更新した。

今まではGTX1660Tiを利用していて、パフォーマンス的には特に困ってはいなかった(ゲームをするわけでも機械学習するわけでもないので)。ただし、blender等さわったりする機会はあるし、RTXレイトレーシングAPIを利用できる環境は欲しかった。

RTX4000シリーズの発売直前ではあるし、RTX3000シリーズのハイエンド帯は価格が下落傾向ではあるが、エントリー帯であれば価格改訂や値下げが進むことはないだろうと判断してRTX3050を購入した。 RTX3050であれば現行GPUとほぼ同程度のパフォーマンスを出すことができるので自分の用途で困ることはない。 将来的にはGPUのミドルエンド・ハイエンドへのアップデートも考慮しつつ、このGPUは別サーバ等でも利用することを想定する。

SSD更新

OS更新時にはシステムストレージごと交換して新規インストールすることにしている。このため現在システム用ストレージに利用しているSSD(NVMe M.2)も更新する。

従来はSamsung SSD 970 EVO 250GBを利用しており、パフォーマンス的には満足していたものの容量不足を感じていた。

新規ストレージとしてはWD Blue SN570 1TB を選択した。 細かなパフォーマンス比較はしていないが、WD BlueはHDDとしてはよく利用しているしNVMe M.2 SSDとしても利用してみたかった。また、SN570が比較的新しくリリースされた製品なので試してみようと考えた。価格も特に高価とうわけではなかった。

OSインストール

OSインストールまわりのトラブルについて。

インストールメディアの準備

USBメモリを利用してOSをインストールするため、インストールメディアを作成して利用した。

今回はddコマンドを利用して作成したのだが、手順ミスなのかたまたまデータ書き込みエラーが発生したのか、作成したインストールメディアでインストーラを起動できなかった。 結局そのときはWindows PCにRufusを使ってインストールメディアを作成して対処した。

ddでもよいが、Ubuntuヘルプ または Ubuntuチュートリアルの通り Startup Disk Creator を使って作成してもよかった。

また、できればPXEブート環境を構築してUSBメモリなしにOSセットアップを可能にしたい。ただし、これを実現するには開発用ネットワークを分離する必要がありハードルが高い。

フルディスク暗号化

OSの新規インストールと合わせてフルディスク暗号化オプションを有効にする。

手順は Ubuntu22.04フルディスク暗号化を有効にする などが参考になるが、特にLVMレイアウトを変更しないので考慮する点はない。

問題はリカバリーキーの扱いで、生成されたリカバリーキーはデフォルトでは永続化されない。このため、インストール直後の再起動前もしくはインストールセットアップ時にリカバリーキーを永続化する設定が必要だった。この対応をしないとリカバリーキーは失われてしまう。 リカバリーキーを保存することなく削除してしまったら、リカバリーキーの失効と再発行を行う必要がある。また、LUKSは今までまともに使ったことがないので理解を深める必要がある。

ソフトウェアインストール

OSインストール後のセットアップまりのトラブルについて。

Extension Manager および Sound Input & Output Device Chooser

音声まわりのトラブルに対処するために、入出力デバイスを細かく制御できる必要があった。 これを実現するために Sound Input & Output Device Chooser を、GNOME Shell Extension Manager経由でインストールする。詳細については以下の記事を参照。

gihyo.jp

これにより、音声入出力デバイスの制御が可能となった。ただし、初手で Sound Input & Output Device Chooser をセットアップしたのでUbuntu22.04環境で本当に必要だったのかわからない。OS更新やGPU更新で問題は解消できていた可能性もあったので、Sound Input & Output Device Chooser をインストールする前に各種音声まわりのトラブルが発生しないか確認しておくべきだった。 Sound Input & Output Device Chooser 自体は便利に利用できているので、これを継続利用すること自体は問題なし。あとはExtension Managerまわりもまだ理解できていないので理解を深めておきたい。

NFSマウントセットアップ

OSクリーンインストールにより、起動時にNFSマウント失敗する問題も解消される想定だったが、そもそもNFSマウントに失敗するようになった。

原因等不明だが、対策としてはマウントオプションとして mountvers=4 を付与することで解消した。これにより、mountコマンド経由でも、/etc/fstab 経由でもマウント/自動マウントするようになった。

NFSバージョン詳細やマウントオプション詳細はあまり理解できていないので、詳細確認が必要。

deb版 firefox

snap版firefoxは不具合もあるのであまり使わない方がよいと事前から聞いてはいたが、実際に上手く動作しない問題があった。1passwordのアドオン拡張で Ctrl+. のショートカットが動作せず、パスワード補完にマウス操作が必要になるという問題があった。 これはさすがに許容できないと、以下の記事を参考にdeb版のfirefoxを導入した。

yuzu441.hateblo.jp

これにより無事1passwordアドオンも動作するようになった。ただし、カーソルが入力欄にあたっているとまだ動作しないという問題は残っており、完全解決には至っていない。

また、firefox以外も基本的にはsnap版を利用しないという方針をとっている。slackなどのアプリも上手く動作しないという事象に遭遇しており(Ubuntu20.04時、詳細は忘れた)、そういったトラブルの可能性を抱えてまでsnap版を利用するメリットを感じていない。

vim error

vi/view/lessなどのコマンドを利用するとき、 Failed to source defaults.vim のエラーが発生するというトラブルに遭遇した。 この不具合は既知のもので、いくつかのフォーラムにて報告されている。

bugs.launchpad.net

bugzilla.redhat.com

対策としては、 touch ~/.exrc にて .exrcファイルを作成した。これによりエラーは発生せずに動作するようになった。

SRE NEXT 2022に参加しました

2022-05-14 - 2022-05-15の2日間で開催されていた SRE NEXT 2022に参加しました。 各社のさまざまな工夫や取組みが共有され、学びのある2日間でした。 運営、発表者、スポンサーのみなさま、ありがとうございました。

以下視聴したセッションのうち特に気になった発表の備忘録です。

How We Foster Reliability in Diversity

speakerdeck.com

1日目の基調講演で、SREの難しさやどのように取組むとよいかの発表。

「SREの実践における重要な5つのステップ」において、「いきなりプラクティスを実践するのではなく、状況把握からはじめる」というのはまさに今の自分にあてはまる言葉だった。以前SREのプラクティス導入に失敗した身として、プラクティス導入のモチベーションが伝わっていなかったのでデザインドキュメントのような形で整理が必要と思っていたけど、それ以前に品質やプロダクティビティの現状が十分に共有されておらず、先に計測を始めるべきと取り組んでいる最中だった。「計測なくして改善なし」など、計測が重要なことは十分把握しているつもりだったけど、言語的な・定性的な現状把握だけでなく、定量的な把握が何よりも重要だと思っている(「定量的な」現状把握までは発表では触れられていなかったけど)。

また、組織の氷山モデルについて、単なる行動(Level1)を変えるだけでなく価値観(Level3)を変える必要があり、価値観を変えるためのアプローチが重要というのはその通り。行動を変えるだけならすぐにでもできるけど、それだとすぐに元に戻ってしまうので価値観から変える必要があると感じている。一方で、いきなりMVVの策定などに取り組んでも上手くいかないので、Level1から小さく始めて繰り返し、成功体験を積む必要があると感じており、まさに上からと下からの両面のアプローチが大切だと感じた。

1,000万人以上が利用する「家族アルバム みてね」のSRE組織は4年間でどのように作られてきたのか

speakerdeck.com

ミクシィさんにおけるSRE組織の誕生とこれまで・これから取り組んでいくこと。

SREチーム設立直後の施策として、IaC整備や開発環境整備、ログ分析基盤の構築、S3最適化や各種セキュリティ施策の実施などは、まさに自分が今までやってきたことなので、今まで自分が取り組んできたことは大きく間違っていないと安心することができた。

一方で、自分たちと違うこととして見積りを含むスクラムをベースに開発に取り組んでいる点。障害対応などの割り込みやチームとして開発コストの見積りが難しいことから、自分たちはスプリントを切ってスクラムで開発することは諦め、カンバン方式で開発のフローに集中することにした。このあたりスプリントを切ることの工夫やメリットは気になるところ。

1年間のポストモーテム運用と、そこから生まれたツールsre-advisor

speakerdeck.com

面白法人カヤックさんにおけるポストモーテムの取組み。

障害対応の知見をチーム間でも共有したいという目的の元でポストモーテムのフォーマット共通化およびそれを社内展開・ナレッジ蓄積するための取組みはすばらしい。自分はまずはナレッジの蓄積ができるようにポストモーテムのドキュメントを作成するところまではやっていたけど、それを組織に広めるために興味を引く一言コメント付きで展開するというルールまで策定しているのはよい取組みだと思った。ポストモーテムを書くかどうかの判断基準にエラーバジェットの消費量で判断するというのもわかりやすくよさそう。

また、ポストモーテムから導かれる再発防止をチェックリストにしたくないので、ツールで自動検知できるようにしたというのはフットワーク軽くすごい取組み。IaC側のコードでチェックするのが正道ではないかな、と思ったけどタスク定義のようにIaCされない部分をチェックしたいとか、社内固有のルールをチェックしたいなどの理由もあるようでなるほど。確かにtfsecやtflintで独自ルールを実装・管理するのは結構大変そうなので、このあたりさくっと対応できるのはすばらしい。

SRE チーム立ち上げから1年。気づいたら SRE っぽくない仕事まで貢献しちゃってる説

speakerdeck.com

ビットキーさんにおけるSREとしてやってきたこと、SREっぽくないけどやってきたこと。

プロダクトチームをスケールさせるためにSREチームを立ち上げ、SLI/SLOやセキュリティ,テストなどを整備してきた上に、プロダクト開発における文化醸成やコーポレートセキュリティ、コスト削減などの相談がくるなど、プロダクト開発以外の相談事項がSREにくるのはあるあるなのかなと思った。コスト削減についても、具体的な閾値があるわけではなく無駄使いを止めたい、現在のコストが適切なのか判断できるようにしたい(コストの透明性を確保したい)という本来の目的からコストの可視化に取り組んだ点はまさに自分も同じことをしたので納得感が強かった。

SREの守備範囲が広過ぎてDevOpsの文脈以外の取組みもあるというのはその通りだし、コストやセキュリティなどは無関係ではいられなくても片手間でどうにかなる話ではないので、きちんと責務を分離して取組めるようになるとわかりやすい。現状だと Embedded SRE / Enabling SRE / Platform SREのようなわけ方はあるが個人的にはしっくりこないので、品質にコミットするSRE、セキュリティにコミットするSRE、コストにコミットするSREのような分類方法があっても面白いと思う。

Who owns the Service Level?

speakerdeck.com

リクルートさんにおけるSREの実現について2020年の発表を踏まえたふりかえり。

いつもながら、自己完結を重視しこれを実現するのはすばらしいなと思いつつ、エラーバジェットを元にした行動には至れていないというのは少し驚いた。ただし、SLO違反したら機能リリースはストップするというのは難しいと思っていたので、これを幻想と言うのはすごく納得した。SLI/SLOはエンジニア以外との共通言語の役割で、認識共有やディスカッションにつながっていればそれで十分役目を果しているというのであれば、自分ももう少し安心して社内にSLI/SLOを導入できる気がする。

街じゅうを"駅前化"する電動マイクロモビリティのシェアサービス「LUUP」のIoTとSRE

speakerdeck.com

LuupさんにおけるIoTシステムにおけるSREの取組み。

IoTなシステムにおける信頼性の計測に、CUJからSLI/SLOを策定するだけでは不十分なのでM2M通信の可用性を計測する必要があり、これをCMC(Critical Machine Communication)と名付けて電文解析・ログ管理して計測できるようにするという取組み。このあたりはまあ難しいよねと思いつつ、ハードウェアでは故障を検知した時点で手遅れなことが多い(修正に時間が掛かる)ので、故障予測などが必要ではないかと思ったら当然並行して取り組んでいるとのこと。 IoTシステムの場合、特に製品が安価になるほど監視や故障予測がコストに見合わずに、障害時にさっさと代替品を提供するという判断になりがちなので、CUJを重視してこのあたりを取り組んでいく取組みは非常に興味深い。

SRE NEXT全体について

動画視聴やQ&Aなどは特に問題なく、2日間通して気持ちよく参加することができた。これだけで運営のみなさまには大感謝。今後カンファレンスには発表する側か、せめてプロポーザルリジェクトな状態で参加したいところ。

ただ正直なところ、EventbriteやZoom Event Lobbyはあまり使いやすいとはいえず、このあたりもう少しどうにかならないかなとは思った。自分の普段利用の環境であるLinux Desktop(Ubuntu)はZoom Event Lobbyに対応しておらず、1日目開始直前の動作環境で利用できないことに気付いてあわててmacbook環境を準備した。Linux Desktopがこういった機能未対応なことはよくあるのでしょうがないけど、ちょっと悲しい。

書評: Jetpack ComposeによるAndroid MVVMアーキテクチャ入門

久しぶりにAndoridアプリ開発がしたくて始めたけれど、 Jetpack Composeがよくわからなかった。 いろいろ調べているうちにこの本を見付けて、よさそうだったので読んだ。

概要

Android アプリ開発においてMVVMアーキテクチャを採用する方法として、Jetpack Composeを用いる方法の解説。 MVVMの解説・シンプルなアプリ例・実践的なアプリ例の3構成となっている。

自分はJetpack Composeというところに惹かれて購入したけど、どちらかというと主題はMVVMであり、 Jetpack Composeに含まれているViewModelライブラリの方に重点が置かれている。 そのため、Viewに関するところの説明でデザインに相当する解説はほとんどない。 また、MVVMを採用する上で重要となるDIについても扱われている。

よかったところ

目的であったJetpack Composeについて知れたのはよかった。 UIデザインの目的で購入したが、それよりもUIを宣言的に実装できること、ViewModelを導入してライフサイクルの考慮が軽減できることが知れてよかった。 ただし、本書で「Androidアプリに特有のライフサイクルの問題を吸収してくれる機能がある」と記載しておきながら、 その具体的なライフサイクルとは何か説明されていないことは気になった。 いろいろ調べて試してみたところ、自前実装のライフサイクルを考慮していないViewModelだと 画面の回転でリソースが破棄されて画面の表示がリセットされるが、 JetpackライブラリのViewModelを利用すると表示が引き継がれることがわかり感動した。 おそらくAndroidアプリ開発経験者にはあたりまえの事なので省略されていたのだと思うが これを理解していると実感がまったく異なるのでこれに気付けてよかった。

また、DIについて知れてよかった。 AndroidにおけるDIはまったく把握していなかったので、このとっかかりにすることができた。 残念ながらDIの解説書ではないので説明が十分とはいえないが、予めDIとは何か簡単に知っていると本書の内容としては理解できるし、 知らなくても実際に動くコードを見ながら理解を深めることができる。

よくなかったところ

一番残念なのは4章の実践的なアプリとして登場する、GitHubのWeb APIを使ったアプリについて説明が少ないこと。 分量としては約40ページ割かれているが、その大半がコードの掲載およびそのコードの説明で、 その背景にあるMVVMアーキテクチャの説明としては不十分に感じた。

例えば、ViewがViewModelに依存しておらず状態変更を購読しているだけだという2章における説明が、 4章のアプリの説明では一切出てきていない。 これを実現するためにDIが上手くやってくれていると一言あるだけでMVVMとの対比が鮮明になると思う。

それ以外にも4.2節 Remote Data Sourceについて、大きくRemoteDataSource、ApiClient、GitHubUserと登場する中で、 それぞれの立ち位置が説明されておらずきちんと理解できているかよくわからない。 RemoteDataSourceがRepositoryに対するインタフェース、ApiClientはRemoteDataSourceに対するインタフェース、 GitHubUserは各インタフェースおよびRepositoryに対するDTOと理解したが正しいか自信がない。 どのインタフェースが何に対して抽象化しているのかといった説明は明記して欲しいと思った。

まとめ

AndroidにおけるMVVMアーキテクチャを理解する上で、またJetpack Composeを利用する上で非常に参考になった。 後半若干説明不足に感じるが、精読したり周辺技術を追加調査したりすると、MVVMやJetpack Composeについて理解を深めることができる。 そのとっかかりとして本書は非常に有益に感じた。

2021年のふりかえりと2022年の抱負

2021年のふりかえり

2021年は2020年と比べて失敗経験を積めた年だった。 2020年は新しい環境で、今までにない経験を積むことができたのに比べて、2021年は今までの取り組みをより良くするために試行錯誤してきた。結果、上手くいったものもあれば、上手くいかないものもあった。 残念ながら課題の多い1年だったけど、これを糧に2022年をより良い1年にしたい。

できたこと

成果のアウトプット

アウトプットは一定の成果を出せたが満足行くものではなかった。及第点という感じか。

  • 登壇: 1件
  • 個人ブログ: 11件
  • Qiita+Zenn: 5件
  • 会社ブログ: 1件

一番よかったのは目標であったカンファレンスでの発表を実践できたこと。カンファレンスでの発表はエンジニアキャリアの中でも目標の1つだったので、ひとまずそれが達成できたのがよかった。 とはいえ、久しぶりのプレゼンで話をするのが下手になっていたので、発表には満足できておらずそれは残念だった。 もう少し気軽に5分LTから経験してと考えていただけに、いきなり&久しぶり&初の社外向けの発表で15分はやり過ぎだったか。15分くらいは大したことないと思っていたので、今後どのように発表していくかは考えどころ。

tech.spacely.co.jp

OSSへのコントリビュートも、実装レベルでプルリクを作成することはできなかったが、不具合のissue報告などは取組むことはできた。 しかし件数がたった2件と圧倒的に足りていない。もちろん数の問題ではないが、普段利用しているOSSの数や利用量から考えるとコントリビュートするという目標に対して少ない。 github actionを作成・公開することはできたが、それも1件かつ作成後ほとんどメンテできていない。

メインとなるはずのブログやQiita/Zennなどの記事執筆も量的には満足できないものだった。 2021年前半はある程度順調にアウトプットできていたと思うが、後半には社外へのアウトプットが途絶えてしまった。 社内でのアウトプットは継続できており、社内Qiita、GitHub Wiki、Google Docsとさまざまな形で実施できていた。 業務で得た知見はすべてが社外に公開できないものではないので、これを社外に公開できないのは反省点。 個人での学びも2021年後半は減りはしたものの止まったわけではなかったのでもっとアウトプットに時間を割くべきだった。

CI/CDの強化

CI/CDはいろいろと取り組むことができたのでよかった。

  • GitHub Actionの作成と公開
  • コンテナアプリのCI/CD環境としてGitHub Actions (CIサービス)の利用
  • lambda関数のCD活用
  • railsアプリのCodePipeline適用
  • インフラまわりのCI/CD活用(ansible-lint, Terraform Cloud活用, ImageBuilder活用)

CI/CDサービスとしてはGitHub ActionsやAWS Codeシリーズなどを本格的に活用できるようになった。 対象アプリとしても、コンテナアプリ、lambda関数アプリ、その他のアプリ、インフラと幅広く扱うことができた。 社内のCI/CDインフラもだいぶ改善したし自分の知見もいろいろと蓄積することができた。

もちろん課題も多くある。 1つは、CircleCIまわりのメンテ・サポートがほとんどできなかった。 Webエンジニア側にまかせてもいいかと判断した点はあったけど、せっかくCI/CDに注力するとしていたのだからもう少し手を出してもよかった。 2つ目がDevSecOpsの導入で、具体的にはSonarCloudを検証・導入したが、残念ながらあまり上手くいっているとは言えない。 このあたりは導入モチベーションをきちんと共有できないことが失敗の原因だった。どちらかというとマネジメントの問題。 最後にインフラまわりのCI/CD。Terraform Cloudの活用がどんどん進んだことはよかったが、 ansibleはlint止まりでテストは導入できず、terraformもtrivyを検証まで行ったが導入までいかなかった。 AWS Image Builderもなんとか動作するようにはなったがまだまだ課題が多い。

運用・監視の深化

運用監視はまだまだ課題はありつつも、大きく進歩した1年だった。

具体的にはWebエンジニアを巻き込んだダッシュボードのふりかえり定例会議が開催されるようになった。 ここでの確認を通してダッシュボードや監視の仕組みの継続的な改善が行われるようになった。 これを通してダッシュボードの修正や監視メトリクスの追加・修正なども行われるようになった。 加えてWebアプリの修正にも反映されるようになったのでよかった。

一方で課題としては、SLI/SLOの導入失敗が挙げられる。 これはできなかったことにも挙げているがマネジメントの失敗で、十分にSLI/SLOのメリットや導入目的を共有しないまま進めてしまったことが失敗の原因にある。 そりゃSLI/SLOやエラーバジェットなんて知らない人の方が多いのだから、もっと導入意義を納得してもらってから進めるべきだった。

セキュリティ対策強化

苦手だと思ってあまり深追いしてこなかったセキュリティ分野は、必要に迫られる形でいろいろ取組むことができた。

Webアプリの脆弱性診断を主導することができたし、CIの中でセキュリティを意識し始めることができた。 DevSecOpsはtrivyを通してインフラに対しても適用検討することができた。 こういった取組みを開始して形として残り始めたのはよかった。

一方で、まだまだ対応については満足できていない。 本来は対応すべき内容を優先度の観点から保留しているケースもあり、 2022年はセキュリティ面でも安心できるようにしたい。

できなかったこと

マネジメント

正直なところ、2021年で一番失敗したと思うのがマネジメント、というよりリードエンジニアとしてエンジニア組織を引っ張るところ。 具体的には、エンジニア全体で取組むべきと自分が考えた事について十分に理解を得ずに進めようとした結果、空回りしてしまった。

やりたい理由・モチベーションを十分に共有してから進めるべきだった。 また、上手くいかない状況に焦ってより悪い振舞いをしてしまったのよくなかった。 モチベーション共有にはデザインドキュメントを採用してみたが、これも上手くいっているかは判断できない状況。 デザインドキュメントの導入自体も押し付けであるとも考えられるので、自分1人で試しているが上手く運用に乗せることができるかは2022年次第。 振舞いの改善はどうすればよいかはまだ悩み中。自分で気付いたときには振舞いを改めるようにしているが、大抵の場合は議論の最中には気付けない。

逆にタスクマネジメントについてはある程度上手くいったのでこちらは継続していきたい。

スケーラブルなインフラ

インフラのスケーラビリティについてもビジネス的な必要性がないことから対応できなかった。

自分たちでリソースを管理する必要のないマネージドなサービスを選択できている一方で、 リソース管理が必要な部分ではまだまだ無駄が生じている。 コストまわりはやっと課題として認識されてきたので、2022年こそは取組めるはず。 2021年にもいろいろと検討できているので、その検討結果をリリースまで取組みたい。

DB知見の深化

DBまわりも結局詳細な検討にまで取組めなかった。

RDBはパフォーマンスモニタリングまでは取組めたものの、改善には着手できなかった。 スロークエリやDB負荷については認識を共有できたと思うので、着実に改善に繋げていきたい。 また、Redisは未対応だしMongoDBまわりも結局置き換えてしまった (これはむしろ良い判断だった。ただし、MongoDBまわりを検証する機会は失った)。

DBまわりは今後も課題がたくさん残されているので、継続して取組みたい。 RDB負荷については負荷試験のための取組みを取組みたい。 Rails6の複数データベースまわりの知見は間違いなく必要になるのできちんと検証しておきたい。 Redisの対応は必要になるだろうがMongoDBは必要になるだろうか?その分Elasticsearchのような全文検索の仕組みは必要になりそう。 いろいろなデータレイク・DWHを試して知見を蓄積したい。

フロントエンド技術入門

結局フロントエンドまわりはほとんど取組むことができなかった。

できたのは node.jsでバックエンドを構築するくらいで全然フロントエンドではない。 Vue.jsやTypeScriptを学ばなければ、と思いつつも本当に触っただけに終わった。 Railsのアセットパイプラインについては学ぶことはできたが全然フロントエンドではない。

ここは自分の興味であるVRに範囲を絞って取組むべきだった。 それ以外のフロントエンドまで含めてしまうと自分の興味から外れてしまうので取組むモチベーションにならなかった。 もしくは、アプリケーションの実装という中でフロントエンドにも触れる、くらいを目指すべきだった。

クラウドネイティブな技術のキャッチアップ

これは元々目標ではなかったけれど。 年々業務に必要な知見にのみ注力してしまい、Kubernetesやその周辺知識のキャッチアップが疎かになってしまった。

AWSの新規プロダクトを通して知見を増やすことはよいが、もっと上流(と言えるかは不明だが)のOSSまわりや他社含めた動向にも目を通すべきだった。 CNCFもそうだが、USENIXなどの学会系も含めた最新技術の動向や、他社のアウトップトを通しての実践例を学び、 自社にない技術についても知見を深めていきたい。

2022年の抱負

2022は継続と完結をテーマにしたい。

一時的な興味だけに終わらず、継続して取組むことで目標達成まで到達すること、完結させることを大切にしたい。 調子の良いときに成果を出すのはもちろんだが、調子が悪いときに無理なく取組めるか、継続できるかを意識して頑張りたい。 やるべきこと、やらなくてよいことの取捨選択を行い、いつかやるで保留せずにやらない判断を下して物事を完結できるようにしたい。

個人成果の追求

良い意味でもっと自己中心的に、自分個人の取組みに注力していきたい。 組織をリードする点も止めるわけではないけど、それが理由で個人の成果を犠牲にはしないようにしたい。

組織のリードについては、会社組織が拡大してきたこともあり、自分が何でもリードする必要はなくなってきた。 言いたい事ややりたい事を少し我慢してでも、特に別チームの事はそのチームに任せ、 エンジニア全体として取組むべきでも合意を得ることが難しいようであれば諦めることも選択肢に入れたい。 エンジニア全体の改善よりは、多少局所最適になっても自分のことに注力したい。

また、業務にばかり時間を掛けずにもっと個人的な興味に時間を使いたい。 自分の興味や好みにリソースを割いて、自分が楽しむことを優先していきたい。

成果のアウトプット

2021年はもの足りなくても2020年よりは上手くいった。 2022年は2021年よりさらに意識して取組みたい。

カンファレンスでの発表ももっと増やしていきたい。発表するという目標から、自分が満足できる質で発表できることを目指したいし、発表回数も増やしていきたい。 OSSへのコントリビュートや自作OSSの公開などは特に注力したい。 できれば実装修正のプルリクを投げられるようにしたいが、そうでなくても不具合再現のためのissue起票などをできるようにしたい。 自分が利用しているOSSをしっかりと使い込んでいきたい。 ブログ記事等の執筆は2021年前半のペースでよいので継続していきたい。 どちらかと言うと、ブログ記事は内容にこだわって書けなくなるよりは、小ネタでも継続して書けるようにしたい。 その際はQiita/Zennなども活用してアウトプットしていきたい。

xR技術

せっかくVRの会社で働いているのだからxRの技術について理解を深めたい。 VRはもちろんだけど、個人的にはARにも興味はあるのでARにも取組みたい。

VR技術としては、three.jsなどのフロントエンド技術もそうだし、blenderやOpenCV、Unityなどを通して3DCGモデリングについても理解を深めたい。 またVR動画(というか360度動画)まわりにチャレンジしたい。正直なところ、動画まわりは配信技術としてインフラまわりに特に興味があるのでそのあたりも含めて検証したい。 できれば、Androidアプリなどを通してARにも挑戦したいし、いろんなデバイスについても試してみたい。

テスト

テストまわりの知見強化と実践に取り組んでいきたい。 2021年はCIという形でテストに触れてきたけど、よりテストにフォーカスしたい。

アプリケーションのテストとしては静的解析/動的解析やセキュリティおよびリファクタリングまわりも含めて取り組んでいきたい。 このあたりはインフラエンジニアとしてではなく、SETやQAなどのロールとしても動ける程に知見を深めていきたい。 また、その流れとしてシステムテストとその自動化まわりにも取り組んでいきたい。

アプリ以外にもインフラのテストについて取り組んでいきたい。 インフラのテストをどう実践するかはまだ具体化できていないが、2021年の課題に感じていたところなのでいろいろと実践していきたい。 IaC自体のテストはもちろんだが、システムテストにまでいかない、上手いテストのやり方を模索していきたい。

低レイヤ技術

業務ではOSに近い低レイヤ技術にあまり触れる機会がないので、個人的な形ででも取組んでいきたい。 HWに近いいわゆる低レイヤ技術だけでなく、オーケストレーションツールやGPUまわりなど、今より1つ低いレイヤに取組みたい。

Amazon Linux2022の検証という形でFedoraディストリビューションは試していきたいし、その他ディストリビューションやlinux kernelレベルの知見を深めていきたい。 途中で止まっている自作OSの取組みもできれば再開していきたい。 自宅サーバの運用もほとんど動きが止まってしまったのでアップデートしていきたい。 xR技術に取組む中でGPUやIoTデバイスなどをいろいろ扱っていきたい。