かりあどぷらねっと

思ったこととか感じたこととか何か書きます

飲酒プログラミング -ほぼリーディング-

ごきげんよう、かりあどです。 今回は飲酒プログラミングAdvent Calendarを書いていきます。

adventar.org

実は1日前に書く予定だったのですが、色々環境構築でハマってしまい後ろが空いていたので1日後ろにこっそりずらしました😇 (今までは会社貸与PC上に環境作っていたのですが、退職に伴い個人PCに作り直しました)

本日のワイン

f:id:kariaduu:20191219160520p:plain:h300

井筒ワイン竜眼です。

自分はワインが好きなのですが、別に詳しいとかそんなことは全くなく適当な感想を書いているかもしれないのでその点はご容赦ください🙏 今回飲む竜眼種ですが、主に長野県で栽培されており、なかでも善光寺で栽培されていたことから善光寺ブドウとも呼ばれているらしいです。 飲んだ感想としては辛口なのですが、強いドライ感はなくすっきりした味わいの中にほのかに香る果実感と言った感じで日本食にとても合いそうな味わいです。 ざっくりいうと辛口よりのほんのり甘口と言った感じでしょうか。

本日のお題

今年のiOSDCでこんな発表をしました。

speakerdeck.com

このスライドの後半でSanitizerCoverageというものが出てくるのですが、発表当時深く追いきれなかったところがあるので、そこら辺をなんとなくみていきたいと思います。

そもそもこのSanitizerCoverage使ってる人いるのかな、という気持ちはあるのですが、まあ実装されている以上誰かが使っているのでしょう。

SanitizerCoverageのドキュメントは基本的にClangのものを参考にしていきます。

clang.llvm.org

ドキュメントを見ると実はSanitizerCoverageにはいくつかの種類があることがわかります。 その例として、 * Tracing PCs with guards * Inline 8bit-counters * PC-Table * Tracing PCs

などが挙げられます。まあほとんどExperimentalなんですけどね。 これらがswiftcには実装されているのか?みてみようと思います。

手がかりとしてまずはこのSanitizerCoverageに関するtestを見てみようと思います。

ちなみに今2杯目です。 そして書き始めるまでに環境構築で失敗してめっちゃ時間使いました。 ブランチを切り替えたりしていたのですが、次のようにハマったりしていました。

救いの手が

感謝、圧倒的感謝...!

実際にチェックアウトしたディレクトリ構成を見ていたら以前は/swift-source/llvmとなっていたものが/swift/llvm-project/llvmとなっていることに気がつきました。

そのあともビルドしたらCMakeのエラーがでてよくわからなかったりしていましたが、なんとかNinjaのビルドを通すことに成功したみたいなので、もう少し先へ進めそうです。(13インチMacBook Proなのでビルドに1~2時間かかってます)

ついでに3杯目を注ぎにいきます。 また余談なのですが、ワインオープナーはウイングタイプよりもソムリエナイフタイプのがきれいに開けやすいと思います。

こういうやつ

f:id:kariaduu:20191219165444p:plain:w200

testを読む

test/IRGenディレクトリにsanitize_coverage.swiftがあります。

// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=func %s | %FileCheck %s -check-prefix=SANCOV
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=bb %s | %FileCheck %s -check-prefix=SANCOV
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge %s | %FileCheck %s -check-prefix=SANCOV
// RUN: %target-swift-frontend -emit-ir -sanitize=fuzzer %s | %FileCheck %s -check-prefix=SANCOV
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,trace-cmp %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_TRACE_CMP
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,trace-bb %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_TRACE_BB
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,indirect-calls %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_INDIRECT_CALLS
// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,8bit-counters %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_8BIT_COUNTERS
// RUN: %target-swift-frontend -emit-ir -sanitize=fuzzer %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_TRACE_CMP

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
  import Darwin
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku)
  import Glibc
#elseif os(Windows)
  import MSVCRT
#else
#error("Unsupported platform")
#endif

// FIXME: We should have a reliable way of triggering an indirect call in the
// LLVM IR generated from this code.
func test() {
  // Use random numbers so the compiler can't constant fold
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
  let x = arc4random()
  let y = arc4random()
#else
  let x = rand()
  let y = rand()
#endif
  // Comparison is to trigger insertion of __sanitizer_cov_trace_cmp
  let z = x == y
  print("\(z)")
}

test()

// FIXME: We need a way to distinguish the different types of coverage instrumentation
// that isn't really fragile. For now just check there's at least one call to the function
// used to increment coverage count at a particular PC.
// SANCOV_TRACE_CMP: call void @__sanitizer_cov_trace_cmp

// SANCOV: call void @__sanitizer_cov

Swiftコンパイラのテストコードはlit(LLVM Integrated Tester)と呼ばれるツールを用いて行います。 使い方は公式ドキュメントだけではなく、日本語での説明もあるのでとても参考になります。

llvm.org

qiita.com

medium.com

qiita.com

Swiftコンパイラに関する丁寧な日本語ドキュメントは結構あるのでとても助かります。

これらを参考に先ほどのテストをまずは実行してみます。 litが上のQiitaだと swift-source/llvm/utils/lit/lit.pyとされていますが、上述したとおりswift-source/llvm-project/llvm/utils/lit/lit.pyになっていることだけ注意です。

llvm-project/llvm/utils/lit/lit.py -sv build/Ninja-RelWithDebInfoAssert/swift-macosx-x86_64/test-macosx-x86_64/IRGen/sanitize_coverage.swift

当然ですが成功しますね。 が、よくテストコードをみるとなんか怪しいです。FIXMEと書いてる時点でよく見なくても怪しいですが。

例えばこの行において

// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge,8bit-counters %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_8BIT_COUNTERS

