ちりもつもればミルキーウェイ

好奇心に可処分時間が奪われる

つくって理解するストリーム暗号 ChaCha20

はじめに

Go 1.22 で math/rand に ChaCha8 実装が入ったらしい

しかも math/rand/v2 トップレベルで利用されてる、かつシードがない math/rand でも使われるようになったらしい。一応議論を追った感じだと、暗号学的強度がある乱数をもとめてるのに math/rand つかっちゃうケースがちょいちょいあるらしく、そういうケースでリスクが少なくなるし生成コストも大したことないからいいんじゃね?みたいな雰囲気だった。

ぼくは RSAを完全理解しようとして途中で疲れた 過去を持っており、このへんちょっとわかり手なのでホットな話題に乗っかって ChaCha 実装しながら完全理解しようというやつです。

はじめにやってる操作について説明し、そのあと実装する感じでやります。みんなで完全理解しよう

ChaCha 概要

ChaCha 自体の元ネタは Bernstein, D., "ChaCha, a variant of Salsa20", January 2008 で、ストリーム暗号の一種です。

めちゃめちゃざっくりいうと、入力とか定数から内部状態をつくって、それにround関数かけてかき回すことで擬似乱数つくり、最後にXORとって暗号化や!みたいなやつです。

Go 1.22 では、この擬似乱数を得る部分の処理が math/rand に採用された感じです。

かけるラウンド r の数によって ChaCha r みたいな言い方をしたりします。 ChaCha8 とか ChaCha20 とか。

なので ChaCha の理解にあたって着目すべき主要な観点としては、内部状態をどう初期化するかということと、それをround関数でどうかき回すかの2点です。

そのへん説明していきます。

内部状態の初期化

入力は

  • 256bit key: K = (key_0, key_1, key_2, ... key_7)
  • 32bit counter: C = (counter_0)
  • 96bit nonce: N = (nonce_0, nonce_1, nonce_2)

です。(元ネタにある表だと counter と nonce は区別せず input として記載していますが、ここではわかりやすさのため別の性質であることを明示しています)

さらに以下の定数も保持しています。

  • const_0 = 0x61707876
  • const_1 = 0x3320646E
  • const_2=0x79622D32
  • const_3=0x6B206574

(余談だけどこの定数は特に意味のない値で expand 32-byte k ていう文字をそのままhexにとっただけ。なんかこういう意味のないことが自明な値を定数に使うとかよくあるらしい)

入力3つと定数を合わせて4つの要素から状態を構成しています。
状態は以下のような行列で表せます。

 \boldsymbol{X} =
\begin{bmatrix}
x_0 & x_1 & x_2 & x_3\\
x_4 & x_5 & x_6 & x_7 \\
x_8 & x_9 & x_{10} & x_{11} \\
x_{12} & x_{13} & x_{14} & x_{15}
\end{bmatrix}
=
\begin{bmatrix}
const_0 & const_1 & const_2 & const_3\\
key_0 & key_1 & key_2 & key_3 \\
key_4 & key_5 & key_6 & key_7 \\
counter_0 & nonce_0 & nonce_1 & nonce_2
\end{bmatrix}

これが初期状態で、こいつをround関数かけてぶん回した出力が擬似乱数になるぞいという感じですね。

QuarterRound

次にround関数の詳細です。ChaCharでは QuarterRound という関数を使ってかき混ぜてるのでそのあたりを紹介します。

ある関数 QuarterRound(a, b, c, d) があったとき、その操作は以下

a += b; d ^= a; d <<<= 16;
c += d; b ^= c; b <<<= 12;
a += b; d ^= a; d <<<= 8;
c += d; b ^= c; b <<<= 7;

ここで +2^{32} を法とした演算であり <<< は回転シフト なので注意。

ようは各要素ごとに加算、XOR、回転シフトを順繰りに繰り返して値をガシャガシャにしているという感じ。

QuarterRound() っていうくらいなので、これを4回やって1ラウンドということになってるぽい。

QuarterRound を使って擬似乱数列を得る

