taiyoh's memorandum

@ttaiyoh が、技術ネタで気づいたことを書き溜めておきます。

ベース用ラインセレクターを自作したお話

Untitled

去年暮れに某オクで買ったアップライトベースと、以前から持ってるエレクトリックベースをステージ中に簡単に切り替えたいというニーズが僕にありまして。 それならABYボックスや2ch入力に対応したプリアンプを買えばいいのですが、

  • 練習時、音を出しながらペダルチューナーでピッチを確認したい
  • プリアンプやコンプをかけっぱなしで使う想定なので、できればそれら用のエフェクトループが欲しい
  • 持ち替えの際にノイズが漏れないようにミュートできるようにしたい

という要望もあり、ここまでくると2ch入力できるスイッチャーを探した方がお手軽なんですね。 でも、そもそも2ch入力のスイッチャーは選択肢がほとんどなく、高い上に嵩張るのでできれば避けたい。 あとループもまずは1ループあればいい。 ということで、一旦自分がどんなものが欲しいのかを書き出してみることにしました。

Untitled

これを書いたところで何故かふと「これは、ちょっと頑張れば自分で作れるのではないか」と思ってしまい、そこからはもう一気に製作モードに。 大急ぎで自作エフェクター関連のサイトを読み漁り、必要そうなパーツを買い集めてきました。 まずは3PDTスイッチの扱い方から覚え、3PDTスイッチとLチカを連動させ、そこから更にA/Bスイッチができるようにし、と徐々にできることが増えていった。

Untitled

ただ、一つ想定外だったことがあって、僕の上述のスケッチではA/B切り替えのあと、チューナー向けにパラレル出力するというものだったんだけど、 いざその回路を組んで試してみたら、パッシブのベースの音量が明らかに落ちたんですね。 まあ、それは当たり前で、パッシブベースはそもそも電流の量が少ないんだから、パラレル出力で更にその電流が分割されてしまったらボリュームが落ちるのはあたり前。 ということで、急遽バッファ回路を用意し、パッシブのベースはバッファを通して出力することに。

101010.fun

バッファ回路はほぼここのサイトに載ってるものを使わせてもらいました。 ただ、いざこの回路を通してみたところ、思ったより低音がスカスカになっていて結構ショック。他のサイトや本で調べた結果、前段のコンデンサの容量を1μF(サイトに載ってるものの10倍)にしたことで、まあそこそこな感じになりました。もうちょっとコンデンサの種類は買い揃えて、いろいろ聴き比べた上で決めてもよかったかもしれない。

Untitled

ケースの穴あけは本当にギリギリまで後ろに引き伸ばし、もうあとは出来上がった回路をケースに取り付けるだけ、みたいなところまできてからようやく着手。 ただ実際は、各種ジャックを取り付けてから長すぎたコードを全部切ってほどほどの大きさに直したり、フットスイッチで無駄な取り付け方になってるのを修正したりで、結局かなりの箇所は作り直しました。

Untitled Untitled

そんなこんなでおおよそ半月ちょいかけて、ようやく自分専用の自作ラインセレクター(+バッファ+チューナー用パラレルアウト+1ループ+ミュートスイッチ)が完成しました。 Untitled

これはマスキングテープの上からマジックで書いただけだけど、これはこれでちょっとロックっぽい雰囲気あって好き。 ただ、その後ラベルライターが届いたので、

を使って貼り付けました。で、冒頭の写真に至る。

今回一番衝撃だった学びはバッファ回路前段のコンデンサについて。 how toの載ってるサイトではなかなか「なぜ低音部を通すのにコンデンサの容量を上げる必要があるか」ということはなかなか書いてなかったけど、

この本がKindle Unlimitedになっていたので早速入手して読み進めたところ、P220に「容量性リアクタンス」という言葉と共に「Xc = 1/2πfC」の記述が。 これを読んで一気にこの部分の理解が進みました。
本来ならこうした電気回路の基礎知識を学んだ上で作れ、って話なのは承知してるんですが、僕の性分は「パッション重要。熱が冷めないレベルでひたすら手を動かしてまずは物を作って、そのあと理論で肉付けする」というものなので、今回はこの進め方でよかったと思ってます。

goのdriver.DriverでAWS X-RayによるTracingとSQL Commentを両立させる

aws-xray-sdk-goxray.SQLContext を利用することで、 AWS X-Ray のtracingにSQLを発行した際のセグメントを載せることができます。

発行したSQL文はセグメントの SQL タブから確認することができます。ただもうちょっと欲張って、実行箇所をSQL Commentとして埋め込むことでセグメントを見れば発行箇所がわかるようにしたいと考えました。

Go言語におけるSQL Commentの埋め込み方はSongmuさんの以下のブログが詳しいです。

songmu.jp

まずはSQL Commentの埋め込み部分について、以下のように実装してみました。

package myapp