-check-prefixSANCOV_8BIT_COUNTERSをチェックする内容として記述されていますが、ファイル内でそのような定義は見当たりません。 ファイルで定義されているのは

// SANCOV_TRACE_CMP: call void @__sanitizer_cov_trace_cmp
// SANCOV: call void @__sanitizer_cov

この二つだけです。 この二つ以外はテストとして記述はされているが、アサーションされていないと言った感じでしょうか?

試しにSANCOV_8BIT_COUNTERSについてClangのドキュメントを参考にこうなるであろうという期待結果のCHECKを追加してみます。

// SANCOV_8BIT_COUNTERS: __sanitizer_cov_8bit_counters

テストが失敗しました。 少なくともこの形では実装されていなさそうです。 ちなみにこちらもテストはないですが、Tracing PCs with guardsについては以下のように追記してみるとテストは通ります。

// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-coverage=edge %s | %FileCheck %s -check-prefix=SANCOV -check-prefix=SANCOV_TRACE_PC_WITH_GUARD

// SANCOV_TRACE_PC_WITH_GUARD: call void @__sanitizer_cov_trace_pc_guard

上で貼ったスライドにもありますが、Tracing PCs with guardsについては実装されていることはわかります。

もうだいぶ酔ってきたのでそろそろ締めたい。

じゃあこのSANCOV_8BIT_COUNTERSが実装されているのか、についてコードを追っていくと、 それぞれを受け取るフラグの存在は確認できます。

https://github.com/apple/swift/blob/5446d333b844e96a73c7bb75b04d21d86d06d2f1/lib/Option/SanitizerOptions.cpp

うーん、今日はここまで... ここから先はまた今後調べてみます。

ワインはとても美味しかったです。 いろんなワイン飲んでいきたいですね。

iOSDC Japan 2019でコードカバレッジについて話してきました

ごきげんよう、かりあどです。

iOSDC Japan 2019の2.5日間の日程全て終わったので少し感想とか書きます。

発表資料

speakerdeck.com

自分の発表

こうした大きな場での発表は初めてだったのでとても緊張したけどなんとか無事終わって良かったです。

発表の内容自体はわかりづらいところや、冷静に見直すと単語など前提知識を要するところがいくつかあったかもな...と思っています。 特にタイトルでブランチカバレッジと銘打ったのですが、こちらが誤解を招いてしまったかもしれないという点とLLVMとはみたいな説明を一切しなかった点です。

カバレッジについてはブランチという単語がGitにも存在することから紛らわしかったかなと思っています。 ブランチカバレッジはコンディションカバレッジとも呼ばれるのでこちらを選択する方が適切だったかもしれないですね。

LLVM等の単語については30分という限られた時間では全ての用語を説明する時間もなく、SwiftのバックエンドはLLVMなんだという説明をすっ飛ばしてしまいました。さらにはLLVM IRの説明すらしなかったですね...。 ただLLVM IRが何かということは今回の発表の本質ではないと思っているので、時間的に仕方なかったとも思っています。LLVM IRについては@rikusoudaさんのLTで説明あったのでもしモヤモヤしてしまった人がそこで補完できていたらいいな...と勝手に思っていたりもします。

とはいえ何もわからないところからスタートして準備にかなり時間がかかったので、良かったと感想いただけるのはとても嬉しかったです。

こうした感想は懇親会で話しかけてもらえるのもとても嬉しいのですが、Ask the Speakerに来てもらえると最高に嬉しいんだということも今回自分が待つ立場になってわかりました。

今回Ask the Speakerにday2で発表もされていた@kateinoigakukunさんが来てくれてさらに発表に関連した内容を一緒にさらに深掘りしたりと次のスピーカーの方が来るまでめちゃくちゃ楽しい時間を過ごすことができました。双方向コミュニケーションできて大変良かったです。Ask the Speaker来てくれると本当に嬉しいのでみんな積極的に行きましょう!

また、今回の発表をするにあったって色々調べたのですが、調べれば調べるほどわからないことが増えていくという感じでした。 そのため今はわからなくて話せなかったけど、みたいな内容もあるのでそこはこの後じっくり調べて見てどこかでアウトプットできればなと思います。

聞いた発表

今回自分が聞いて特に印象に残り良かったと思うトークはday2の@koherさんの「Heart of Swift」 です。 最近仕事ではJavaを書くことが増えたのですが、頻繁にSwiftのが書きやすいなとか個人的に好みな表現ができるなということを感じています。

そうしたSwiftのHeartをとても丁寧に解説していただけました。Swiftという言語の根幹をなす思想、そして今後の向かう方向...。

Value Semanticsは一応値型には参照型のオブジェクトは持たせないようになどは心がけていたのですが、単語として、その明確な定義を今まで知らなかったですが、今回の発表ですごくわかりやすく説明していただけので理解することができました。今までやっていたことがなんでそうするのか、できていなかったことをなぜやるのかを説明するためのとても貴重なお話でした。

POPについては型としてのProtocolと制約としてのProtocolという使い分け、意識しての分けは全くできていなかったのでそうなのか、とちょっと感動しました。

何度でも見たい最高のトークだったと思います。

全体感想

懇親会や茶会では今までお話したことなかった方など色々な方とお話できて楽しかったです。

スタッフのみなさまもお疲れ様でした。おかげでとても楽しいiOSDCを過ごすことができました。

来年も参加したいですね!

iOSDC Japan 2019でコードカバレッジについて話します

ごきげんよう、かりあどです。

9/5~7にiOSDC Japan 2019が開催されますね。 今回はその事前ブログとなります。 事前ブログを書くとプレゼントも貰えるそうです。

iosdc.jp