以下のように column 方向と diagonal 方向ごとに1ラウンドごと、計2ラウンドをセットでまわすっぽい

/* column round */
QuarterRound( x0, x4, x8,x12)
QuarterRound( x1, x5, x9,x13)
QuarterRound( x2, x6,x10,x14)
QuarterRound( x3, x7,x11,x15)
/* diagonal round */
QuarterRound( x0, x5,x10,x15)
QuarterRound( x1, x6,x11,x12)
QuarterRound( x2, x7, x8,x13)
QuarterRound( x3, x4, x9,x14)

わかりやすく図字すると、column 方向の処理対象はこんな感じ。順にやっていって、要素を全て処理したら1ラウンド!

column round

diagonal 方向はこんな感じ。おなじく全部処理したら1ラウンドなのは同じだけど、ななめ方向にかきまわすのが column round との違い

diagonal round

それぞれ合わせて2ラウンドで、これを何回繰り返すかがいくつかパターンがあるようす。 ChaCha20 はこのセットを10回繰り返す感じぽい。

最終的に期待回数のラウンドをこなしたあとに、初期状態 X との和をとったものが key stream として出力されるぞ!ということらしい。

暗号化 & 復号

擬似乱数とXORするだけなので特に語ることなし!

しいていうとしたら平文 m を ChaCha の擬似乱数出力サイズである 512bit ごとのブロックにわけてXORとっていくくらいだけど、まあそれも説明不要だと思うので省略。このときブロックごとに counter を increment しながら key stream を作っていったりするんだけど、実装みればすぐわかりそうなのでそれも省略。

実装してみる

最終的な実装はこちらにあるので、まとめて見たい方はこちらを!

github.com

RFC8439 の appendix A.1 に ChaCha20 のテストスイートがあるのでこれをパスさせることを目指します。のでラウンドは20で実装するぞい!

(Go 1.22 math/rand に ChaCha8 実装入って気になったのがそもそものモチベなので、せっかくだからラウンド8でやりたい気持ちもあった。けどシュッといい感じのテストスイートを探せなかったので20ラウンドでやることにしまた!ラウンドかける数しか違いないしまあどっちでもいいよねという感)

勉強目的の実装なので、細かいハンドリングは考慮せず作っていきます。

あとせっかくなので、かっちょよく crypto/cipher.Stream interface を実装して使える感じにしていきましょう。

まずはノリで初期化を書く!初期状態周りはすでに説明してるのでそのまんまいきます。

type Cipher struct {
    constant [4]uint32
    key      [8]uint32
    counter  uint32
    nonce    [3]uint32
}

var _ cipher.Stream = (*Cipher)(nil)

func NewCipher(key [32]byte, count uint32, nonce [12]byte) *Cipher {
    c := new(Cipher)
    c.constant = [4]uint32{0x61707865, 0x3320646e, 0x79622d32, 0x6b206574}
    c.key = [8]uint32{
        binary.LittleEndian.Uint32(key[0:4]),
        binary.LittleEndian.Uint32(key[4:8]),
        binary.LittleEndian.Uint32(key[8:12]),
        binary.LittleEndian.Uint32(key[12:16]),
        binary.LittleEndian.Uint32(key[16:20]),
        binary.LittleEndian.Uint32(key[20:24]),
        binary.LittleEndian.Uint32(key[24:28]),
        binary.LittleEndian.Uint32(key[28:32]),
    }
    c.counter = count
    c.nonce = [3]uint32{
        binary.LittleEndian.Uint32(nonce[0:4]),
        binary.LittleEndian.Uint32(nonce[4:8]),
        binary.LittleEndian.Uint32(nonce[8:12]),
    }
    return c
}

func (c *Cipher) toState() [16]uint32 {
    return [16]uint32{
        c.constant[0], c.constant[1], c.constant[2], c.constant[3],
        c.key[0], c.key[1], c.key[2], c.key[3],
        c.key[4], c.key[5], c.key[6], c.key[7],
        c.counter, c.nonce[0], c.nonce[1], c.nonce[2],
    }
}