import (
    "context"
    "database/sql"
    "database/sql/driver"
    "fmt"
    "runtime"
    "strings"
    "sync"
    "time"

    "github.com/aws/aws-xray-sdk-go/xray"
    proxy "github.com/shogo82148/go-sql-proxy"

    // for using mysql driver
    _ "github.com/go-sql-driver/mysql"
)

type proxyHooksManager []func(ctx context.Context, stmt *proxy.Stmt, args []driver.NamedValue)

func (hooks *proxyHooksManager) Add(fn func(ctx context.Context, stmt *proxy.Stmt, args []driver.NamedValue)) {
    *hooks = append(*hooks, fn)
}

func (hooks proxyHooksManager) Run(ctx context.Context, stmt *proxy.Stmt, args []driver.NamedValue) (interface{}, error) {
    if stmt.Stmt != nil {
        return nil, nil
    }
    for _, fn := range hooks {
        fn(ctx, stmt, args)
    }
    return nil, nil
}

func (hooks proxyHooksManager) PrePrepare(ctx context.Context, stmt *proxy.Stmt) (interface{}, error) {
    return hooks.Run(ctx, stmt, nil)
}

func (hooks proxyHooksManager) PreExecAndQuery(ctx context.Context, stmt *proxy.Stmt, args []driver.NamedValue) (interface{}, error) {
    return hooks.Run(ctx, stmt, args)
}

var (
    proxyHooks  proxyHooksManager
)

func init() {
    const (
        ignorePath = "/path/to/myapp"
    )
    proxyHooks.Add(func(ctx context.Context, stmt *proxy.Stmt, args []driver.NamedValue) {
        var (
            pc   uintptr
            file string
            line int
        )
        // 適宜調整してください
        for i := 1; i < 100; i++ {
            pc, file, line, _ = runtime.Caller(i)
            if !strings.Contains(file, ignorePath) {
                break
            }
        }
        fn := runtime.FuncForPC(pc)
        stmt.QueryString = fmt.Sprintf("/* %s (%s:%d) */ %s", fn.Name(), file, line, stmt.QueryString)
    })
}

proxyHooks という変数を用意したのは、SQL Commentを埋め込むのと同じタイミングで、テストからも何かしらの処理の注入して実行できるようにしたかったからです。 aws-xray-sdk-go では attrHook という変数でテスト時の処理の注入を可能にしていて、それでも特に問題はないですが、sliceで保持しておけばテスト用の挙動かどうかという境界は無くせるかな、と。

あとは sql.Open を行う際に1度だけ実行するコードを定義します

// これを事前に定義しておく
var driverSetup sync.Once

func Open(dsn string) {
    driverSetup.Do(func() {
        // わざとOpenして `*sql.DB` のオブジェクトを取得する
        db, err := xray.SQLContext("mysql", "")
        if err != nil {
            panic(err)
        }
        defer db.Close()
        sql.Register("mysql:myapp", proxy.NewProxyContext(db.Driver(), &proxy.HooksContext{
            PrePrepare: proxyHooks.PrePrepare,
            PreExec:    proxyHooks.PreExecAndQuery,
            PreQuery:   proxyHooks.PreExecAndQuery,
        }))
    })

    db, err := sql.Open("mysql:myapp", dsn)
    if err != nil {
        panic(err)
    }

    // snip...
}

キモはDSNを指定せずに、わざと xray.SQLContext を実行して *sql.DB のオブジェクトを取得していることで、 ここで得られる driver.Driverproxy.NewProxyContext の第一引数に指定しています。 そしてアプリケーションが利用する *sql.DB を取得する際は、 proxy.NewProxyContext で指定したドライバー名を使用します。

f:id:sun-basix:20210726181037p:plain

アプリケーション側が使用する *sql.DB が持っている driver.Driver は、こんな入れ子構造のオブジェクトを利用する形になります。 これにより、最上段の go-sql-proxy によるドライバではSQL Commentを埋め込み、処理を移譲した先のX-Rayのドライバではtracingを行い、更にそこから移譲した先のmysqlのドライバで実際に接続先のDBに向けてクエリを発行する、という流れになります。

今回はX-RaySQL Commentの組み合わせでしたが、ドライバの移譲を重ねることで機能を足すことができるので、New Relicによる nrmysql 等でも同様のアプローチでが可能だと考えています。

S2 Geometryライブラリで遊んでみる

 このエントリはSmartDrive Advent Calendar 2019の一環です。

 Googleが2017年に出したS2というジオメトリ系のライブラリがあり、それのGo実装があるので遊んでみました。

ライブラリの公式サイト

s2geometry.io

Go言語での実装

