みんなが出て行くチーム

僕が作りたいチームは

メンバーを最大限稼働させて成果をあげるチームじゃなくて

スキルの高いメンバーによって支えられているチームじゃなくて

在籍年数の長いメンバーがその経験と勘でなんとかプロジェクトを成功させるチームじゃなくて

よく知ったメンバーがあうんの呼吸で仕事を進めるチームじゃなくて

全員が成長することでチームも成長していくようなの、でもなくて

みんなが出て行くチーム。

かなぁって思った。

色んな人が、そこに入りたいなと思って、そこで成長して、そこから出て行って、数年経つとメンバーは全員入れ替わってるんだけど、チームとしては成長し続けてくような「場」。

かなぁって思った。

今日は淡麗かなー。

今日は引力がないなぁ

忙しいときは、家族が寝た後にこそっと帰って、起きる前にこそっと家を出るから、結局顔をみないんだけど。

それでも、引力があるんだよなぁって、今日みたいに、みんながお泊まりに行ってるときに、再確認するのであった。

黒ラベルでも買って帰ろー。

Spring Boot + Gradle on Intellij IDEA でアプリケーション実行中にコードの変更反映と Thymeleaf テンプレートの変更反映

これまではずっとEclipse(STS) + Mavenでわいわいコード書いて過ごしてきたんだけど、最近IntelliJ IDEA使い始めたうえに、MavenじゃなくてGradle使い始めて、頭で考えたことがそのまま手に繋がらなくてぐぬぬってなりながらコード書いてる。まぁ、それ自体は楽しんでる。

んで、どうやったらいいんだろう?って思ったのが

変更が反映されない

ってこと。次の2つ。アプリを起動(bootRun)してる状態で

  1. コードを変更してもDevToolsがリロードしてくれない
  2. Thymeleafのテンプレートの変更が反映されない

結論から言うと

どちらも解決しました。で、コードの変更の方はDevToolsだけじゃなくて、SpringLoadedというものもあるって教えていただいたんですけど、最終的にはDevToolsにすることにしました。

つぶやき

STSのときはどっちも大丈夫だったんだけど、IntelliJだとそういうもんなのかなぁ?いやー、そんなことないよなぁ?と思いつつ、つぶやき。

そしたらしおしおさんが「昔のやつなので、今できるかは分からないですが」ってコメントつきでSpringLoadedを教えてくれました。(∩´∀`)∩ワーイありがとうございます!SpringLoadedって全然知らなかったんだけど、アプリを再起動せずにHotReloadしてくれるみたいで便利そうだなー。

siosio.hatenablog.com

んで、DevToolsとかSpringLoadedとかをごにょごにょしながら「んむーうごかんー」とかしばらく戦ったのですが。

DevToolsとかSpringLoadedとかを使うときには

どちらのツールも、この2つの設定をすれば動きました。変更したときに自動でビルドする設定。

まずは "Build project automatically"

f:id:bufferings:20170724002546p:plain

んで、もういっこ。上記のままだと、IDEAからbootRunでアプリを起動してるときにはビルドが走らないのでそれを有効にしてあげた。

参考: Intellij IDEA – Spring boot template reload is not working

Help > Find Action... から、"Registry" って打って出てきたやつで "compiler.automake.allow.when.app.running" にチェック

f:id:bufferings:20170724003032p:plain

あとは、それぞれのツールの説明を見ながら動かせばOK。

spring-boot-devtools: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#howto-reload-static-content

SpringLoaded: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#howto-reload-springloaded-gradle-and-intellij-idea

SpringLoadedの方が反映は早いんだけど、spring-boot-devtoolsの再起動するって方がなんとなく好きなのと、spring-boot-devtoolsが有効なときはThymeleafのキャッシュが自動でoffになるので、spring-boot-devtoolsを使ってみることにしました。SpringBootのドキュメントにもおすすめって書いてあるしね。

(spring-boot-devtoolsを使ってないときは、自分でapplication.propertiesでspring.thymeleaf.cache=falseを設定すればキャッシュがoffになります)

Thymeleaf

については、ぽざうねさんがこれを教えてくれて

intellij idea - How do I enable Thymeleaf Live Reloading in Spring Boot 1.3 - Stack Overflow

bootRun {
    addResources = true
}

これを入れたら変更が即時反映された。(∩´∀`)∩ワーイ