func (c *Cipher) XORKeyStream(dst, src []byte) {
    panic("implement me!")
}

いちおう test vector を定義してくれてる RFC8439 では little endian で取り扱う旨が記載されていたのでそれに従って取り扱っているけど、その部分以外で読んでわからないところはないはず!

つぎに QuarterRound(a,b,c,d) を作る。回転シフトは math/bits に準備されてるのでありがたく使いましょう。

func qr(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
    a += b
    d ^= a
    d = bits.RotateLeft32(d, 16)
    c += d
    b ^= c
    b = bits.RotateLeft32(b, 12)
    a += b
    d ^= a
    d = bits.RotateLeft32(d, 8)
    c += d
    b ^= c
    b = bits.RotateLeft32(b, 7)
    return a, b, c, d
}

加算は 2^{32} を法とする加算なのに普通に a += b していますが、これは uint32 での演算なので溢れたら勝手に捨てられるためです。

素材がそろったので、あとは column round & diagonal round を10回ずつぶんまわして最後に 2^{32} を法とする和をとれば key stream がとれる!

func (c *Cipher) keyStream() [64]byte {
    x := c.toState()
    for i := 0; i < 10; i++ {
        // column round
        x[0], x[4], x[8], x[12] = qr(x[0], x[4], x[8], x[12])
        x[1], x[5], x[9], x[13] = qr(x[1], x[5], x[9], x[13])
        x[2], x[6], x[10], x[14] = qr(x[2], x[6], x[10], x[14])
        x[3], x[7], x[11], x[15] = qr(x[3], x[7], x[11], x[15])
        // diagonal round
        x[0], x[5], x[10], x[15] = qr(x[0], x[5], x[10], x[15])
        x[1], x[6], x[11], x[12] = qr(x[1], x[6], x[11], x[12])
        x[2], x[7], x[8], x[13] = qr(x[2], x[7], x[8], x[13])
        x[3], x[4], x[9], x[14] = qr(x[3], x[4], x[9], x[14])
    }
    initial := c.toState()
    for i := range x {
        x[i] += initial[i]
    }
    var stream [64]byte
    for i, v := range x {
        stream[i*4] = byte(v)
        stream[i*4+1] = byte(v >> 8)
        stream[i*4+2] = byte(v >> 16)
        stream[i*4+3] = byte(v >> 24)
    }
    return stream
}

あとは↑のstreamと適当にXORをとる処理を実装すればよろし
(実用に耐えるものを作るならlenのエラーとか細かいハンドリングが本来必要だけど、今回は勉強目的なのでskip)

func (c *Cipher) XORKeyStream(dst, src []byte) {
    // NOTE: Skip error handling because this implementation is learning purpose.
    for len(src) > 0 {
        stream := c.keyStream()
        block := len(stream)
        if len(src) < block {
            block = len(src)
        }
        for i := range block {
            dst[i] = src[i] ^ stream[i]
        }
        c.counter++
        src, dst = src[block:], dst[block:]
    }
}

これでうごくはず!key stream size である 64byte ごとに処理していくんだけど、その際1回ごとにカウンタを increment するのを忘れずに(1敗, ここ忘れてると test vector が通りません)

実装とテストは playground にまとめてポン置きしたので、実際に動いてる姿を眺めることもできます。

https://go.dev/play/p/gp9lej-MBO6

これにて実装も完了!すべてを理解しましたね。

感想

やってる操作はそんな難しくないので完全に理解した。

ChaCha20 とか ChaCha8 とか数字違うのなんやねんと思ってたけど、単にラウンド数の違いでしかないというのもわかってよかった。

なんというかこんなに簡単そうな操作で計算量的安全性のある擬似乱数つくれるっていうのは面白かった。ChaCha は専用命令のってないハードウェアでもコスト軽いって紹介されることがおおいけど、そら軽いわという感想になった。