github.com

 ジオメトリライブラリにはその目的によってアルゴリズムや実装がいくつかあると思いますが、よく使われる用途というと、緯度経度の情報の検索容易性を上げたりデータのサイズダウンを意図したものが多いと思います。この手のライブラリでは、日本だとgeohexをご存知の方は多いのではないでしょうか。geohexのようなGeohash系アルゴリズムの基本的な考え方は、地図上を多角形のタイルで隙間なく敷き詰め、そのタイルの大きさが小さければ小さいほど情報の精度が上がっていく、というものです。そしてそのタイルを使った操作によって、計算を単純化して求めやすくします。

 さてS2についてですが、敷き詰めるものは「Cell」と表現されていて、これは四角形で構成されています。また大きな特徴として、Cellは二次元の地図ではなく真円に対して投影されています。これらを総合して、ある程度計算量を落としてアルゴリズム自体を簡易にしつつ、その上で球全体の歪みを極力少なくするという辺りを狙って設計されているそうです。
 S2についての更に詳しい解説は、Misreading Chat #50「Geodesic Discrete Global Grid Systems」をお聞きいただけますよう、どうぞ宜しくお願いします。

 個人的にですが、S2の魅力はそうしたスケーラブルさだけでなく、APIの豊富さにもあると思っています。そこで、良くありそうな事例を具体的な数字やコードを交えて一つご紹介したいと思います。

 弊社の現在の所在地は日比谷のNTTビルにありますが、ここを中心としていくつかの周辺駅をピックアップしておきます。

f:id:sun-basix:20191212123042p:plain

 今回は、「日比谷駅」「有楽町駅」「銀座駅」「東銀座駅」「新橋駅」「内幸町駅」「虎ノ門駅」「霞ケ関駅」「桜田門駅」を探索対象とし、ピンを立てた座標を利用します(ピンの位置はGoogleMapでの検索結果を利用したものです。。。)。  ここから周囲500m以内の駅をピックアップしたいなと思ったとき、先ずは RegionCovererというAPIを利用します。  このRegionCovererというのは、ある地図上に指定した図形に対して、その図形を確実に埋めるセルのリストを返すものです。ただこの時、セルの総個数やレベル(セルの大きさ)の範囲は固定しておく必要があります。ここで注意すべきなのは、得られたセルのリストによって構成されるエリアというのは、必ずもともと指定した図形よりオーバーサイズになります。そのため、指定したセルのレベルによっては、本来500m以上離れたポイントなのに検知される、ということがあり得ます。

f:id:sun-basix:20191212123106p:plain
セルのレベルを上げ、総数を増やせば限りなく指定した図形に漸近していくのです。。。

 当然ながら、RegionCovererAPIには制限があり、無限にセル数やレベルを指定することはできません。

f:id:sun-basix:20191212123129p:plain
500mより大幅に大きいセルのレベルを指定するとこうなる

 またこのように、あまりにセルを大きくしすぎるとミスヒットが増える要因にもなるので、ここはアプリケーションの計算量と相談しながら調整していく必要があります。

f:id:sun-basix:20191212123150p:plain
この辺がほどほどかな

 ここまでのスクリーンショットは、Sidewalk Labsによるデモサイトを利用させていただきました。これ、S2の雰囲気を知るのにとても分かりやすいです。

s2.sidewalklabs.com

 今回はCellレベルをmin, maxともに14に設定して進めてみたいと思います。勿論、maxをもっと上げてより精度の高いエリアを割り出すこともできます。下記のコードの方針は、

  • まずはRegionCovererによって取得できたCellリストのそれぞれのトークンと、探索対象の地点のCellレベル14のトークンを比較する。マッチするCellがあったら次の段階に進む
  • 中心点(オフィス)と各探索対象地点の距離を求める。もしその距離が500m以内であれば [HIT!!!]をつける

となっています。

https://play.golang.org/p/ZSKFlauQKOl

package main

import (
        "fmt"

        "github.com/golang/geo/s1"
        "github.com/golang/geo/s2"
)

type station struct {
        name   string
        latlng s2.LatLng
}

func toSpecifiedCell(ll s2.LatLng) s2.CellID {
        return s2.CellFromLatLng(ll).ID().Parent(14)
}

// https://www.vcalc.com/equation/?uuid=e6cfcccb-da27-11e2-8e97-bc764e04d25f
const earthRadius float64 = 6378137 // meter

