Gopher道場卒業式でLTしてきました

mercari.connpass.com

11月から4回に渡ってメルペイさんの主催するGopher道場に参加して、12/3に卒業式でLTしてきた。

業務でやらない言語を実践的に学ぶ機会はなかなかないので、大変貴重でありがたかった。

課題に手が回りきらなかったのが悔やまれるが、自学で粛々とやろうかなと思う。

LTはネタがないなぁと悩んでいたんだけど、FAQの内容をJavaと絡めてみた。

クオリティはともかく、Javaと絡めたことでJavaの人と認識され、懇親会でも声かけてもらえたりした。

Javaにいつも助けられてます。最近書いてないけど。

speakerdeck.com

CircleCIをローカルで動かす #CircleCI

概要

circleciのCLIをインストールするとローカルで動かせるようになります。

公式 を見ながらやってみた

インストール

Macだとbrewで入れられる。

$ brew update
$ brew install circleci

brewで入れるとUpdateコマンドは使えないらしい。

$ circleci update check
`update` is not available because this tool was installed using `homebrew`.
Please consult the package manager's documentation on how to update the CLI.

APIトークンの取得

ここからAPIトークンを発行する

設定

setupコマンドを使う。

$ circleci setup
✔ CircleCI API Token: ****************************************
API token has been set.
✔ CircleCI Host: https://circleci.com
CircleCI host has been set.

使い方

基本的にプロジェクトルートで行う。

ただしconfig.ymlのパスをオプションで渡すことはできる。

config.ymlのバリデーション

$ circleci config validate
Config file at .circleci/config.yml is valid.

Jobの実行

単一のJobしか実行できないようだ。

workflowとかは多分無理。

キャッシュやartifactの保存など一部は対応していないっぽいログが出る。
(でもビルドは通る)

Job名はオプションで指定するが、デフォルトだとbuildになってる模様。

$ circleci build --job build

デバッグ実行

buildコマンドとの違いはよく分からない。

helpには出てこないが、buildコマンドのオプションも渡せそうな雰囲気がある。

$ circleci local execute --job build

ヘルプ系

コマンドのヘルプ

$ circleci --help

各コマンドのヘルプ(下記だとbuild)

$ circleci help build

バージョン

$ circleci version

テスト用のDBをdockerで立てるGradleタスクを作る #Gradle

概要

テストでDBを別立てするような場合に、CI上ではCI環境側で提供するデータベースを利用するが、ローカル開発時のテストDBの用意がめんどくさい。

なので、コンテナDBをテスト時に立ち上げるタスクを作ってみる。

build.gradle

task setupTestDatabase(type: Exec) {
    commandLine 'docker'
    args = [
            'run',
            '--rm',
            '--name', 'continer_name',
            '-e', 'POSTGRES_USER=user_name',
            '-e', 'POSTGRES_PASSWORD=user_password',
            '-e', 'POSTGRES_DB=db_name',
            '-p', '5432:5432',
            '-d', 'postgres:10'
    ]
    doLast {
        logger.info 'database started.'
    }
}

task cleanupTestDatabase(type: Exec) {
    commandLine 'docker'
    args = ['stop', 'continer_name']
    doLast {
        logger.info 'database stopped.'
    }
}

task localTest(dependsOn: [setupTestDatabase, test]){
    doLast {
        println 'test completed.'
    }
}
test.mustRunAfter setupTestDatabase
localTest.finalizedBy cleanupTestDatabase

解説

./gradlew localTest で実行できるタスクを用意している。

タスクの中で行われるのは下記。

  1. dockerでPostgreSQLのDBコンテナを起動
  2. testを実行
  3. コンテナを停止

補足

  • Execを使うとコマンド実行できる
  • dockerは --rm を付けることで、停止時にコンテナを破棄する
  • dependsOnでDBの構築とテストのタスクを束ねる
  • mustRunAfterで依存タスクの順序を制御する
  • finalizedByでコンテナを停止する

その他

  • doLastがないと、タスクの終了を待ってくれないようだ
  • testでコケるとfinalizedByが実行されない