あと TLS 1.3 では AEAD (Authenticated Encryption with Associated Data) として ChaCha20-Poly1305 が定義されてたりするので、Poly1305 を理解していい感じに腹落ちしたいなという感じもあるのでそのうち興味わいたらやってみようかな〜〜〜〜

2023年の振り返りと来年の抱負

はじめに

けっこう遅刻したけど毎年やってたので振り返りちゃんとやるか〜と思い立って書いた。まあ詳細は後述するけど、大きいテーマみたいなのを決めてたんだけどあんまりそれは達成できんかったよという感じでした。

毎年いってるけど一年に1回しかフィードバックサイクル回らないのやばすぎるだろ

去年やろうとしてたことに対する振り返り

このへんに書いてある

convto.hatenablog.com

収束させるっていうテーマでがんばるぞい〜という話をしていたんだけど、あんまりうまくいかなかったですね。

結構目の前のことに熱中して頑張る、あるいは頑張りたいみたいな機会が多くてそれ以外のことにはリソースを避けなかった感じだった。仕事が忙しかったともいう。

コンテナまわりかDBまわりを深掘りたいな〜というのはおもっていたんだけど、結局それ関連でやったのは去年の年明け近くに Database Internals 読んだだけであとはそれっぽいことはやってない。

一方で仕事でたのしくわいわいやるのはだいぶできた感じがしており、全体的に比重がそっちに寄ったかなという所感がある。

仕事関連の振り返り

とにかくわちゃわちゃしていた。ほとんどここに書いてある

convto.hatenablog.com

今北産業の従業員向けにかくと

  • 半年くらいでチーム移籍したりわりとドタバタした
  • (チーム移籍後はとくに)やりたいこととリソースの制約のギャップに苦しんでる
  • いいもの作ろうとする意思があってだいぶ楽しい

という感じ。たいへん楽しく働けております。

いくつかでかい機能もデリバリしたけど、もうちょい価値を最大化するために、どのfeatureを作るべきか、どう提供すべきかについての嗅覚を磨きたいな〜と思う1年だった。

でかい弾仕込んでて短期的な顧客へのアウトカムがないみたいなのも健全じゃないと思うので、もっとイテレーション細かく顧客からのFBがもらえるようにプロセスを改善したりとか、あるいは単位時間の顧客への出力が最大化するようなロードマップ策定を考えてみたりとか、そういう方面に対してできることを増やしたいな〜と思った。

ので来年は頑張ります。

技術関連の振り返り

今年はマジで記事書かなかった!「ちりもつもればミルキーウェイ」なのに全然ちり積もってないじゃん!大反省した

社のほうで書いたやつ含め7本しか書いてない(うち技術関連の記事は4本)

2021は当ブログである「ちりもつもればミルキーウェイ」だけで32本、2022年は少し減ったけど21本書いてたし、どっちもよそのアドカレとか会社のほうで書いたやつとかも合わせたらもっと書いてたので今年は微妙でしたね。

来年は積もらせていきたいニャンね〜

外部登壇とかは Go Conference 2023 でブログにも書いた tree err についての話をしたのがある。たぶんそれ以外は外で喋ってない

gocon.jp

(余談だけどバーチャル背景使うの忘れてて寝室が世界に公開されてしまった)

OSSへのパッチは今年はなにも出してない!ぐえ〜反省。日々いろいろなソフトウェアを使わせてもらってるので、せめて自分の興味ある領域とかぐらいは協力していきたいっすな。来年は頑張るんだよ

技術系の振り返りの総括として今年はあんまりちゃんとやれなかったなと思っている。

とはいえそんななかでもid採番芸人した記事は自分でも気に入ってる。こういう出力を月1くらいで出していきたいもんですね。

tech.layerx.co.jp

仕事と関係ない方面でちゃんと面白いことやりたいっすね。無駄に見えてもそういうのが変なところで役に立ったりするし、なによりそういうのが好きなんだからしっかりやりなよという気持ち。来年はもっと面白くなるよね、ハム太郎

プライベート振り返り