func main() {
        office := s2.LatLngFromDegrees(35.671262, 139.757476)
        stations := []station{
                {"Hibiya", s2.LatLngFromDegrees(35.674867, 139.759596)},
                {"Yurakucho", s2.LatLngFromDegrees(35.674865, 139.762818)},
                {"Ginza", s2.LatLngFromDegrees(35.671706, 139.764472)},
                {"Higashi-ginza", s2.LatLngFromDegrees(35.670010, 139.766721)},
                {"Shimbashi", s2.LatLngFromDegrees(35.666456, 139.758267)},
                {"Uchisaiwaicho", s2.LatLngFromDegrees(35.669388, 139.755331)},
                {"Onarimon", s2.LatLngFromDegrees(35.660473, 139.751265)},
                {"Toranomon", s2.LatLngFromDegrees(35.670113, 139.750109)},
                {"Kasumigaseki", s2.LatLngFromDegrees(35.674789, 139.751890)},
                {"Sakuradamon", s2.LatLngFromDegrees(35.677265, 139.751376)},
        }

        officePoint := s2.PointFromLatLng(office)
        // 地球は(本当は楕円だけど計算が複雑になるので)球形なので、二次元の地図だと円に見えるが、
        // 実態は球体に円を被せるようになっていて、その形が帽子に似てることから「Cap」と呼んでいる。
        // その「帽子の深み」は「求める円の半径/地球の半径」によって算出できる
        officeCap := s2.CapFromCenterAngle(officePoint, s1.Angle(500/earthRadius))
        regionCover := s2.RegionCoverer{
                MinLevel: 14,
                MaxLevel: 14,
                MaxCells: 16,
        }
        coverings := map[s2.CellID]struct{}{}
        for _, cellID := range regionCover.Covering(officeCap) {
                coverings[cellID] = struct{}{}
        }

        for _, st := range stations {
                // coveringsにないということは脚切りすべき対象なので、下記の計算はスキップする
                if _, exists := coverings[toSpecifiedCell(st.latlng)]; !exists {
                        continue
                }
                stPoint := s2.PointFromLatLng(st.latlng)
                // Capの捉え方と同様に、二点間の結び方は直線ではなく、地球が球形であることに影響を受けている。
                // 具体的には、単位球面における2点という扱いとなり、その距離とは弧の長さとなる。
                // その弧の長さに地球の半径をかけることで、実際の近似の距離が算出できる。
                angle := officePoint.Distance(stPoint)
                distance := angle.Radians() * earthRadius
                hit := ""
                if distance <= 500 {
                        hit = " [HIT!!!]"
                }
                fmt.Printf("[%s] distance: %f%s\n", st.name, distance, hit)
        }
}

/*
// 出力結果

[Hibiya] distance: 444.748778 [HIT!!!]
[Yurakucho] distance: 627.884061
[Ginza] distance: 634.597277
[Higashi-ginza] distance: 847.599459
[Shimbashi] distance: 539.762741
[Uchisaiwaicho] distance: 284.865174 [HIT!!!]
[Toranomon] distance: 678.393858
[Kasumigaseki] distance: 639.788421
*/

 上記の算出ロジックにより、オフィスから500m以内にある駅は内幸町駅(約285m)と日比谷駅(約445m)だと分かりました!
 今回はCapを利用した円形の探索を行いましたが、矩形やポリゴンでの探索も可能になっています。なお、上記の出力結果から御成門駅桜田門駅が含まれていませんが、これはRegionCoverer.Coveringメソッドの結果に含まれるCellIDにこの2つの駅が所属するCellIDが含まれてないので、事前に除外されているという構図です。

 今回のように中心点や探索対象が全てオンメモリにいるのであれば、以下のようなコードで同様の探索も可能です。コード量としてはこちらの方が少なくなります。
(探索対象の駅の各地点がofficeを中心としたCapの中にいるかどうかをContainsPointメソッドによって直接判定しています)
https://play.golang.org/p/GZgk7a2csCj

 スマートドライブではこんな感じで、地図関連のライブラリについても定期的に調査していきたいと思っています。
 弊社もまた全職種募集しておりますので、是非お気軽にお声がけいただく!

smartdrive.co.jp

git tagを活用してリリース工程を簡略化する

 このエントリは、SmartDrive Advent Calendar 2019の一環です。今回は僕がメインで担当しているプラットフォームプロダクトでのリリース周りについてお話していきます。
 僕が入社して一年以上経ちますが、リリースに伴うフローは以下のようになっていました。

f:id:sun-basix:20191212110932p:plain

 オレンジの枠が手動で実行する部分で、緑の枠がJenkinsのpipelineによるフローです。リリース時でなければtag打ち等の工程は必要なく、CIが終了して開発環境に自動的にデプロイされるのを待つだけです。一応、これをGitHub flowの名目で続けていました。ただこの「GitHub flow」による開発体制には大きく2つの問題があったことに気付きました。

  1. デプロイを始めるまで定形化した手作業がいくつかのあるのと、開始できるまでのリードタイムが長い
  2. 開発環境によるチェック工程が省かれていて、masterマージしても即リリースできる体制になってなかった

 まず定形作業とリードタイムについて、このフローチャートで示されている諸々の工程を終えてデプロイ作業を開始できるまで、CIの待ち時間含めて15分ほどかかっていました。その為に「大した変更じゃないから次にリリースする誰かに任せよう」という心理がメンバー間で働いた結果、masterブランチなのにリリースとの差分が大きくなることがよくありました(よくない)。
 また検証体制について、開発環境でのチェックののちにリリース、というのをmasterブランチ上のみで行っていたため、必然的にリリースできないmasterの状態というのが度々発生していました。

 これが積み重なった結果、実質週一回のリリースみたいな流れが徐々にできてきて、GitHub flowとは何だったのか。。。という気持ちに。
 一番困ったのは、ご想像の通りmasterと本番との差分がそれなりにある状況で本番側でトラブルが発生し、hotfixを作成しないといけないときでした。その時の手段は割愛します。ただ、割と最近の話です。
 こうした諸々を改善するためいくつかの方策を講じ、現在のフローは下の画像のようになりました。