事前ブログキャンペーン、今年も実施です – iOSDC Japan スタッフブログ

今年はスピーカーとして参加します

今回私はスピーカーとして以下の内容でトークをします。

fortee.jp

こうした大きいカンファレンスでトークをするのは初めてなので今から緊張しています。

時間はday1(9/6)の13:30~からTrack Bです。 ランチ直後ということもあり、食後のデザートがわりに気軽に聴きに来ていただければと思います。

謝罪

スピーカーディナーにて予告動画を撮影し、公開もされているのですが、そこで話したことに適当なこと言ってしまったなというところがありました。 動画は上記のプロポーザルのページからみることができます。

予告動画では、調子に乗って「業務には全く役に立ちません」なんてことを言っていましたが、実際にスライドを作ってみたら少しは業務にも参考や役立てそうな内容になりました。

全ての人の参考や役に立つ、というわけではありませんがコードカバレッジを普段から意識している、測っているという方には何かしら参考になるところはあるのではないかと思います。

方向性が少しだけ変わったというだけで話す内容は変わりません。どちらかというと元から予定していた内容に業務でも役立ちそうなことが追加されたぐらいの感覚です。

トークについて

XcodeならびにSwiftのコードカバレッジについて話します。 コードカバレッジをどう使うべきかという話ではなく、普段私たちがみているコードカバレッジは何カバレッジなのかと言った仕組み的な話しになります。 今回調べてみて今まで当たり前のようにコードカバレッジを取っていたけど、実はこうなっていたんだみたいなことがわかり発表準備をしている最中もとても面白かったです。

また、発表準備をしていく中でLLVM IRを読むことがあったのですが、頭に残りすぎていたのか、夢の中でもLLVM IRを読んでいました。

f:id:kariaduu:20190903211306p:plain ↑これの話をします

参加者として

1参加者としていろんなトークを聞くことや、いろんな方とお話しできることをとても楽しみにしています。 普段のコミュ障っぷりをこの期間は頑張って取り除いて積極的に話しかけに行こうと思っているので、トークを聞いてくださった方も聞いてない方もどなたでも見かけたら気軽に話しかけていただけたらと思います。

後は今年はじめぐらいからクラフトビールにハマっているのでビール楽しみです🤤

期間中、一緒に楽しみましょう! (とりあえずの目標は寝坊しないこと)

2018年を振り返る

2018年は色々あったので、(暇なのと)後の自分のために振り返ってみます。

転職した

新卒で入った会社をやめて転職した。
最終的にやめたのはもっとやりたいことが見つかったからだった。
前の会社は航空業界という多分他ではなかなかできないような仕事ができるので、楽しかった。

転職については転職そのもの以上に転職活動が自分にとってプラスになった気がする。 正直転職しようと思うまで今後のキャリアとか本気で考えたことがなく、目の前の仕事をしていて満足、という状態だった。 でも転職活動をする中では当然何をやりたくて転職するのか、ということが聞かれるので自分が何を本当はやりたいのかを真剣に考えるきっかけになった。

本当にやりたかったこと

その自分の本当にやりたいことはお客様と開発者、両方を幸せにすることだと思った。 その具体的な手段として、テストと自動化が今は課題だと思っている。

前職時代、とてつもないケース数のテストをデータ作成から全て手動でやったことがあった。 正直毎日毎日終電近くまで残業してそれをやり続けるのは肉体的にも精神的にもとても辛かった。 正直今思えばそもそも意味のないテストケースが多かったし、全て手動というのも自動化できたよなーと思うところがある。

またテストについてはアジャイル開発をしていた時にテストコードを書いていたがどこまでテストすればいいのか、 このテストで十分なのかなどわからなくなることがよくあった。

開発している中でいくつか大きなバグも出したことがあった。 バグはお客様にとってかなり悪い体験になってしまう。 本当はとても使いやすいサービスだとしてもバグ一つで印象が悪くなりかねないし、それにより離脱してしまう可能性もある。 開発した側もリリース後にバグが出るとかなり凹むし、精神的に来るものがあった。

これらの経験からテストはCX*1だけではなくDX*2をも向上させることができると思っている。 またテストやその他作業を自動化することでリリースサイクルを短くすることができればよりお客様に良い体験を提供できるし、開発者は単調な繰り返し作業から解放されるとも考えているので、自動化も大事だと思っている。
CXとDXを両方向上させてみんなが幸せな世界を作っていきたい。

当然これらの前提にはどうやって本当にお客様にとって嬉しいサービスを作っていくか、ということがあるが、自分の中では一つ軸となる考えがあり、それは今後も継続して続けていきたい。

転職してやったこと

iOSエンジニアとして入社した。
入社当時はテストコードが全くない現場だった。 また設計という概念が内容な無法地帯なコードだった。

まずはそれなりの規模のコードということもあったので、設計を持ち込んだ。 色々試行錯誤した上、最終的にClean Architectureに落ち着いた。 とは言え細かい点はあまり縛っておらず書きながらより良い方法を探している。 無法地帯への設計の導入と同時にテストコードを書いていった。 結構な量リファクタリングしたし、テストをかいた気がする。

アジャイル(スクラム)の導入をした。 入社当時はなんちゃってスクラムだったが、あまりうまく回っていない感じがしたのでもっと厳密にやっていきましょうよということで、 言い出しっぺなので主導して導入していった。 正直これはまだうまく導入できた感じはなく、課題が残っているので来年頑張る。

外での活動を増やした

勉強会とかそんなに行っていなかったし、行ってもちょっと出て懇親会は帰るみたいな感じだった。 まずはインプットからということでもっと積極的に参加して色々な人と話したりしてインプットを増やした。 インプットしていくうちに自分でもアプトプットできそうな内容があるなと感、12月には初めて登壇もできた。 来年はもっとアウトプットを増やしていく年にしようと思う。 その他日頃お世話になっているOSSなどにも貢献していく年にもしたいと思う。