転職したらめちゃくちゃ良かった。全てはこの転職エントリに書いてる

convto.hatenablog.com

気性との噛み合いも感じているしもっと頑張りたいなと思っています。来年もやっていきて〜な。やっぱいいものつくることをみんな目指してるのいいよね。

あと大学生になった

convto.hatenablog.com

そろそろ1年経つんかという驚きがある。ちなみに1/10締切の課題があるので現在進行形でヒーコラいってます。

なんか単位とるノリとかよくわかってなくて夢詰め込みすぎて早速いくつか落としてるんだけど、まあ今後は無理ない範囲でゆっくりやります。仕事との兼ね合いもあり取りやすそうな単位に誘惑されるやつを人生周回遅れ(当社比)でやっている。雰囲気的に4年で卒業とかは目指さなくてもよいかな〜と思っているので今後もゆったりやります。学割で映画見ると神になった気分を味わえるのでよい。

まああとは家事ができなすぎて双方相談のうえで荒療治やり出してたり、細かいことはいろいろあるんですがあまりにもプライベートなので省略〜

今年の総括

それぞれうまくいったこともいかなかったこともあるけど、とりあえずいい1年やったわ。またよろしゅう〜というかんじ。

個別の振り返りだと、やっぱ技術方面で仕事に関係ない遊びをあんまりしてないのはよろしくないので、もっと精進せなな。

あとごめんけど去年に立てた抱負的なやつやれんかったで。すまんやで
まあこれについてはもうちょっと好き勝手やる時期なんかなと〜と感じている。変に絞らずに毎度体当たりして気になるものはやったらええがなって思ったので、収束させることを目指すのは時期尚早だったかも。

あと今年めちゃめちゃ感じたけど、フェイクにならない意思をこめた出力が定期的に自分を焼いてくるので書いて良かったなと思う。引き続きやっていくよ。

convto.hatenablog.com

来年も頑張りたいわね

来年の抱負

今年も抱負を考えたいんだけど、去年はスローガン的なやつにしたんだけどやっぱ多少振り返りづらいので今年は観測可能な目標にしようかな。

とはいえここで頑張った数字をつけるとなんかドタバタしたりしたときにやーめた!となって空中分解するので(N敗)、 どうしようもなくなったら最後の2週間本気だせば終わらせられるくらいの目標きめてざっと方向性だけ示すぞ というのをやってみたい。破滅したとしても12月から根性だせばギリギリ回収可能くらいな目標設定にすることで、最低限やりたかったことはなんかいい具合にやってくれることを期待している。

ここでいう2週間は出力最大の超人2週間です。2週間はカンで決めたけど、なんかちょうどいいんじゃないかなと思っている。どうなるかな〜

抱負くん、毎年いろいろ理由があって全然達成できてないので、こういう立て方する年があってもええやろ。

で、来年やりたいことは

  • [仕事] 認証/認可に関する出力を10本
  • [仕事以外の技術研鑽] 業務に関連しない技術の深掘り2本
  • [仕事以外の技術研鑽] OSSパッチ1つ
  • [仕事以外の技術研鑽] 本2冊(技術1, 読み物1)
  • [人生] 時間を決めて作業するのを1週間続ける
  • [人生] 5枚くらい絵も描きたいな

という感じにしようかな!今年は仕事に関連しない技術研鑽があんまりできなかったので、そこを少し厚めにした格好。

超人の2weekならギリギリいけるかいけないかくらいのいい感じの設定な気がするぞこれ。ちなみにここから単位を取ったりもするのでもうよくわからないわね

急に飛んできた人生のやつは、作業時間を持続可能かつ予測可能な形で生活のサイクルに組みたいっていう話と、絵を描くのを趣味くらいでつづけたいなというのを入れた。ただこれ人生でN敗しとるんで、多分習慣にはならん気がする。

まあ数字決めてやってればやってる期間はボーナスタイムみたいな感じになるので、一年にすこしでもボーナスタイムあったらいいじゃんね!というくらいの期待値っすな。僕は波あるタイプだからボーナスタイムはたまにきて気がついたら終わるんですが、能動的にボーナスタイムを起こせるだけでアドという考え