しおしおさん、えいりゅーさん、ぽざうねさんありがとー!

シュークリームもぐもぐ

ほんとはもっといいものを作りたいのに!と思いながら、たぶん60%くらいの満足度で作ってしまってる。

コードの綺麗さとか、テストの読みやすさとか、アーキテクチャとか、自動化とか、そういうのとか色々。

それに対する、ビジネスの状況だったり、時間だったり、チームのスキルだったり、お金だったり、そういう色々な制約で。

それに対して「本気出せばもっと良いものが作れるのに!」とは思わなくて。まぁ、そういう実力なんだよなって。思う。

んでも、だいたい毎回60%くらいなので。自分がスキルアップしとけばできあがるものは良くなりそう。

だし、実際のところ残りのうちの20%くらいは横道にそれる部分で使ってる気がする。次の成長のために。

今週もお疲れさま!

Macでgit graphのエイリアス設定せんでよくなってたっぽい?←よく分かってない

いつもはね git graph でグラフが出るようにエイリアス設定してたんだけど。んで、いつからか、うすうす気づいててたんだけど、MacOSにgitをインストールしたらデフォルトでいくつかエイリアスが入ってるっぽい?どっかにドキュメントあるんかな?

$ git alias
a    => !git add . && git status
aa   => !git add . && git add -u . && git status
ac   => !git add . && git commit
acm  => !git add . && git commit -m
alias    => !git config --list | grep 'alias\.' | sed 's/alias\.\([^=]*\)=\(.*\)/\1\  => \2/' | sort
au   => !git add -u . && git status
c    => commit
ca   => commit --amend
cm   => commit -m
d    => diff
l    => log --graph --all --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset'
lg   => log --color --graph --pretty=format:'%C(bold white)%h%Creset -%C(bold green)%d%Creset %s %C(bold green)(%cr)%Creset %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
ll   => log --stat --abbrev-commit
llg  => log --color --graph --pretty=format:'%C(bold white)%H %d%Creset%n%s%n%+b%C(bold blue)%an <%ae>%Creset %C(bold green)%cr (%ci)' --abbrev-commit
master   => checkout master
s    => status
spull    => svn rebase
spush    => svn dcommit

この git alias ってコマンド自体がエイリアスなんやね。デフォルトのまま使うのが好きなので結構嬉しい。

git l だとこんなで

f:id:bufferings:20170627230355p:plain

git lg だとこんなで

f:id:bufferings:20170627230759p:plain

git ll だとこんなで

f:id:bufferings:20170627230901p:plain

git llg だとこんなん

f:id:bufferings:20170627230946p:plain

僕は git l が一番使いそう。

ちな、バージョンはこんな感じ。でもちょっと前からそうだった感じする。

$ git --version
git version 2.13.1

設定自体は /usr/local/git/etc/gitconfig に入ってるっぽいね。Ubuntuの方にはこういうのないし、MacOSだけなのかな?なんでなんだろう?←よく分かってない

Schema Registryについて

昨日の続き。

bufferings.hatenablog.com

Avroを使ってメッセージをシリアライズ・デシリアライズするのに、スキーマを保存しておいてくれる場所があると便利だよなーってことで、Schema Registryが(僕の中に)登場。

Schema Registry?

Schema Registry — Confluent Platform 3.2.2 documentation

Avroのスキーマを保存したり取得したりするためのRESTfulなインターフェイスを持ってる。スキーマのバージョンを保存してるので、スキーマエボリューション的な用途で使えるっぽい。僕は、まだスキーマエボリューションについては勉強してないので、「ふーんバージョンがあるんだね」ってくらい。