まとめ

この一年をまとめると、なんとなくで生きていた自分がエンジニアとして独り立ちを始めた最初の年だったと思う。 正直スタートとしては遅い方だと思うが、やりたいこと、目指したいところに向けてこれからも頑張る。

*1:Customer Experience

*2:Developer Experience

エンジニアと健康

ごきげんよう、そしてメリークリスマス、かりあどです。
こちらはOisix ra daichi inc. Advent Calendar 24日目です。

adventar.org

また、前回の私の「テストエンジニアの観点を持ってテストを書いていくぞな話」についてブロッコリーさんがテストエンジニア視点でのブログを投稿していたので、ぜひご覧ください。

nihonbuson.hatenadiary.jp

今回はもう年末だしクリスマスだし、前回と違って軽ーい話題でまったり書きます。

エンジニアは健康志向?

個人的に健康志向な方が多いと思うのは私だけでしょうか。*1
椅子にこだわったり、キーボードにこだわったり、、
もちろん仕事のやりやすさもあるでしょうが、例えば椅子であれば姿勢が悪くならないようにだとか、キーボードであればなるべく腕や肩が疲れないようにだとか。

なんにせよ、何かしら自身の身体に気を使っている、という点では当てはまる方も多いのではないでしょうか。
そんな健康について、今回は私がやっていることをいくつかご紹介します。

立って仕事をする

立って仕事をする、というスタイルも最近増えてきたのではないでしょうか。 少し前に聞いた事例では楽天が導入したことでも少し話題になりました。

ではなぜ、立って仕事をするのか。それは健康に関係があるからです。 以下のリンクでは座りすぎによる健康リスクと立って仕事をする際にメリットについて書かれています。

株式会社オカムラ|ソリューション・事例|上下昇降 +Standing

こちらによると、

  • 座りすぎによる健康リスクは最大で1.4倍
  • 日本のオフィスでは座っている時間が世界でも特に長い
  • 立つことで眠気、足のむくみ、疲労が抑制される

といったことが書かれています。 これらがどこまで本当か、というのはわからないのですが、そういう研究もあるんだということはわかります。

立つといいことはわかった。でも実際どうなのよ、と思われるかもしれません。 私は以前の職場では昇降デスクがあり立って仕事をしていました。
さらにオイシックス・ラ・大地に入社してからも昇降台を買ってもらいましたので、今は立って仕事をしています。 そこで実際に立って仕事をしてみた感想を書いていきます。
ちなみにこちらはこちらは実際に今使っている昇降台です。こちらはデスクの上に置くタイプなので、デスクそのものの買い替えはレイアウト的に難しい、という方でも使えるものになります。

f:id:kariaduu:20181225012557p:plain

メリット

  • 肩、腰への負担が少ない
  • ちょっとした運動ができる
  • 眠くならない

デメリット

  • 立ち方に気を使わないと片足に負担がかかる
  • 慣れるまではすぐ疲れる

ざっとあげるとこんなところでしょうか。 それぞれ少し詳しく説明していきます。

メリットについて
まず私は姿勢がそんなによくなく、座っていると腰が痛くなる経験がありました。 また、姿勢の悪さから肩がこり、それが原因となって頭痛になるということもありました。 立って仕事をするようになってからはこれらはかなり改善されました。 立っているときはよっぽどのことがない限り姿勢は悪くならない気がしています。 特に腰への負担は立っている時と座っているときで段違いに違いを感じます。 座って仕事をしている方で腰痛に悩まされている方にはかなり立っての仕事はおすすめです。

肩こりについては立って、というよりも昇降デスクが関係しているかもしれません。 昇降デスクはデスクの高さが調整できます。そのため、モニタの位置が低く、視線が下がることによって肩がこるということがありません。

ちょっとした運動ができる、ということについてはよく立っているだけでカロリーを消費するなんて話も聞きますが、それだけではなくつま先だちになり上下に動くことでふくらはぎのちょっとした筋トレにもなる気がしています。 ちょっと詰まった時にこれをやると気分転換にもなって個人的には結構気に入っています。

眠くならないは説明不要でしょう。

デメリットについて 立ち方については少し気を使ってあげないとダメで、片足に重心がずっとよっていると、足の付け根に負担がかかると感じています。 こちらは意識的に両方の足でしっかり立つようにしてあげたほうがいいと思っています。

慣れるまで疲れるというのは読んでの通りなのですが、最初は立てても1時間が限界だったりします。意外とただ立っているだけというのは疲れます。

他にも立ちと座りを切り替えることで自分の中のスイッチを切り替えたりといったこともあるのですが、健康とは関係ないので置いておきます。
簡単な紹介でしたが、昇降デスクは一度体験すると良さがわかるので、ぜひまずはオフィスに1台導入してみてください。

ロードバイク

いくら仕事中に立っていても全く運動をしない、というでは健康的にはよくないように思えます。
私は趣味の一つがロードバイクに乗ることなので、週末はロードに乗っています。
特にレースに出るといったことはせず、のんびりまったり乗るのが好きです。 ロードバイクは軽くてスピードもそれなりに出るため、ママチャリと比較して移動距離がグンと伸びます。
例えばランニングは私は景色が毎回同じで少し飽きる、といったことを思ったことがあります。 一方でロードバイクであれば様々なところに出かけることができます。 ちょっと飽きっぽい、という方にもおすすめできます。

こちらは江ノ島にいった時の写真です。都内から江ノ島は近いため、サクッと行って帰ってこれます。 また江ノ島の前を通っている国道134号線は走りやすく、海沿いでとても気持ちが良いです。 f:id:kariaduu:20181225020415j:plain