f:id:sun-basix:20191212111037p:plain

 まず大きくは、もともとGitHub flowを掲げていたんですが完全に形骸化していたので、一時的にですがgit flowに切り替えました。これは現状のリリースのペースを定型化するだけでなく、先述のようなイレギュラーな対応をやりやすくするのと、Jenkinsのpipelineを分解する目的がありました。
 git flowの導入に続いて、Jenkinsのpipelineの分解を行いました。docker imageのビルドはCIを待たずに行っても何も問題ないはずで(仮にCIが落ちるのだとすれば直して再度リリースフローを走らせればいい)、思い切って省いたことでこのリードタイムを大幅に削減しました。このためにrelease tagからdocker imageの作成とpushだけを行う専用jobをJenkins上に作成し、GitHubのWebhookをjob triggerとしています。

f:id:sun-basix:20191212111108p:plain

 WebhookはBranch or tag creationのみチェックをつけています。tagと関係ないブランチの作成時もjobが起動してしまうので、job内のステップでjqでjsonの中身をチェックしていて、ref_type != tagだったら後工程をスキップするようにしています。tag creationだけのイベントトリガーが欲しい。。。
 また、git checkout <タグ名>でコードを固定化した状態でビルドを行うようにしたので、ビルド時のcommit hashは期待したものと確実に一致するようになったのも地味に大きいです。以前の運用だと、masterブランチのcommit hashと指定されたtagのcommit hashが一致しない可能性が常に付き纏っていました。

 あとは11/13に遂に正式リリースとなったGitHub Actionsを採用し、goreleaserを使ったフローは自動化しました。

github.com

 このREADMEに書いてあるYAMLはほぼほぼコピペで採用させてもらっていて、起動トリガーだけtag push時に絞っています。

name: Goreleaser runs when new tag was pushed
on:
  push:
    tags:
      - v*

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@master
      -
        name: Set up Go
        uses: actions/setup-go@master
        with:
          go-version: '1.13.3'
      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v1
        with:
          version: latest
          args: release --skip-validate --rm-dist
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

 さて、今回の話の発端なのですが、このtogetterのページを何度か読んでいて、新しいリリースフローへの変更のアイディアというかモチベーションが出てきた、というのが大きいです。ありがとうございます。

togetter.com

 しばらく僕が実質リリースマネージャ的なことをやって、各所との調整に疲れてきたというのもあります。また、最近のGitHub flowは以前と少し違うという話も聞きました。

guides.github.com

 この辺を踏まえて、「tagを打ったらどこの環境に対してもリリースできる」というシンプルなルールを適用できるようにして、デプロイ作業に移れるまでのリードタイムを短くしたというのが今回の取り組みになります。少なくとも僕がこのリリースフローで2〜3回行ってみたところ、例の心理的な億劫さはそれなりに軽減されたと感じました。あとは、PR authorにリリースマネジメントをお願いできれば、リリースに伴う負担を僕一人が負うことも減ってくるので、git flowを終わりにして、もっと素早いデリバリが実現できると睨んでます。この辺は年明けから履行予定です。

 引き続き、ストレスのなるべく少ない、素早いCI/CDについては模索していくつもりです。

 弊社もまた全職種募集しておりますので、是非お気軽にお声がけいただく!

smartdrive.co.jp

「7つの習慣」読了

完訳 7つの習慣 人格主義の回復

完訳 7つの習慣 人格主義の回復

 何年も前から存在は知ってたけどなんとなく避けていて、ここ最近になって急に「読むべきだ」という気持ちに変わったので通勤中にコツコツ読んでいた。
 やはり、読んで良かった。
 昔から自己啓発系の本は斜に構えている事が多かったけど、これは本の中で書いてある通り、「小手先のテクニックではなく、原理原則に基づいて生きていくにはどうすればよいか」という観点に忠実だった。この観点は、自分が常々「小手先ではなく、根本的なスキルを身につけたい」と思っていた自分の感覚ともマッチした。

 読みながら、心に留まったことや記述を受けて考えたことを手帳に書いてた。くれぐれも、これはサマリでも新解釈でもない。つまり、誤読した結果もここに書くことになると思う。

4/1

人との接し方や生き方について「個性主義」と「人格主義」の大きく2つのパラダイムがあって、
7つの習慣では「人格主義」の方に強く焦点を当てている
4/3

一方的な依存ではなく、自立し、その上でお互いに「依存」しあえるような関係になる

(第一の習慣について)
主体性とは、インプットに対して反応を自分で選択すること。そしてその反応に責任を持つこと。
4/5

(第一の習慣について)
主体性の本質とは「決意」し「約束」し、それを「守る」ことだ

