taiyoh's memorandum

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

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日間くらいは、興奮しすぎて夜中まで眠ってくれませんでした。。。

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

DDDとClean Architectureの対応関係について

 まず何より、DDDとClean Architectureそれぞれの指向性の違いを把握しておいた方がいいと思う。
 DDDはアプリケーション層(Clean Architectureでいう「UseCase層」)の内部、つまりドメイン層の表現を豊かにするための手法だと僕は捉えている。ドメイン層の独立性の担保のために仕方なく他のレイヤも大雑把に分割している、くらいに思っておいた方がいい。特にインフラ層とプレゼンテーション層にドメイン層ほどの厳密な説明がないのは、DDDが採用される多くのケースはある程度ドメインが見えてきているほどシステムやビジネスが成熟してきている時が(エヴァンス本執筆当時)多かったので、プレゼンテーション層を作り直すようなリファクタリングはドラスティック過ぎるので、アプリケーション層とドメイン層の再分析・再設計に多くのリソースが割かれたからではないだろうか。
 一方のClean ArchitectureはUseCase層(DDDでいう「アプリケーション層」)の外部、つまりFrameworks&Drivers層とInterface Adapters層までいかにユニットテストが書けるくらい責務を分割するか、というところに焦点が当たっていると僕は捉えている。なので、Entities層の独立性や表現云々ではなく、それぞれの責務に応じて機能の分割を行えば、必然的に各レイヤは独立するだろう、くらいのニュアンスではないだろうか。

 僕は上記のような捉え方をしているので、アーキテクチャや実装方針を話す時にDDDの言葉だけで進めると不明な点がたくさんでてくると思うし、業務を正確に理解する時にアーキテクチャに拘ってClean Architectureの言葉でしか話せないと、深い理解にはつながらないと思っている。それこそ両者は似てるとはいえコンテキストが違うので、似た単語が中にあったとしてもあまり緻密な対応付けをしても双方の理解には大きくは貢献しないんではないだろうか。

 因みに僕はDDDとClean Architectureをどう区別しているかと言うと、機能実装をする時にユースケースはDDDの手法を使って分析・記述して、その外側はClean Architectureを意識した実装になるように心がけている。これなら双方のいいところを残せる上に不明瞭な箇所をカバーしあえるので、精度の高い設計や実装を目指すことができるんではないか、と僕は勝手に信じている。

以下は蛇足。

自作キーボードとDvorakと私

この記事はSmartDrive社員が綴るアドベントカレンダー「SmartDrive Advent Calendar 2018」の13日目の記事となります。

qiita.com

Agenda

  • きっかけは転職から
  • Ergo42を組んだ
  • Dvorak配列へ

きっかけは転職から

9月1日付けで株式会社スマートドライブに入社しました。よろしくお願いします。

smartdrive.co.jp

6月(前職中)、退職の諸々の連絡をして僕の視点からは各方面から割とあっさりと了承してもらったので、意気揚々としておりました。退職はなんだかんだ言って一つの区切りなので、何か自分へのご褒美を買おうかなと考えていたところ、ふと「分割キーボードが欲しいな」と思いつきました。
同時に、転職先のSmartDriveはIoT関連のスタートアップでありデバイスを扱ってることを思い出し、折角なら以前からtwitterのTL上でたまに目にしていた「自作キーボード」なるもので分割キーボードを自作するのが一番エキサイティングではないか!?と思うに至りました。

Ergo42を組んだ

この辺のドタバタはブログ記事を書いてました。

Ergo42を組み立てています(そしてどうやら失敗しています) - taiyoh's memorandum

Ergo42が遂に組みあがりました - taiyoh's memorandum

(本当はHelixも組もうとしていたのですが、ハンダ付けでかなり色々なところをミスってたことに気づき、その後の自作キーボード作成の際の反省とさせてもらいました。すいません><)

実はこの後Fortitude60も組んだのですが、macbook proのキーボード(QWERTY)・Ergo42(Dvorak)・Fortitude60(QWERTY)と3つ平行して使ってみたら頭の中がだいぶ混乱してしまったので、今はメインはErgo42を使用し、ミーティング等で席を離れるときはmacbook proのキーボードを使用しています。
Ergo42はかなり使用感がよく、キー数はがっつり減ったとはいえ必要に応じて追加できる余地があるので、かなり気に入ってます。
また、これを作ったときは僕のハンダ技術がたりなかったために時々接触不良を起こすので、「開腹手術」をしてすぐに直せるのもよいですね。

Dvorak配列へ

10年以上前からDvorak配列自体は知ってましたが、以下の理由から大人しくQWERTYを使っていました。

  • 多くの市販PCやキーボードはQWERTY前提のキー配列となってることが多く、そこを無理やり変えてまでDvorakを採用するモチベーションがなかった
  • ソフトウェア的に配列を変えて、キーキャップに印字されてる文字と出力される文字が違うのは抵抗があった
  • MXキースイッチのキーボードを買っていたので試してみたが、列ごとにProfileが違うため、QWERTY以外の配列に並べるとちぐはぐになった

が、自作キーボードというか同じProfileのキーキャップを使える環境なら、自由に自分の思い通りのキー配列が設定できるため(これはqmk_firmwareの存在も大きいですね)、8月の夏休み期間(有給消化とも言う)に思い切って乗り換えることを決めました。
夏休み中は小さなGo製のアプリケーションを試しに作っていて、そこでGoでのプログラミングの勉強をしていたのですが、Go自体もあまり慣れてないしDvorakもおぼつかないので、かなりストレスフルでした。
が、最初は0.5key/secくらいだったのが徐々に1key/secになり(よくそれで仕事回してたよな、というツッコミはありますが)、最近はやっと内容によっては3〜4key/sec(肌感)くらい出せるようになりました。が、まだ配列に慣れてないっぽく、特に日本語入力時のミスタッチはかなり多いのでそれは改善したい。。。

8月からDvorakを使い始めたので4ヶ月以上経ってるので、Dvorakの感想を。

  • QWERTYでのタイピング時の変な指の移動に気づけるようになった
  • Dvorak自体は英語向きの配列だと思う
    • 英語は -tion , -er , pro- のようにある程度決まった接頭辞・接尾辞の組み合わせが多く、これがDvorakだと打ちやすい
    • プログラム言語は英語ベースのものが多く、打ちやすい。が、日本語は若干打ちづらくなった
    • QWERTYでも高速に打ってる人が多いので慣れの問題はありそう

まとめ