またロードバイクはランニングに比べると膝への負担が少ないです。*2 膝が少し悪い、という方でも始めやすいのではないでしょうか。

一方でいくつかデメリットも存在します。 自転車本体は言わずもがなですが、快適に乗るためには服、靴、整備道具など様々なものが必要となってきます。 が、そこまでこだわらなければめちゃくちゃ高い、というものでもないので、社会人であればそこまで苦にはならないのではないかと思います。 かくいう自分も自転車本体はビギナー向けの安いものに乗っています。

お金以上に大変だと思っているのが保管場所です。 ロードバイクは基本室内保管です。値段もしますし、外では雨で錆びてしまいます。 私は乗り始めた時は一軒家の実家だったので、室内でも置くところには困らなかったのですが、引っ越してから狭いマンションで室内をロードバイクに場所を取られています。人によってはここが保管できなくて始められない、という方ももしかしたらいるかもしれません。

左右分割キーボード

こちらは完全に予定となるのですが、先日Fortitude60という左右分割キーボードを買いました。
今度の自キー会(詳しくは以下のリンクをご覧ください)で作ろうと思っています。

社内でキーボードつくる会を企画した話 - Qiita

左右分割キーボードは肩が開くので肩こりにいいとも聞くので試してみたかったです。 こちらは完成して、しばらく使ってみたらまた感想をどこかで書きたいと思います。

まとめ

今回はライトに健康について書いてみました。 他にもこんなことで健康に気を使っている、ということがあれば教えてもらえると嬉しいです。 一方で何かしたかったけど、何もやれていないという方にはどれか参考になれば幸いです。

中でも私の一押しは立って仕事です。

ぜひみなさんもチャレンジしてみてください。

ちなみに食の会社にいるんだから食事についても書きたかったのですが、自炊をしているくらいで、自炊も一応野菜は食べるようにしているけど栄養価まで考えられてはいないので書けませんでした。いつか栄養価まで考慮してレシピを考えていきたいです。

*1:別にエンジニアだけが健康志向という訳ではなく、単純に私がエンジニア以外の職種の人をあまり知らないから語れないだけです。

*2:きちんとしたフォームで乗らない場合、負担は結構かかり膝は普通に痛くなります

テストエンジニアの観点を持ってテスト書いていくぞな話

ごきげんよう。かりあどです。

12/15~16に開催されたWACATE2018 冬 〜C’mon baby ジドウカ〜 に参加してきました。
そこでテストエンジニアの方々と色々議論できたのでそれを書きます。
またt_wadaさんによる講演もとても素晴らしかったので感想を書きます。
WACATEそのものの感想よりも議論の内容を書きたいので、WACATEって何?という方はこちら。

wacate.jp

当初の予定は参加レポートだったのですが、議論した内容があまりにもよかったのと、個人的に振り返りたかったので急遽予定変更です。

なおこちらの記事はOisix ra daichi Inc. Advent Calendar 2018の18日目となります。 前日の弊社スーパーSREエンジニアの@morihaya55さんの記事はこちら

adventar.org

開発者とテストの関わりについて

私は普段iOSアプリの開発をしているのですが、テストコードも書いています。
しかしいつも思っているのがテストコードはこれで足りているのか、どこまでかけば品質の担保となるのだろうかと考えていました。
実際に世の中的にはどうなんでしょうか? 開発者でテストを書いている方は何を基準にテストコードを書いているか気になります。

最近ではテストコードを開発者が書くことも一般的になってきたんじゃないかなと思う中で、じゃあ次のステップはと考えたときにそのテストコードにソフトウェアテストの観点が入っているのだろうか、ということじゃないかなと私は考えています。

そんな中でもっと自分自身ソフトウェアテストを勉強する、テストエンジニアと色々議論してみたくてWACATEに参加しました。

開発者視点、テストエンジニア視点

WACATEでは夜の分科会という話したいテーマごとに別れて議論する場があります。 そこで私はBDDのモブプログラミングに参加しました。 元々テストコードを書くにあたってテストエンジニアの観点を知りたかった私にはぴったりなテーマでした。 その場では時間があまりなく、多くは議論できなかったのですが、その後の延長戦で深夜の分科会としてさらに少人数で続きをやりました。 そしてなんとそこからはt_wadaさんも参加してのモブプログラミングとなりました。

ホワイトリストブラックリスト

深夜の分科会でまず議論となったのが以下のようなリファクタリングを行った際のことでした。*1

 自動販売機の入金確認
 GIVEN 自動販売機に
 WHEN 1円を入れた時
 THEN 入金額が0円であること

リファクタリング

public class VendingMachine {
  int currentMoney = 0;

  public void insertCoin(int money) {
    if (money == 1) {
      return;
    }
    currentMoney += money;
  }
}

リファクタリング

public class VendingMachine {
  int currentMoney = 0;

  public void insertCoin(int money) {
    if (money != 1) {
      currentMoney += money;
    }
  }
}

まず第一段階として、 != の否定が入ると読み辛いのではないか、という意見が出ました。 が、ここで別の視点でこのリファクタリングはあまり良くないという意見が出ました。

とのことでした。

先に謝ります。ごめんなさい、改めてコードを見てみたらこのコードに対してどっちがホワイトリストブラックリストなのかちょっと混乱してきました。 もしお分かりになる方いましたら教えていただけないでしょうか。

しかし、ホワイトリストのが頑強であるというのは理解できます。 意図しない入力に対して、処理を実行してしまうことはエラーの原因になり得ます。 このホワイトリストの考え方はでも同じことが言えるのではないでしょうか?*2