参考

What's New in Kotlin 1.3をさらっと眺めてみた #kotlin

What's New in Kotlin 1.3 - Kotlin Programming Language

↑をサラッと読んだ

  • contract構文ができた?
    • 🙄スマートキャストが便利になったみたいだけどよく分からん。。
  • whenの条件で変数代入ができるようになった
  • @JvmStatic@JvmField がinterfaceのcompanion objectで使えるようになった
    • 🙄うれしみはよく分からん
    • 🙄インターフェース内定数が宣言できるようになったってことかな?
  • アノテーションクラスの中にインナークラス、インターフェース、Enumが定義できるようになった
  • main関数の引数が省略可能になった。
  • FunctionTypeが引数を42個まで受け取れるようになった。
    • 🙄そんなに必要なのん。。?
  • progressiveモードができた
    • 🙄破壊的変更を厭わない人のためのコンパイルモード?
  • インラインクラスができた(実験的)
    • 🙄プロパティ一つだけのクラス?
    • 🙄最適化が積極的になされるっぽさ
  • 符号なし整数型ができた(実験的)

標準ライブラリ

  • マルチプラットフォームのランダムができた
    • java.util.Randomkotlin.random.Random
  • isNullOrEmpty/orEmptyの拡張関数ができた
  • array.copyIntoができた
  • keyのリストからMapを作れるassociateWithができた
    • 🙄valueだけ返せばMapになるっぽ
  • CollectionにifEmptyとifBlankができた
  • リフレクションでsealedクラスに触るAPIができた?
    • 🙄sealedクラスってなんだったけか
    • 🙄Enumの拡張版?

小さな変更

  • BooleanがCompanionを持つようになった
    • 🙄TRUEとかFALSEとかかな?
  • Any?.hashCode() はnullの場合0を返す?
  • CharにMIN_VALUE/MAX_VALUEの定数ができた
  • プリミティブ型のCompanionにSIZE_BYTESとSIZE_BITS定数ができた

データアクセスのUnitTestについて考える

問題

DBに登録したり、ファイルに書いたり、保存するような処理のテストについて考える。

インターフェースを抽象化すると、下記のような感じになる。

public interface ItemRepository {
    // itemを保存する
    void save(Item item);
}

この場合、saveのユニットテストは「itemが保存されていること」になるが、どうやってテストしたらいいだろう?

考えられる選択肢

考えられる選択肢はいくつかある。

実体を見に行く 🤔

たとえば保存先がデータベースならデータベース、ファイルならファイルを直接参照しに行く形。

Spockであれば、Groovy.Sqlみたいなクラスを使って、テストDBにクエリを発行して結果を確認する。

ただこの手段だとどうしても実装量が増えてしまうし、テストのためのコードの品質が気になってくる。

また、実装のテストなのかインターフェースのテストなのかも曖昧になる。

実体を見に行く+ヘルパーを用意する 🤔

実体を参照するような処理をヘルパーなりライブラリなりに切り出して、ヘルパーの品質はヘルパーのテストなりで担保する方法。

実体を参照する処理は(ヘルパーに追い出したので)ある程度スッキリはする。

しかし実体を参照するために用意しているけど本当にやりたかったのは保存をするテストだったはずで、何をやりたかったのか分からなくなってくる。

取得のインターフェースを用意する 🤔

save(item) した後に findById(id) のように、取得のインターフェースを作成する。

しかしこうするとsaveのテストをしたかったはずなのにfindByIdを作成しなければならないし、findByIdのテストはどうするんだっけ?となってくる。

「ユニット」は「メソッド」ではない

結論から言うと、取得のインターフェースを提供するのがよさそうである。

粒度として対称性のある処理が必要になる(なりそう)なのであれば、それはモジュールが果たすべき役割ではないか。

createがあるならdeleteがあるだろうし、pushがあればpopがあるだろう、といったように。

「ユニット」を「メソッド」ではなく「モジュール」と考えると、「ユニットテスト」は「モジュールの整合性が取れていること(必要なインターフェースが揃っている)」を確認するものといえる。