(第二の習慣について)
「終わりを思い描くことから始める」というのが、
アジャイル開発におけるDoD(Definition of Done)と通じるものがある気がする
4/10

(第二の習慣について)
イメージを膨らませてあるべき姿やゴールを想像することを「知的創造」と名付ける。
これは具体的に現実世界に反映させる「物的創造」と名付ける創造活動より先に行われるものだ。
この知的想像を文章に変換したものが「ミッションステートメント」と呼ぶ宣言文となる。
(つまり、ミッションステートメントを遂行することは第一の習慣である「主体性」に紐付いていく)
4/16

(第三の習慣について)
時間のレバレッジを利かせる。
重要かつ緊急なタスクに追われるだけでは疲弊していく。
重要だが緊急ではないタスクの時間を確保できるようなスケジューリングを行う。
スケジューリングの際、自分が被っている帽子(=ロール)に応じて第二領域の時間を確保することを念頭に置くこと。
重要でないタスクに時間を割かないように、振る舞い方を工夫する。
「ロール」は、自分作成したミッションステートメントと関わっている
4/20

(第四の習慣について)
信頼口座を潤沢に
4/22

(第四の習慣について)
「信頼の預け入れ」とは
- 誠実さを示す
- 小さな気配り
- 約束を守る
- 理解する
- 期待を明確に
- 悪かったら心から謝る
4/24

(第四の習慣について)

内的な思考パターンと外的な行動パターンは採用の方法が少し違う。
思考パターンは原則を重視し、行動パターンは相互の関係が良好になるように動く。

リーダーシップとは何か、というと、Win-Winの原則に忠実に、
議論やコミュニケーションを恐れない、そして妥協点なり第三案を受け入れる、ということだろう。
5/1

(第一〜第三の習慣を振り返って)

行動を変える→どうすれば行動が変わるか考える→考え方を変えるにはどうすればいいか考える
みたいに読み替えられそう

(編注:このメモは精度が粗くて、
当時は第三の習慣に向かうにつれてどんどんインナーに向かっているイメージがあった。
今はそうは思ってなくて、自立の為の心技体のようにイメージしてる。
第一の習慣は主体的な行動なので「体」、
第二の習慣はDoDをイメージするので「心」、
第三の習慣はDoDを遂行するための取捨選択なので「技」、
とそれぞれ言えると思う)
5/7

(第五の習慣について)
傾聴の話、自分は果たしてできてるのか?
共感することでお互いに冷静になれる。
感情的なやり取りには、自分が寄り添う
5/10

(第六の習慣について)
シナジーは、自分の意見を取り入れてもらうことではなく、
互いに思いもしなかったアイディアにお互い納得することだろうか

(第七の習慣について)
(乳幼児の)子育て中の人って、運動の時間をどうやって確保してるのか?
5/11

(第七の習慣について)
肉体:
運動して鍛える
精神:
心の動きをある程度コントロールする術を身につける
またレジリエンスを高める
知性:
日々勉強。。。?
社会・情緒:
外部とのつながりや共感

 あとがき的なセクションで、著者ですらすべてを完璧に実践し続けることはできない、と書いていたのがとても印象的だった。身につけることがゴールではなく、より良い人生になるように自分のあり方、振る舞い方をほんの少しでも変えていくように日々考え続けることに意味があるのだろうと腹落ちした。

このGW中に読んだ本

 このGW中は、なんか「チーム」というのがキーワードになってたように思う。
 最近特に、個人で取り組むことにある種の現界や物悲しさを感じるようになってきて、自分の意識や取り組み方を(先ずは)少数の集団構成である「チーム」にどうやって押し広げていったらよいかを考えることが増えてきた。

Team Geek ―Googleのギークたちはいかにしてチームを作るのか

Team Geek ―Googleのギークたちはいかにしてチームを作るのか

 Team Geekは実は読んだことがなくて、HRTという言葉しか知らなかった。読んでみて、

  • 個人に対して
  • チームに対して
  • 上司(チームリーダー)に対して
  • 不和のチームメンバーに対して
  • 組織(チームより大きな括り)に対して
  • ユーザに対して

 HRTを軸として、それぞれボトムアップで、誠実に対応しながらやるべきことを進めていくための実践集だと感じながら読んでいた。一般的な組織論ではなく、もっとプリミティブなレベルでのプロトコル集と言ってもいいかもしれない。敢えて突っ込んだ言い方をすると、良くも悪くも、ソフトウェアエンジニア一辺倒な人が手っ取り早くチームや組織と歩調を合わせる為のhackishな手法ではある。が、右も左も分からない自分みたいな人にとっては、形だけでもそこそこな振る舞いができることが期待できるので、とても有用に感じた。特にグッときたのは第4章で、有害な人を排除するのではなく、有害な振る舞いを排除する、という趣旨を読んでハッとした。自分の視座が低いせいもあり、ついつい振る舞いとその行動を起こしてる人間を繋げて考えてしまうことが多いので、絶対にこの思考は改めなきゃ、と自分に対して危機感を感じた。
 5章以降、読み進めるのにだいぶ心理的な負荷が高かったが、多分それは自分がこの視点まで上がってないんだろう、というのが何となく分かる。
 そういえば、個人レベルから段々視点を上げていく構成は、「エンジニアリング組織論への招待」でもそうだったな。