少し考えてみます。例えば次のコードはどうでしょうか。(ここからSwiftで書きます)

enum Coin: Int {
    case hundred = 100
}

class VendingMachine {
    var money: Int = 0
    
    func insert(coin: Coin) {
        money += coin.rawValue
    }
}

こちらは insert 関数ではそもそも Coin 型しか受け付けていません。 つまりそれは許可したもののみ受け付けるホワイトリストを活用している例でしょう。 型を用いたホワイトリストは意図しない入力に対してはコンパイル時にエラーとなる、かなり早いフィードバックです。

一番最初のJavaで書いていたプログラムでは、insert 関数はint型を引数に取っていました。この時点でinsert関数に対するテストは入力に取りうる値がint型全てになったしまったことがわかります。

一方で型を活用したSwiftのプログラム*3では入力に取りうる値がCoin型に限定されています。そのため、テストする範囲もCoin型で定義されたcase数で済みます。

型を活用したホワイトリストはただ頑強であるだけではなく、型検査そのものがテストの役割を果たしているため意図しない入力に対するテストを実施しなくてもよくなります。 もちろん一番最初の入力はInt型かもしれません。その時でも以下のようにCoin型をinitializeするタイミングで存在しない値が引数として渡されて時点でエラーとすることができます。

let input: Int // 何かしらの入力と仮定
guard let coin = Coin(rawValue: input) else {
    throw InvalidInputError.notCoin
}

多言語には明るくありませんが、Swiftのenumはテスト観点からみてもとても強力だと思います。

これからもなるべく型を意識したプログラミングは続けていきたいところです。

そのテストケース、どう書きますか

リファクタリングではテスト概要のリファクタリングも行いました。 元のテストケースは次になります。

 自動販売機の入金確認
 GIVEN 自動販売機に
 WHEN 100円を入れた時
 THEN 入金額が100円であること

 自動販売機の入金確認
 GIVEN 自動販売機に
 WHEN 100円を入れた
 AND 50円を入れた時
 THEN 入金額が150円であること

ここから1段階目のリファクタリングを行います。

 自動販売機に1枚コインを入れた時の入金確認
 GIVEN 自動販売機に
 WHEN 100円を入れた時
 THEN 入金額が100円であること

 自動販売機に2枚コインを入れた時の入金確認
 GIVEN 自動販売機に
 WHEN 100円を入れた
 AND 50円を入れた時
 THEN 入金額が150円であること

より具体的なテスト概要になったことがわかります。 が、ここでさらなる指摘がテストエンジニアのみなさんから上がりました。

この場合コインを3枚入れたらどうなりますか?

言われてみて気がつくわけです。1枚、2枚とテストケースが来たら当然3枚は、4枚はとなります。 が、一方で私の頭の中では次のようになっていて、実際に先ほどの問いにも次のように答えました。

コードでは加算しているのだから何枚来ても変わらないです

開発者である私はコードを起点に考えていました。 そのため、1枚、2枚というところには注意が向かず、コード上では何枚来ても同じだから2枚でテストしておけば問題ないと考えていたわけです。

一方でテストエンジニアの方は、このテストケースをみて、3枚の場合がテストされていない=バグが潜んでいるかもしれないと考えたことになります。 もちろんここではモブプロなのでコードを書くところもみていた為、何枚来ても同じということはテストエンジニアも知っていました。 しかし、その上で第3者視点でこのテストケースだとそれがわからない、という観点を持っていたことになります。 最終的にその場では次のようになりました。

 自動販売機に連続して複数枚コインを入れた時の入金確認
 GIVEN 自動販売機に
 WHEN 100円を入れた
 AND 50円を入れた時
 THEN 入金額が150円であること

よくテストコードは仕様にもなる、と言いますが仕様書という観点でもリファクタリング後の方が実装との紐付けがしやすくなっているようにも思えます。

これからはテストを説明する自然言語部分にも注意してテストコードを書いていかねばと思わされました。

テストエンジニアと開発者によるモブ(ペア)プロ

これらの経験を経て、テストコードを書く際にもソフトウェアテストの観点を取り入れることでより良いテストコードになっていくと確信しました。 そうした中でテストエンジニアと開発者の技術的交流や一緒に働くことがもっと盛んになった方がいいのではないか、という気もしてきました。

特に私が経験してきたアジャイル開発では厳密なテストフェーズというものがない場合が多く、開発者の書くテストコードで品質を担保しなくてはいけないパターンが多くありました。 そうした中で同じチームにテストエンジニアに入ってもらい、一緒に働くことで早い段階からテストエンジニアの観点を持って開発することができます。 もしくは、開発者自身がソフトウェアテストを勉強し、テストエンジニアの観点を身につけていくのも同じ結果を期待できるのではないでしょうか。

TDDのその先へ、ChekingからTestingへ

今回のWACATEではあのt_wadaさんによる講演も開催されました。 その内容はとてもよく、Twitter上では感動して涙がでたという人も一人ではありませんでした。

私もTDDBootCampへの参加経験などはあったのですが、t_wadaさんの講演を聞くのは初めてでした。

TDDの説明をすることが目的ではないので飛ばしますが、これは絶対読んだ方がいいです。

テスト駆動開発

テスト駆動開発

内容は一般的なFizzBuzzでした。 それをTDDやコードを知らない人でも理解できるようにとても丁寧に説明しながら進行していきました。
ある程度進んだところで次のようなコードになっていました。(当日はJavaでしたがSwiftで書きます)
そこから説明していきます。

class FizzBuzzTest: XCTestCase {
    let fizzBuzz = FizzBuzz()

    func test_3の時Fizzと返される() {
        XCTAssertEqual(fizzBuzz.fizzBuzz(3), "Fizz")
    }