Confluent Platform?

Kafkaを作ったチームがConfluentって会社を立ち上げて、Kafkaを真ん中に置いたConfluent Platformっていうプラットフォームを提供してるみたい。Kafkaを中心として便利なツールを色々提供してくれてて、Open Source版とEnterprise版がある。

f:id:bufferings:20170626175453p:plain

Confluent: Apache Kafka & Streaming Platform for the Enterprise より

んで、Schema RegistryはそのOpen Source側にも含まれてる。

f:id:bufferings:20170626175925p:plain

Download Confluent Open Source & Confluent Enterprise より

ソースはこちら。Apache License 2.0ね。

GitHub - confluentinc/schema-registry: Schema registry for Kafka

Schema Registryを動かしてみる

ということなので、Confluent Platformの中に含まれてそうなんだけど、僕はもうKafkaは別で動かしてたから、今回はConfluentが用意してくれてるDocker Imageを使うことにした。

この辺読みながら → Quickstart — Confluent Platform 3.2.2 documentation

こいつを使う → https://hub.docker.com/r/confluentinc/cp-schema-registry/

僕は発表のデモ用にDocker Composeを使ってローカルで色々立ち上げたんだけど(あ、うまく動いてなかったけど)その中からSchema Registryの部分だけを抜き出すとこんな感じ。

  schema-registry:
    image: "confluentinc/cp-schema-registry:3.2.1"
    network_mode: "host"
    environment:
      SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL: "localhost:2181"
      SCHEMA_REGISTRY_HOST_NAME: "localhost"
      SCHEMA_REGISTRY_LISTENERS: "http://0.0.0.0:8081"
      SCHEMA_REGISTRY_ACCESS_CONTROL_ALLOW_ORIGIN: "*"
      SCHEMA_REGISTRY_ACCESS_CONTROL_ALLOW_METHODS: "GET,POST,PUT,OPTIONS"
    depends_on:
      - "kafka"

内容的には

  • ホストネットワークモードで動かして、ホスト側のlocalhost:8081で動く
  • SCHEMA_REGISTRY_ってプレフィックスの環境変数で、Schema Registryに渡す設定を指定できる
  • KAFKASTORE_CONNECTION_URLで、Zookeeperの場所を指定
  • その環境変数ACCESS_CONTROL_ALLOW_ORIGINとMETHODSのところはなくても大丈夫。Schema ResgistryをWebUIで見られるようにしてくれるツールを使うために設定してる

ちな、docker-compose.yml全体はこちら。

https://github.com/bufferings/kanjava-party-2017/blob/master/environment/infra/docker-compose.yml

動作確認

# "Kafka-key"ってSubjectで登録
~ $  curl -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
>     --data '{"schema": "{\"type\": \"string\"}"}' \
>     http://localhost:8081/subjects/Kafka-key/versions
{"id":6}
~ $

# 登録されてる全部のSubjectを取得(デモで使ったので他のも登録されてる)
~ $ curl -X GET http://localhost:8081/subjects
["InventoryRecoveryRequestedEvent","Kafka-key","Tweet","InventoryReservationRequestedEvent","TweetWordTop5","DifferentSchema"]

動いてる!

Schema Registry UIを動かしてみる

Schema RegistryをRESTで使うんでいいんだけど、WebUIあると便利だなーって思ってうろうろしてたらLandoopってところがSchema Registry UIを出してた。Kafka周りの色んなツールを提供してるみたいね。

Landoop | Kafka Web Tools

Schema Registry UIのソースはこち

GitHub - Landoop/schema-registry-ui: Web tool for Avro Schema Registry |

ライセンスはBSLってので、Kafkaのサーバーインスタンスが4台までは無料で使えるみたい。

http://www.landoop.com/bsl/

例によってDockerがあるのでこれで試した。これを使うのにさっきのACCESS_CONTROL_ALLOW_ORIGINとMETHODSが必要だから忘れずにね。