実際の要求ではcreateメソッドだけが必要な場合もあるが、テストで結局同等の処理を書くなら、抽象度揃えたインターフェースを提供したほうが旨味もありそうである。

まとめ

  • ユニットはメソッドではなく「モジュール」と考える
  • ユニットテストはモジュールとしての整合性(必要なインターフェースが揃っているか)を確認する役割もある
  • やりすぎはよくないが、対称性のある処理について考慮し、必要に応じてモジュールに提供させる

「決断力」を読んだ

決断力 (角川oneテーマ21)

決断力 (角川oneテーマ21)

読んだきっかけ

将棋を指さない僕でも名前は知っている羽生さん。

読んだきっかけは↓のtweet

すごくいいなぁと思って、本とかないのかなと探してみたのがきっかけ。

この話も本書に登場した。

技術書関連以外の本を読んだのは久しぶりな気がする。

決断、その前に

タイトルも「決断力」だし、目次にも「直感の七割は正しい」といった話が出てくる。

ただ本を読んでいて思ったのはその前の準備、勉強の大切さ。

それがあるからこそ、実践ではシンプルに考えること、大局を見て判断することができるのだろう。

その一方で完璧な準備は存在しないとも思うので、決断のときの心構えが大切なのかもしれない。

最先端を学ぶ

最先端を知らないと、その時点で負けてしまう。

自分の経験や力を発揮する前に勝負が終わってしまう。

最先端を学ぶことから逃げてはいけない。

羽生さんの勉強法

羽生さんの勉強法として下記が紹介されていた。

  • アイディアを思い浮かべる
  • うまくいくか調べる
  • 実戦で実行する
  • 検証、反省する

実戦で試していく、というのが大事なんだなと。

目先の勝利にこだわらずに、長期的な視点に立った場合に、敢えて自分の得意ではない形で戦ったりするなど、常に挑戦している姿勢が素晴らしいと思った。

空白の時間を作る

頭の中に、空いたスペースがないと集中できない。

ぼんやりする時間を大切にする。

継続は力なり

無理をして途中でやめてしまうくらいなら、歩みを遅くしても構わない。

毎日、少しずつ続けることが大切。

まとめ

多くの気づきがあり、モチベーションがもらえました。

将棋を分からなくても楽しめると思うし、ところどころで別業界での喩え話も出てきたりする。
羽生さんの本でKISS(Keep it simple, stupid)の話が出てくるとは思わなかった。

どんな職種の人にも通じるものがありそう。

短くてサクッと読めるし、おすすめです。

MacにVagrantでAnsibleのお試し環境を用意する #vagrant #Ansible

VirtualBoxVagrantを最新化

$ brew cask install virtualbox
$ brew cask install vagrant

VagrantUbuntuの環境を作成

Ubuntu18.04のBoxを使う。

Vagrant box ubuntu/bionic64 - Vagrant Cloud

Boxの追加

$ vagrant box add ubuntu/bionic64

追加の確認

vagrant box list

Vagrantfileの作成

適当な作業ディレクトリで、Vagrantfileを作成する。

$ mkdir -p ansible-sandbox
$ cd ansible-sandbox
$ vagrant init ubuntu/bionic64

ubuntuの起動

$ vagrant up
  • ステータスは vagrant status
  • 停止は vagrant halt
  • ログインは vagrant ssh

sshできるようにする

sshの設定を確認する。

$ vagrant ssh-config

大体こんな感じ。(Hostはansible-sandboxに変更)

Host ansible-sandbox
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile ansible-sandbox/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

~/.ssh/config追記してsshしてみる。

$ ssh ansible-sandbox

inventoryファイルを作成する

inventoryファイルにUbuntuホストの情報を定義する。

$ vi sandbox-hosts

Ubuntu18.04にはPython2が入っていないので、ansible_python_interpreterも設定しておく。

[sandbox]
ansible-sandbox

[sandbox:vars]
ansible_python_interpreter=/usr/bin/python3

Ansibleを実行してみる

$ ansible ansible-sandbox -i sandbox-hosts -m command -a "uptime"

参考