    func test_6の時Fizzと返される() {
        XCTAssertEqual(fizzBuzz.fizzBuzz(6), "Fizz")
    }

    func test_5の時Buzzと返される() {
        XCTAssertEqual(fizzBuzz.fizzBuzz(5), "Buzz")
    }

    func test_15の時FizzBuzzと返される() {
        XCTAssertEqual(fizzBuzz.fizzBuzz(15), "FizzBuzz")
    }
}

少し過程を説明しますと、ToDoリストからテストを書いていき、3の倍数は三角推論を用いて2つのテストケースを書いています。
一方で5の倍数や3と5の倍数のテストや実装は明白な実装を用いて1つのテストケースしか書いていません。

ここまでは通常のTDDでも到達するところかと思います。
講演ではさらにここにソフトウェアテストの観点を入れて品質保証のためのテストが追加されていきました。

まずはToDoリストをみてみます。

  • [x] 3の倍数の時Fizzが返される

    • [x] 3の時Fizzが返される
    • [x] 6の時Fizzが返される
  • [x] 5の倍数の時Buzzが返される

    • [x] 5の時Buzzが返される
  • [x] 3と5の倍数の時はFizzBuzzが返される

本来の仕様に加えて、さらに問題を小さくするために具体的な数字に落としています。
その具体的な数字でテストコードも書かれているため、本来の仕様が抜け落ちてしまっています。 それでは後日別の人が見たときに仕様がすぐわからないかもしれません。
そのため次のような構造的なテストケースにリファクタリングします。

class FizzBuzzTest: XCTestCase {
    let fizzBuzz = FizzBuzz()

    func test_3の倍数の時Fizzと返される() {
        XCTContext.runActivity(named: "3の時Fizzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(3), "Fizz")
        }

        XCTContext.runActivity(named: "6の時Fizzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(6), "Fizz")
        }
    }

    func test_5の倍数の時Buzzと返される() {
        XCTContext.runActivity(named: "5の時Buzzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(5), "Buzz")
        }
    }

    func test_15の倍数の時FizzBuzzと返される() {
        XCTContext.runActivity(named: "15の時FizzBuzzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(15), "FizzBuzz")
        }
    }
}

抜け落ちていた仕様を構造化することでテストコードに落とし込むことができました。*4

実行結果の見た目もいい感じです。 f:id:kariaduu:20181218223604p:plain

しかしまだこれでは足りていないところがあります。
3の倍数は複数のパターンでテストしていますが、5の倍数や3と5の倍数では1つのパターンでしかテストしていません。
何かしらの変更があった際に気が付けない可能性もあります。 次のようにさらにリファクタリングしていきます。

class FizzBuzzTest: XCTestCase {
    let fizzBuzz = FizzBuzz()

    func test_3の倍数の時Fizzと返される() {
        XCTContext.runActivity(named: "3の時Fizzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(3), "Fizz")
        }

        XCTContext.runActivity(named: "6の時Fizzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(6), "Fizz")
        }
    }

    func test_5の倍数の時Buzzと返される() {
        XCTContext.runActivity(named: "5の時Buzzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(5), "Buzz")
        }

        XCTContext.runActivity(named: "10の時Buzzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(10), "Buzz")
        }
    }

    func test_15の倍数の時FizzBuzzと返される() {
        XCTContext.runActivity(named: "15の時FizzBuzzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(15), "FizzBuzz")
        }

        XCTContext.runActivity(named: "30の時FizzBuzzと返される") { _ in
            XCTAssertEqual(fizzBuzz.fizzBuzz(30), "FizzBuzz")
        }
    }
}

それぞれのケースに追加しました。 これらはTDDのCheckingとしては書く必要のないテストだったかもしれません。 一方でTestingの観点からはあったほうが良いテストケースだったでしょう。 実際には10や30といった元の数字の2倍ではなく、異なった数字でテストした方がいいかもしれません。

ここまでリファクタリングを重ねたことで、本来のTDDに品質保証の観点を取り入れることができました。 TDDのその先をみた気分になりとても感動し、実践していきたいと思いました。

まとめ

3つほど議論したことや、講演を説明しましたが全てに共通していることは開発にテストエンジニアの観点を取り入れることの重要性です。
冒頭でも述べましたが、自動テストのコードを我々開発者が書くことが一般化してきた今だからこそ、開発者がテストエンジニアの観点を持って品質保証まで考えられたテストコードを書いて行くべきだと私は思っています。 テストコードには開発を駆動させる役割もあります。これらをうまく使っていけば開発を駆動させながらさらに品質保証まで行うことができます。*5 今回私はそれをテストエンジニアと一緒にコードを書いていくことで学ぶことができました。 最近では開発者の間でもテストへの関心が高まっていると個人的には感じています。 そこでぜひおすすめしたいのはテストエンジニアと交流し一緒にコードを書くことです。 今回の経験を経て、強くそれを感じています。 そして私たち開発者がテストエンジニアの観点を持ってテストコードがかけるようになっていきましょう。

おまけ

まったく参加レポートしていなかったので最後に一つだけ。

BPP(ベストポジションペーパー賞)というものをもらってしまいました。 ポジションペーパーとは、参加申し込みのときに書いた自己紹介やら意気込みやらを書いたものになります。 BPPは参加者投票でもっとも良いと思ったポジションペーパーが選ばれます。 私は何を書けばいいかわからず、困った結果、お酒を飲んで勢いで書きました。 どこが良くて参加者みなさまに投票していただいたのかはわかりませんが投票していただいたみなさまありがとうございます。

ちなみに私が書いたポジションペーパーが次のようなものです。もし次回以降書く内容に困った方がいたら参考にはならないかもしれませんがないよりあった方が雰囲気つかめると思うので置いておきます。