いきごみ

今年の目標は、高いところに辿り着くことことよりも、方向性だけ決めて最低限行動を引き出すことを優先するような建て付けにしている。

なんで達成しても自分がメガシンカするわけではないが、まあこういうのの積み重ねだからね。ドタバタして積めなかった〜みたいな嘆きより幾分ましになると思うので、いまから2024年の年末が楽しみや

そんなこんなで2024もやっていきますわ

LayerXに転職してました

会社で撮影したリニューアル後のロゴ

あんまり派手に公開していなかったけどじつは 2023/03/01 からLayerXに転職していました。
入社してから8ヶ月たってるけどまだ会社についての出力を(techblog以外)なにもしてなかったので書くか〜〜となった次第です。

いろいろやってたけど、具体的にやったこととかそこでの工夫とかは別途会社のブログとかにそのうち出力するかもなのでここでは言及しないつもりです。

ざ〜と8ヶ月振り返りつつ、個人的にいいな〜とおもってる部分を整理したりするぞい

8ヶ月の歩み

もともと入社当時はバクラク事業部のバクラク申請/バクラク経費精算を開発しているプロダクトチームに配属されました。

バクラク申請

bakuraku.jp

バクラク経費精算

bakuraku.jp

自分が使うサービスの開発に参加するのはだいぶ好きで、チームの打ち上げの経費精算とかで実際に使えるのは嬉しいし、自分がユーザーだと自分ごとで考えられるのでかなり良かったです。

そののち直近2ヶ月くらいでチームを移籍していて、いまは共通管理(認証やチーム構造/所属などの従業員マスタ系の情報などを管理するサービス)のプロダクトで頑張っています。
このチームは最近できた新しいチームで、いま絶賛PdM/EMらとともに現在の構成の整理や業務知識の獲得につとめています。たいへんだけど楽しい〜〜

8ヶ月間いろいろやっていたので、うまくいったことも、もっと綺麗に進められたな〜と反省してることもどっちもいっぱいあります。反省は次に活かしつつこれからもがんばろかなと思っています。

個人的には反省が多かった半期だとおもっているけど、半期締め会で新人賞ノミネートされたのは一定の価値提供ができてることがわかり嬉しかったです(なおノミネートのみで受賞には失敗しています)(またぼくは全然写真を撮らないことで有名なので写真も撮ってません)

あと、なんでかわからんけど社内では「ブルーアイズ組織図ドラゴン」とか「ドラゴン」と呼ばれています。なんで?*1

そうじてドタバタしていて大変なこともあったけど、とっても楽しく8ヶ月すごせたなという感じです。次に繋げたい反省もあるのでこれからも頑張るます。

いいものつくろうぜ、やっていこうぜ

とにかく顧客の課題を解決できるいいものつくっていこう、やっていこうという文化を強く感じており、そこはめちゃめちゃ噛み合ってると思う部分の一つです。

ぼく個人の価値基準として、いいものをつくることにかかわりたいニャンというのが強いモチベーションとしてあるのでここはめちゃめちゃめでたい

ユーザーの真の課題はなにか探究しようとする意思が浸透していて、それは行動指針から派生してより具体的に落とし込まれた羅針盤というものでも言及されています。面白いので読んだことない人はチラ見してきてください。

speakerdeck.com

課題の解決手段が複数あるなかで、「ユーザーの業務が減ること、楽になること」という観点で目線を揃えて解法の探索ができているのがめちゃめちゃよいとおもっています。
たとえばある機能について、必要としないお客さまにまで認知負荷を押し付けてないか?など、少しでも簡単に楽に使ってもらえるようなFBが日頃から相互にされています。

システム面でもenabling teamなどプロダクト開発者をエンパワーする横断組織があり、日々作られた基盤を使わせてもらったり、設計の相談させてもらったりめちゃめちゃお世話になっています。

type.jp