https://hub.docker.com/r/landoop/schema-registry-ui/

  schema-registry-ui:
    image: "landoop/schema-registry-ui:0.9.1"
    environment:
      SCHEMAREGISTRY_URL: "http://localhost:8081"
    ports:
      - "9001:8000"
    depends_on:
      - "schema-registry"

8000番は別のアプリで使いたかったので、こっちはブリッジネットワークモードでで9001をマッピングしといた。

こんな感じでSchema Registryの内容が見られる。

f:id:bufferings:20170626182750p:plain

(∩´∀`)∩ワーイ

スキーマデータはKafkaに保存されてるっぽい

もういっこLandoopのツールで、Topicの中身を見れるツールを使って見てみたら、デフォルトで_schemaって名前のTopicにスキーマ情報が入ってるっぽいね。

f:id:bufferings:20170626184234p:plain

ここに説明が書いてあった。

Design Overview — Confluent Platform 3.2.2 documentation

まとめ

Schema RegistryをDockerで起動して叩いてみて、その後UIを立ち上げて見てみた。って話でした。

今日はここまで。次は、Javaで書いたKafkaクライアントからどうやって使うかってところかな。

Avroについて

昨日、関ジャバで喋ったのしかったよー(∩´∀`)∩

bufferings.hatenablog.com

その発表のために色々と新しいことを学んだので、ちょこちょこ気が向いたときにアウトプットしておこうと思う。数カ月後に全て忘れているであろう自分のために。

てことで、今日はAvro。余談ですが、勉強会に行くと勉強になるけど、勉強会で登壇するともっと勉強になるからおすすめです!

Avroとの出会い

同じ学年にAvroさんという人がいるのは知ってたけど、違うクラスだから喋ることもないかなーって思ってたくらいの距離感(なんの話?)

名前を初めて聞いたのは、去年のSpring Oneに行った時。Spring Cloud StreamでData Microserviceだー!って言葉が押し出されてて。Avroの名前がでてきてたのはSchema Evolutionという文脈の中だったなという印象。「メッセージング系の処理やってると悩むのは、メッセージのスキーマを変更したいときよね。この問題をどうやって扱おう?そこでAvroを使って、スキーマの進化について考えてみよう」って感じだったかな。

でも、僕はSpring Cloud Streamは別に追いかけなくていいかなーと思ってて(好き嫌いとかじゃなくて、単純に優先順位の問題ね)。なので、Avroのことも「ふーん、そんなのあるんだー」くらい。

スキーマがあると良さそう?

登壇駆動ってことで、タイトルを先に決めてから「よし!Kafkaを勉強するぞー!」って触りはじめて。

といっても、実は去年の秋のJJUG CCCで発表したときも少しKafkaを触ってたんだけど、その時はドメインイベントのオブジェクトをJSONシリアライズ・デシリアライズしてた。

今回も同じようにしたらいいかなーと思ってたんけど、去年から一歩進めて複数のサービスに分割してイベントを扱おうと思った時に「はて、これは、決めごとがあるほうが良さそう?」って思った。

同じアプリの中でメッセージのやり取りをするんだったら、そのクラスをやり取りすればいいからJSONでもいいかなーって思ってたんだけど。サービスごとに複数のチームに分かれて作業するとかを考えるとインターフェイスみたいなものを決める方が良さそうだなーって思った。「ここ、数字だと思ってたら文字列も入ってくるのか!」とか「nullの場合あるの?初期値とかは?」とかならないように。しかもプログラミング言語に依存しない形で。

だから、スキーマがある方が良さそう。ということで、Avroさんに会いに行くことにした。

Avroとは?

公式サイト: Welcome to Apache Avro!

今ぐぐってみたんだけど、日本語だとOracleのサイトの説明が分かりやすい 第7章 Avroスキーマ Oracleで使用するケースの話みたいだけどね。

スキーマ定義に従って、データをコンパクトなバイナリ形式でシリアライズ/デシリアライズする。という感じなのかな。

Javaのサンプル