f:id:kariaduu:20181218231145p:plain

最後にこれも置いておきます。一緒にモリモリテストやっていってくれる方きてくれると嬉しいです。

recruit.oisixradaichi.co.jp

*1:記憶を頼りに書いているので実際とはおそらく少し異なっています

*2:私は普段Swiftを書いているため強い静的型付け言語を基準にしがちです

*3:このように書くとJavaが悪いように見えてしまうかもしれませんが、単純にWACATE時はJavaで書き、説明には普段から慣れ親しんでいるSwiftで書いているというだけです。

*4:Javaではクラス毎に分けていました

*5:テストコードで全ての品質保証ができるわけではありません

TDDBC Tokyo 2018-9に参加しました

9/30に開催されたTDD Boot Camp 2018-9に参加しました。

tddbc.connpass.com

一言で感想を言うと、非常に満足度の高いイベントでした。

一応前職でTDDで開発していたこともあったのですが、最近あまりやれていなかったのと、 厳密にTDDを理解して実践できていたかと言うとそんなことはなかったのでよりTDDを理解するために参加しました。

午前

@yattomさんによる基調講演から始まりました。

TDDとはと言う基本的な説明から、途中でライブコーディングによるデモもあったりしました。 ライブコーディングではTDDでTAや参加者にペアの相方を担当してもらいながら計算機と素因数分解についてデモしていました。

いくつか印象的だった話を書きます。

  • 仮実装によってプロダクトコードでテストコードの正しさを確認する

テストコードに関わらずテストに必ずつきまとう、「テストそのものの正しさ」について言及しています。 実際、自分もテストコードが間違っていてテストは成功していたけど実はバグがあったという経験があります... 最小限の実装によってテストが成功することで、テストの正しさを確認するプロセスがTDDには組み込まれているのはとても素晴らしいと感じました。

  • TDDはあくまでも開発手法であってテスト手法ではない

TDDやったからといってテストがすごいできるわけではないし(世の中にはTDDをテスト手法にまで昇華させた人もいるとか) TDDやったからバグがなくなるというわけでもないのはすごく納得しました。なぜなら網羅的に書くことが目的でもないから。
アジャイルテストの4象限http://jasst.jp/archives/jasst10n/pdf/S2.pdfに書いてある部分のうち TDDがカバーする範囲はチームを支援するテストが中心になる。Checking=既知の確認とTesting=未知の探索の考え方。 TDDではプロダクションコードを書くためにCheckingのツールとしてテストを書くので、Testingは別にちゃんとやりましょうねということだと思いました。

ランチ

ランチにはSwiftを選択した参加者とSwift担当TAのみんなで食べに行きました。
まずは全員で自己紹介後各々話をしたのですが、それがまたとても濃い内容でした。 特に今回SwiftのTAとして参加してくださっていた@Kuniwakさんはみんなの相談にのっていてご飯を食べるのを忘れていたほど...!

午後

お待ちかねのTDD実践タイム。お題は自動販売機の実装でした。 今回自分は@shizさんとペアを組ませていただきました。
二人でTODOを作成して、小さなステップを踏んでRed→Green→Refactorのサイクルを実践して行きます。 もうとにかく楽しくてあっという間に時間が過ぎ去って行きました。(もっともっとやっていたかった!!) 特にサイクルがクルクル回っている時は気持ちが良くて最高に楽しかったです。

今回はTDDという要素以外にもペアプログラミングという要素もありました。 実はペアプログラミングも以前仕事でやっていたこともあったのですが、やはり良いなと再実感しました。
自分がコードを書くときには声を出して自分の考えを伝えながら書くことで自身での理解も深まりますし、相手の考え方もわかってそういう方法もあるのか!という気づきの機会も与えてくれました。

途中レビューという形で他のチームの発表をいくつか聞くこともできました。 他のペアもみんな得るものが多かったのか楽しそうに発表されていました。 仕事でペアプログラミングというのもいいのでしょうが、こうした場で普段と違う人とペアプログラミングを実施するというのがとてもいいなと感じました。 会社も場合によっては職種も異なる相手(発表されたペアで開発エンジニアとテストエンジニアというペアがありました)とペアを組んで一つのことに取り組むのはとても勉強になると感じています。

コードを書くにあたっては、自分は結構型で縛ることでテストしなくていいことはテストしなくてもいいようにしたいと思っているのでそこは意識して書いて行きました。
自動販売機の課題でもコインをenumで表現することで101円といったイレギュラーの投入を型レベルで防いだりという感じです。

課題の最後まで行くことはできませんでしたが、とても濃密な時間でした。

懇親会

懇親会では突発モブプロが始まったりもしていました。

他のSwift参加者ともたくさん話せてとても楽しく過ごすことができました。 (生ハムも美味しかったです)

感想まとめ

TDDBCは控えめにいっても最高のイベントでした。まだ参加されていない方はぜひ一度参加してみて欲しいです。 運営のみなさま、TAのみなさま、そして参加者のみなさまも本当にありがとうございました。

TDDは開発の一部分だけにでも取り入れることはできるので、社内でも興味ある人に教えて行きたいと思っています。 まずはじめに10月から一緒にiOS開発を行う方がいるのですが、その方とはまず一回TDDでペアプログラミングをしてみようと思います。

また、社内にキッチンがありそこでたまにイベントを開催しているのですが、キッチンTDDみたいなイベントを開催して みんなでご飯作って食べながらわいわいモブプロ or ペアプロTDDができたらいいなとも考えています。

これからもTDDやって行くぞーーーー!

とりあえずみなさんまずはテスト駆動開発読みましょう。

テスト駆動開発

テスト駆動開発