THE TEAM 5つの法則 (NewsPicks Book)

THE TEAM 5つの法則 (NewsPicks Book)

 THE TEAMは、単純に広木大地先生がオススメしてたので読んでみることにした。
 チームが成功するのに必要な要素をA,B,C,D,Eの5つにうまくまとめた上で、その各要素は手法がいくつかあり、それぞれトレードオフがあるので一概に特定の手法に対して否定ないし肯定するのを断定すべきではない、というのがよくわかった。チームの特性や事業フェーズによって、どの手法を採用するかは様々に変わるだろう。
 これをある程度読み進めたところで、いざ自分の所属チームはどういう手法が合うんだろ、と考えたとき、そもそもチームの分析がある程度できてないと何もできないな、と痛切に感じてしまった。が、チームの分析が出来て理解が進めば、それだけでもチームにとって大きな前進になることは間違いないだろう。そしてまたTHE TEAMに立ち返り、to-beを明らかにした上でどの手法を取捨選択するのが自分たちのチームにとって最も効果のある手法なのかを確かめればよさそう。

 GW明けに、早速実践できることや試してみたいことが色々見つけることができた。

育休をもらっていました

 2/13に娘が産まれ、翌週から1ヶ月育休をいただいていました。 控えめに言って、娘がめっちゃかわいい。よく泣き、よく眠り、よくミルクを飲み、日々少しずつ成長しているのを感じます。
 SmartDriveというベンチャーに入社して半年も経ってないですが、育休を快諾していただいた社長に感謝したいです。また、自分が抜けている間にタスクの肩代わりや分散をしてくれたチームメンバーにも感謝します。

育休所感

 産院からの退院に合わせて、僕も妻の実家にしばらく居候させてもらうことにしました。事前に友人たちから様々なアドバイスをもらったり、インターネット上の記事を読んだりしたので、少なくとも最初の一ヶ月でどれだけ妻と同じことができるかというのが重要っぽいのがわかったので、ひたすら率先して娘の面倒を見ていました。おかげで、最初は抱っこから始まり、おむつの交換、ミルク作り、寝かしつけ、沐浴と、多分母乳をあげる以外のことは一通りスキルが身についたように思っています。これでようやくスタートラインかな、と。
 また、妻の実家にお世話になったので、僕ら夫婦は妻の体調の回復と娘の世話にある程度集中でき、特に食事面については義理の両親にサポートしてもらえたのはとても助かりました。

 よく聞く話として、授乳を3時間おきに行わないといけないので夫婦ともに寝不足になる、というのがありますが、娘はもともと大きめに産まれてきてくれたというのもあり、夜中はよく眠りますね。ただ、生後一ヶ月以内は4時間以上間隔が開くと騒ぎ出していたので、そのタイミングで妻ともどもむくっと起き、オムツ交換をした後、妻は母乳を含ませ、僕はミルク作りを行う、という分担作業をしていました。夜は22~23時頃布団に入り、朝は8~9時から活動を開始していたので、5時間以上連続した睡眠は取れないものの、あからさまに寝不足でフラフラするということはありませんでした。ただ、じわじわと体力が削られてる感覚はありました。ただ、単に僕がほぼ24/7体制で部屋の中にいたので、体力が落ちただけなのかもしれません。

仕事との距離のとり方について

 育児に専念すると当然ながら仕事する時間がなくなる、という話を聞いていたので色々覚悟していたのですが、いざ産まれてみると、寝かしつけに成功すれば多少時間的な余裕ができるので、そのタイミングでできることはあるなと感じました。が、これはあくまで娘が(いい意味で)思ったほど手がかかってないというだけで、もっと要求レベルの高い赤ちゃんはいるはずですので、この感覚を一般論にするつもりはありません。
 育休期間全体を通して、会社のSlackは遅くとも1日以内に追うことができ、おおよその動向のキャッチアップはできていたと思います。育休終盤では、オムツ替え、ミルク、沐浴のタイミングでなければほぼリアルタイムに追ってました。最初の2週間くらいの間は、仕事するのもアレかと思ったので、会社のプロダクトの開発環境を改善するためのツールを書いてました(GitHub - taiyoh/toyhose)。これ結局育休期間中には完成しなかったなぁ。。。Clean Architectureを意識して書いてる分にはよかったけど、トランザクションを分割してsagaパターンとか段々細かいところに目が行き始めるあるあるパターンに陥ってますね。とりあえず「エイヤッ」と作るだけ作らねば。最後の2週間は会社でリリースしてる機能の一大リファクタリング構想を練っていて、コンテキストマップやコンポーネント構成を決めたり、ロバストネス図を書いてました。これでよりリファクタリングの際の方向性が鮮明になったはず。また、この期間中にパフォーマンス絡みの障害が発生してたのですが、原因はすぐに特定できたので、そのためのPRをサクッと作ったりしていました。