Apache Avro™ 1.8.2 Getting Started (Java)

スキーマ定義ファイルを元にJavaのクラスの生成もできるみたいだけど、好みの問題で、僕はそれは使わずに、GenericRecordを使うことにした。Mapみたいなものね。

だから、上記のドキュメントの「Serializing and deserializing without code generation」の方を見てた。

シリアライズ

例えば OrderItemCreatedEvent.avsc って名前のファイルを用意して

{
  "name": "OrderItemCreatedEvent",
  "type": "record",
  "fields": [
    {"name": "orderGroupId", "type": "string"},
    {"name": "orderItemId", "type": "string"},
    {"name": "orderGuestId", "type": "int"},
    {"name": "orderGuestName", "type": "string"},
    {"name": "productId", "type": "string"},
    {"name": "quantity", "type": "int"},
    {"name": "orderedOn",  "type": "string"}
  ]
}

こんなコードを書くと

    Schema schema = new Schema.Parser().parse(new File("OrderItemCreatedEvent.avsc"));

    GenericRecord record = new GenericData.Record(schema);
    record.put("orderGroupId", "b78cbc2c-ee1b-4c03-9b8c-70abf121b0d1");
    record.put("orderItemId", "7e570f08-65bd-4b1f-be75-3d977d818023");
    record.put("orderGuestId", 123456);
    record.put("orderGuestName", "bufferings");
    record.put("productId", "1d8bcd93-2b9c-4225-a525-8f750d4c444c");
    record.put("quantity", 4);
    record.put("orderedOn", "2017-06-24T06:57:14.090");

    File outputFile = new File("data.avro");
    DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<>(schema);
    try (DataFileWriter<GenericRecord> dataFileWriter = new DataFileWriter<>(datumWriter)) {
      dataFileWriter.create(schema, outputFile);
      dataFileWriter.append(record);
    }

こうなった

f:id:bufferings:20170625133757p:plain

おぉ。スキーマも一緒に出力されるのか。されないと思ってた。そっか、これでもJSONと比べていいのは、複数レコードを保存するときにスキーマを最初に一回だけ書くところなのかな。

シリアライズ

公式サイトに書いてある通りにこんな感じ。インスタンスを再利用してるの面白いね。大量レコード対応って感じすね。僕は1レコードのシリアライズにしか今は興味がないけど。

    Schema schema = new Schema.Parser().parse(new File("OrderItemCreatedEvent.avsc"));
    File dataFile = new File("data.avro");

    DatumReader<GenericRecord> datumReader = new GenericDatumReader<>(schema);
    GenericRecord record = null;
    try (DataFileReader<GenericRecord> dataFileReader = new DataFileReader<>(dataFile, datumReader)) {
      while (dataFileReader.hasNext()) {
        record = dataFileReader.next(record);
        System.out.println(record);
      }
    }

出力はこんな感じになる。

{"orderGroupId": "b78cbc2c-ee1b-4c03-9b8c-70abf121b0d1", "orderItemId": "7e570f08-65bd-4b1f-be75-3d977d818023", "orderGuestId": 123456, "orderGuestName": "bufferings", "productId": "1d8bcd93-2b9c-4225-a525-8f750d4c444c", "quantity": 4, "orderedOn": "2017-06-24T06:57:14.090"}

んでも、スキーマ情報がデータファイルに入ってるのに、デシリアライズのときにもスキーマファイルが必要なのは不思議だ。合ってるかどうかチェックでもするのかな?

ま、気にしない。

Kafkaの場合

んで、Kafkaについて考えてみると、↑の方式でみたいに毎回スキーマ情報を書き込むのってなんかいけてない感じがする。それより、どっかにスキーマ情報を登録しといて、それを使ったほうが良くね?って思った。ら、ちゃんとあった。それがSchema Registry。

Schema Registry — Confluent Platform 3.2.2 documentation

今日はこんなとこかな。次はSchema RegistryとKafkaについて書こうかな。

広告を非表示にする