余談ですがこういう技術横断チームによくありがちなプロダクト開発チームとの壁みたいなのはかなり薄いほうだと思っていて、めちゃめちゃいいことだと思っています。

  • enablingがプロダクト開発に参加しつつプロダクトをエンパワーするとか
  • プロダクト開発側のメンバーが必要な機構をenablingと相談しつつ汎用的なものとして一緒に作っていくとか

みたいな動きが相互にあって、お互い境界を超えてる例が結構多くてとてもめでたい

いいものつくる、を支える文化

ぼくはいいものをつくっていくことを大切にしたいので、ぼくの目線では組織とか文化はそれを支えるための砲台のようにみえています。
(これは個々人の価値観によっても変わるとおもうので、あくまで僕の目線からはということを断っておきます)

ぼくの体感でめちゃめちゃよいなと思ういくつかの要素を紹介します。

情報がオープン

判断材料が増えるほど、考慮事項の見逃しなども減りより確度の高い判断につながるとおもっているので、各種情報がオープンなことにはかなり助かっています。

典型的には設計する時に関連箇所の過去の議論の流れなどがサルベージできるとめちゃめちゃ助かったりする、とか。部署を跨いだ情報とかも思わぬところで役にたったりするのでプールされてる情報は多ければ多いほど助かります。

組織としてはオープンであることだけじゃなくて実際に情報が役に立つかまで含めて課題意識を持っていて、ちょうど入社したときくらいに「社内の情報が検索しづらいのでnotionをいい感じにしよう」みたいな動きがあったりしました。

役に立つ情報は意識して残していこうよ!方向へのアクションもあって、開発まわりだと設計判断等をADRに残す文化も少しづつ広まっています。

さてどの程度まで情報がオープンなの?というとほんとに個人情報に関わる部分とか以外はだいたい見れて、経営会議の議事録とかも見れます。(もちろん情報区分など考慮して伏せるべき情報は一定フィルタされたりはしうる)

プロダクトのコアの戦略にまつわる部分などについても議事録がほぼ公開されているため、システムを作る上で「そういうパターンも考慮しないとな」とか「なくなっちゃうかもしれないならめっちゃ作り込まなくてもいいかもな」みたいな参考にできることがありうれしいことが多いです。

経営戦略観点の話などは時間軸が遠いものもあり、その時点では不確実性が高いものも含まれたりしますが、どういう方向に進みうるのか可能性の段階から情報が流れるのはとても助かってます。

相互に誠実

さっきちらっと顧客の課題しっかり向き合ってるよ、という話をしたんですが、社内メンバーに対しても誠実さを感じていて、うまく言語化しきれてないけどめちゃいいと思っているので書きます。

「なんかやることになっていて、自分でもあんまり意義に納得できてないけどやる」みたいなことがあんまりない*2のが嬉しいです(ぼくは納得できないことをやってるときは出力が下がる傾向があるため)

これは「めでたいね〜」で終わる話ではなくて、逆にいうと説明された側も納得できないなら納得できるまでバトれよということで、関わる人が相互に責任を果たすことで維持されています。役職あろうがなかろうが全員がやるべきこととして浸透している気がしています。

実際の具体的なコミュニケーションに落としていうと、「なんかモヤモヤしてます!その部分こうやってかえたほうがいいのでは?」を表明する人が多いです。ちゃんとpublicかつ参加者が多い場で議論が進むので、組織全体で誤った方向に進みづらくなっている体感があります。

そういうと摩擦が多くてなにかを推進するのがめんどくさそうな感じがするけど、個人的にはあまり摩擦は感じてないです。
大筋いいものつくりたいよね、というのは共通していて、同じ方向目指してよりよいものに近づけるためにいろんな目線から叩いてるイメージ

ぼくも言ってるし言われているけど、実際すごく助かっています。成果物の品質が上がるのが正義!

システム面の改善サイクルも一定まわりだしていること