普段使っているミルクやオムツについて

 ミルクやオムツは、実は産院が用意してくれていたものからあまり変えていません。
 ミルクについてですが、もともと母乳育児にこだわるつもりはなかったのですが、特に生後1ヶ月までの間は母乳よりミルクを欲しがっていたのと、特に産院側で用意されていたビーンスタークで嫌がる素振りもなかったので、継続して自分たちでも購入しています。

 これ、Amazonよりも赤ちゃん本舗の方がずっと安いですね。使い続ける理由は割と消極的なんですが、そもそも他の粉ミルクも試供品もらってるのに、全然試してませんでした。ただ、ビーンスタークより味が濃かったり甘いものは、いくら安くても選択しないかも。
 オムツは、産院側で用意してもらっていたのはメリーズでした。その後一時的にパンパースにしていたのですが、新生児サイズからSサイズに切り替えるタイミングでメリーズに戻しました。正直なところ、メリーズとパンパースで比較してどちらが肌触りがいい、みたいなのはわからないです。夫婦揃って感覚が鈍いだけなのかも。ただ、この2つが他にためしたオムツより使い勝手やおしっこサインの視認性がよかったと感じました。  哺乳瓶は、当初はピジョンのスリムタイプを使っていましたが、生後三週間を過ぎて、ニプルの穴が新生児用だと小さすぎて授乳に1時間かかるようになってしまったので、慌てて1ヶ月用のニプルがある「母乳実感」のシリーズに切り替えました。  このシリーズのボトルは、プラスチックもガラスも耐熱性が高いのか、スリムタイプより冷ましづらくなっていますね。ただこれは仕方ないか。
 一応、スリムタイプ用のMサイズのニプルも買っているので、どこかのタイミングで試してみたいなとも思っています。

育児本について

 多分妻は当初からあまり育児本関連を買う予定はなかったと思います。が、元同僚のバズった記事をみて、「これは買おう」と説得しました。

srdk.rakuten.jp

 この本は妻も時々読んで娘の状態を確認したりしてるようです。
 あと実は、僕は以前から「考える生き方」という本を読んでいて結構感銘を受けたものがあったので、「シアーズ博士のベビーブック」も出産直前に購入しました。

考える生き方

考える生き方

完全版 シアーズ博士夫妻のベビーブック

完全版 シアーズ博士夫妻のベビーブック

 育児本を2冊も持っていてどうなんだ、という気持ちもなくはないですが、カラーでハウツー的に何かを知りたい時は「はじめてママ&パパ」の方を読み、もうちょっと科学的というか、数字を使って詳しく知りたい時は「シアーズ博士」の方を読むようにしています。これに加えて産院の助産師さんや保健師さん、妻の友人である先輩ママ達から色々なアドバイスももらえるので、育児方法については網羅的ではないにせよ、ある程度俯瞰的に見ることができる環境にあると自分では思っています。

育休明けのお役立ちグッズ

 育休明け前から自宅に戻り、徐々に自分たちだけで回していく生活がスタートしました。多分このフェーズで要求されてるのは、娘にかかりっきりにならず、娘が満足しつつ自分達も自分の時間を確保するためにできることを探すタイミングなのかな、と捉えています。
 まずは一番時間を占める抱っこについて。我が家では、僕が妻の友人から借りたスリングを使い、妻はErgobabyを使っています。

 ちょっと外に散歩に出る時は妻がErgobabyで抱っこすることがほとんどです。妻はこちらの方が慣れてるらしい。僕は自宅作業する時にスリングで娘を抱っこしています。

 あと、自分の親から「バウンサーは絶対あった方がいい」と言われたので、買ってもらいました。

 使ってみて感じたのは、始終抱っこしなくても、自分たちが食事をする時や用足しをする時に置いておけば、娘も誰がどこにいるのか把握できてちょっとだけ安心できるみたいです。

 我が家は全体的に壁紙含め白っぽい内装なのと、特に動くものがないので、よく娘が暇そうにしてるなと感じていました。なので、電動のメリーを買いました。

やすらぎふわふわメリー No.5820

やすらぎふわふわメリー No.5820

 IPものではなく、ベビーベッドに取り付け可能なものを探した結果これにしました。オルゴールは必ず鳴らなくても良かったかな。このメリーは効果てきめんで、電源を付けて回り始めると娘が食い入るように眺めてるので、これは買って良かったですね。ただ最初の2日間くらいは、興奮しすぎて夜中まで眠ってくれませんでした。。。

 そういえば、聞くところによると弊社内で育休を取得したのは僕が初めてだったようなので、今後も他の社員が気兼ねすることなく安心して子供の成長を見守れるような環境が維持できるように、自分も努力したいと思っています。