どの組織にもシステムには一定課題があるとおもいます。各プロダクトも成長する中で業務領域の拡大に伴い課題も増えていくし、その中で価値をデリバリーし続ける必要があるので、やはりLayerXのバクラク事業部が抱えるシステムにも多くの課題があります。

そんな中でも各プロダクトで課題の改善活動を行うイベントを設けたり(これは誰かが記事を書いてくれるかも)、enablingチームがプロダクトチームと協力しつつ全体最適につながる動きをしてくれたり、少しづつシステムの改善サイクルがまわり始めてきたように感じます。

とはいえこのへんバランスはやっぱむずかしくて、価値提供のスピードを守りつつもっと自分自身貢献していきたいなとおもっている部分です。

中はめちゃめちゃドタバタしている

ここまでで、いいものを作る砲台としてのLayerXは個人的にはけっこう性能がいいと思うし、自分自身やってて楽しいぞい!みたいなことを話してきました。

いいことばっかいうのはフェアじゃないので、いいものをつくる、を阻害していると感じてる要因についても言及しておきます。端的に言うとめちゃめちゃバタバタしていて困っています。

おちついて考えれば当たり前なんですが

  • 各プロダクトどんどん成長していて、いままで出てこなかった新しい課題とかにも向き合わなきゃいけなくなっている
  • コンパウンドスタートアップやっていくぞ! なので、そんななかでもプロダクトはどんどん増える
    • ポケットを叩くとビスケットがふえる、半年に一つプロダクトもふえる
  • よい価値を提供するにあたってプロダクト間の連携は必須だが、数が増えるとどんどん複雑になる
  • より多くの人の業務を簡単/楽にしていくために向き合う顧客の層もどんどん増える
    • 商慣習がことなったり組織規模が異なったりすると抱えている課題も違うので、向き合う問題領域が広くなる
    • システムが素直な拡張に耐えられないこともある。スピードを意識しつつ負債を残さず解決できるように頑張る
  • あたらしい課題だけじゃなくて、すでに抱えている課題も解決していかなきゃいけない

みたいなことが内部でブン回っており、それはそれはバタバタしています。

チームやプロダクトが直面している課題の数がとにかく多いのが問題になり出している気がしています。

プロダクトが多くの課題を抱える中で、限られたリソースのなかで頑張って取捨選択して順に倒していっていますが、「よいものをつくる」に関連するいろいろな要素が少しづつ落ちかけていっているような印象を感じています。価値提供のスピードを落とさず、システムにまつわる諸課題についてもしっかり改善に繋げていきたい...

いまは中にいる人が馬力を出して頑張ってるけどとにかくバタバタしているので、よりよいものをつくって価値をとどけていくためにも、もっと多くの方の協力を必要としています。

いいものつくりたいひといっぱいきてくれ〜〜〜〜一緒にいいものつくろう〜〜〜〜

さいごに

ワイは元気にやっているし、転職してからかなり楽しくやっています!これが一番すね

いままでいろんな人に世話になってきたし、また一緒に働きたいと思ってる人もいっぱいいるけど、結局僕が言えることって元気でやってるよ〜〜〜以外にないんですよね。
いまの職場が万人に合うわけでもないし、すくなくともぼくはこういうとこが嬉しいだの、こういうとこが困ってるだの言う以外にできることないので。とりあえずぼくは楽しいですよ。

元気でやってる、楽しくやってる、頑張ってる!なによりそれがめでたいんじゃなかろうか

知り合いで燻ってる人いたら飯でもいきましょうや!Twitter(現X) DMでもなんでもお待ちしてます

We are hiring!

もし興味もっていただいた方いらっしゃればぜひカジュアル面談などしましょう〜

jobs.layerx.co.jp

jobs.layerx.co.jp

こっちは採用関連のページです、こちらも興味あればぜひ〜

jobs.layerx.co.jp

*1:「convtoドラゴン」みたいな亜種も観測されている。なんで?

*2:「あんまりない」なので disagree and commit みたいなのもゼロではないです。そういうケースでもpublicな場で議論して擦り合わない観点を相互に明確にした上で行われることが多い