たにしきんぐダム

プログラミングやったりゲームしてます

良い感じに詰めて整形してくれる JSON pretty-printer「jpp」を作りました

jpp というJSON Pretty-Printer を作りました。

github.com

このコマンドはJSONを要素ごとに1つ1つ改行するのではなく、画面内(もしくは指定した幅)に収まる限りできるだけ改行を挟まずに要素を表示します。

そのため、例えばarrayの中身に大量の要素が入っているものや、objectの中身にfieldが大量にあるようなJSONを表示する際、改行をできる限り抑えて表示することによりJSONを見通しよく眺めることができます。

f:id:tanishiking24:20181028224432p:plain

背景

JSONを整形して表示することができるCLIツールとして、jqjsonppや、 python -m json.tool などがありますが(jq はpretty-printのためのツールではないが僕は普段jsonの整形のためによくjqを使っていた)、 これらの既存のJSON pretty-printerを用いて、先に述べたような要素数の多いnodeを含むJSONをpretty-printしようとすると、画面の中に収まらず、 less なりを使ってスクロールしないと全体を眺めることができない、全体を眺めることはできるが見通しが悪い。ということに悩みを感じていました。

ということで画面の横幅に収まる限りできるだけ改行を抑えつつpretty-printすることで見通しよくJSONを眺めることのできる jpp コマンドを作ってみたのでした。

このツールを実装するにあたってはつい先日作った、Wadler's "A Prettier Printer の Go 実装を部分的に用いました。(名前が思いつかず強気な名前になってしまった...)

github.com

このライブラリ(の背後にあるアルゴリズム)は GitHub - prettier/prettier: Prettier is an opinionated code formatter. にも使われているpretty-printerの実装を補助するライブラリです。基本的なアルゴリズムの方針は、与えられた幅に収まる限り一行に収め、幅のうちに収まらない場合は改行するというもので、単純ではあるものの非常に強力なライブラリです。 (scalaだと paiges、swiftだとDoctorPretty などの実装があるようです、prettier/prettier の場合はツールの中に実装が組み込まれています)

JSON以外のpretty-printerを実装するのにも活用できるので、godocや先ほどあげた論文を参考にして使ってみてください。

インストール

Homebrew

$ brew install tanishiking/jpp/jpp

Download binary from GitHub Releases

https://github.com/tanishiking/jpp/releases

Build from source

$ go get -u github.com/tanishiking/jpp/cmd/jpp

使い方

cat example.json | jpp のように標準入力に与えたJSONを整形して出力します。

オプションとして、現在 -w-i を提供しており

  • -w: 整形時に考慮する幅、jpp はできる限りこの幅のうちに収まるようにJSONを整形して出力します。
    • この値は必ずこの幅のうちに収めることを保証するものではないので注意
    • 指定しない場合はterminal widthが利用されます。
  • -i: インデント、デフォルトは2スペです。

https://user-images.githubusercontent.com/9353584/47613438-bb96a700-dad2-11e8-872c-4309d4330aef.png

また出力テキストの色を環境変数やシェル変数を使って変更することもできます。詳しくはREADMEを参照してください。https://github.com/tanishiking/jpp

デモ

f:id:tanishiking24:20181028224152g:plain

機会があれば、是非お試しください。

Instant scalafmt startup using SubstrateVM

github.com

scalafmtはscalametaを利用したscalaのコードフォーマッタです。intellij plugin・sbt plugin・climavenやgradle plugin といった様々な形で提供されており

と様々な方法で利用することができます。

scalafmtの課題の一つはscalafmtの実行にかかる時間です。機能が豊富で複雑なため、ただでさえそれなりに実行に時間がかかってしまうのですが、さらに悪いことにscalafmtの実行に当たってはjvm の起動がオーバーヘッドとなってきます。利用頻度が少ないのならば問題ないのですが、gofmtなどのような軽量なフォーマッタのように気軽に実行できないものだろうか。

このjvm起動のオーバーヘッドを解決する方法の一つがnailgunです。nailgunはJVMプロセス(サーバ)をあらかじめ起動しておいて、クライアント側からサーバー側にjavaプログラムの実行要求をし、サーバー上でプログラムを実行させることでjvmの起動によるオーバーヘッドを解決してくれます。scalafmtからの利用方法

github.com

他の解決方法としてはどうにかしてscalafmtをネイティブバイナリにAOTコンパイルしてしまうことですが、残念ながらv1.6.0-M4段階ではscalanativeサポートはされていません Support Scala Native · Issue #1172 · scalameta/scalafmt · GitHub

しかしGraalVMのツールチェーンの一つであるsubstratevm(とgraal)を使うことでscalafmtをAOTコンパイルしnailgunなしに爆速で実行することができるようになります。

SubstrateVM

  • graal/substratevm at master · oracle/graal · GitHub
  • javaで書かれた(生成されるネイティブイメージに)組み込み可能なVM(ランタイム?)、graalコンパイラによってjavaアプリケーションと一緒にネイティブコードに変換される
  • java(のサブセット)アプケーションの静的解析を行い、実行に必要なモジュールを検出(しそれ以外は捨てる)、これにより生成されるネイティブイメージのバイナリサイズを小さく抑えることができる。

ただしJavaアプリケーションをAOTコンパイルしてしまうので、(特にdynamic class loadingまわりなど)いくつかの制約がある graal/LIMITATIONS.md at master · oracle/graal · GitHub

scalafmtをAOTコンパイルする

先日scalafmtに上記の制約をパスさせAOTコンパイルを可能にするPRが来ていた!のでこれでscalafmtをネイティブイメージにコンパイルできるぞ!

github.com

ということでビルドしてみる

$ sbt cli/assembly
$ native-image -jar scalafmt-cli/target/scala-2.12/scalafmt.jar

いろいろオプションつけたりはできるけどこれでネイティブイメージがビルドできた。楽すぎる...

パフォーマンスの計測

実行環境

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.1 LTS"

$ java -version
openjdk version "1.8.0_172"
OpenJDK Runtime Environment (build 1.8.0_172-20180625212755.graaluser.jdk8u-src-tar-g-b11)
GraalVM 1.0.0-rc5 (build 25.71-b01-internal-jvmci-0.46, mixed mode)


$ cat /proc/cpuinfo | grep "model name" | uniq
model name      : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz

$ cat /proc/cpuinfo | grep "physical id"  | uniq
physical id     : 0

$ cat /proc/cpuinfo | grep processor | wc -l
8

$ cat /proc/cpuinfo | grep "cpu cores" | uniq
cpu cores       : 4

パフォーマンスの計測には Merge pull request #1276 from scalameta/fix-quote · scalameta/scalafmt@5a5747f · GitHub でビルドした3種類のscalafmt-cliを利用しました。

  • scalafmt-jvm
    • coursier bootstrapで固めた普通のCLI
  • ng-nailgun scalafmt
    • この方法でビルドした nailgunを利用したscalafmt-cli
    • ただしnailgunサーバーを温めるために予め一度実行しておき、その後計測環境を同じくした上で二回目の実行にかかった時間を実測値とする
  • scalafmt-native
    • substratevmを利用して作ったscalafmtのネイティブイメージ

フォーマットの実行対象は2種類

scalafmtの設定は scalafmt/.scalafmt.conf at c92153e777984db6d69ec359dd1b1115bd2199d6 · scalameta/scalafmt · GitHub

scalameta/scalafmt全体

$ /usr/bin/time ./scalafmt-jvm
Reformatting...
  100.0% [##########] 142 source files formatted
37.98user 0.69system 0:06.11elapsed 632%CPU (0avgtext+0avgdata 1001288maxresident)k
0inputs+41984outputs (0major+250221minor)pagefaults 0swaps

$ /usr/bin/time ./scalafmt-native
Reformatting...
  100.0% [##########] 142 source files formatted
6.57user 0.17system 0:02.67elapsed 251%CPU (0avgtext+0avgdata 388632maxresident)k
0inputs+952outputs (0major+99109minor)pagefaults 0swaps

$ /usr/bin/time ng-nailgun scalafmt
Reformatting...
  100.0% [##########] 142 source files formatted
0.00user 0.00system 0:01.36elapsed 0%CPU (0avgtext+0avgdata 1796maxresident)k
0inputs+0outputs (0major+73minor)pagefaults 0swaps     

単一ファイル

$ /usr/bin/time ./scalafmt-jvm scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatWriter.scala
12.38user 0.33system 0:02.85elapsed 445%CPU (0avgtext+0avgdata 363232maxresident)k
0inputs+41064outputs (0major+89218minor)pagefaults 0swaps    

$ /usr/bin/time ./scalafmt-native scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatWriter.scala
0.13user 0.04system 0:00.17elapsed 100%CPU (0avgtext+0avgdata 181420maxresident)k       
0inputs+32outputs (0major+41286minor)pagefaults 0swaps 

$ /usr/bin/time ng-nailgun scalafmt scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatWriter.scala  
0.00user 0.00system 0:00.16elapsed 1%CPU (0avgtext+0avgdata 1716maxresident)k    
0inputs+0outputs (0major+70minor)pagefaults 0swaps  

やはりnailgunによる実行が早いのは当然ですが、普通にJVMを起動するCLIの実行と比べるとめちゃくちゃ早くなっていることがわかります:tada: 特に単一ファイルに対するフォーマットの実行のようなshort-live(プロジェクト全体のフォーマットと比べて)な実行の場合はnailgunを利用した場合の実行時間にかなり迫っています。

この実行速度(かつnailgun不要)ならエディタ保存時にscalafmt実行とかしても快適に過ごすことができるのではないでしょうか (もっともプロジェクトに関わる全員のscalafmtのバージョンを揃えないとフォーマット結果がバラバラになりうるのであまり推奨はできない気がする)

所感

scala-nativeが出たときにscala->llvm ir->nativeよりも、scala->jvm bytecode->nativeでネイティブイメージ作れたほうが、scala-nativeが頑張ってるような再実装の嵐を免れることができてお得だよなぁ、実際にはいろいろ制約あって難しいのかなぁと考えていたのですができてしまったよ...

サーバープログラムのようなlong-liveなプロセスに対してはHotSpotVMなどのJITの恩恵が大きそうですが、フォーマッタやlinterやその他CLIツールのようなshort-liveなプロセスにとっては非常に嬉しいツールですね、ありがとうoracle。仕組みがいまいち追いきれてない(論文もsubstratevmに関してはどれを読めばよいのか)なので頑張ってコード読むなりして勉強していきたい。

参考資料

東福寺 - 通天橋

三連休初日、あまりにも天気が良かったのでぶらっと自転車で東福寺に行ってきた、目当ては通天橋。上の写真は通天橋遠景で通天橋に入場するには東福寺境内から入場料400円支払う必要がある。

http://www.tofukuji.jp/temple_map/index.htmlwww.tofukuji.jp

なんで通天橋に行きたかったというと、最近リリースされた Clean Bandit - Solo feat. Demi Lovato [Japan Edition] の1シーンに通天橋の上でダンサーが踊っているシーンを見てハッとなったからであった。 1分56秒あたりから


Clean Bandit - Solo feat. Demi Lovato [Japan Edition]

https://sociorocketnewsen.files.wordpress.com/2018/09/clean-bandit3.jpg?w=1024&h=576

下記サイトより soranews24.com


この辺が橋の中心部、踊ってたところですね

続きを読む

ターナー・南禅寺・ブルーボトルコーヒー

今日は午後お仕事をお休みさせてもらって、京都市文化博物館で催されていたターナー展へ行き、その後南禅寺ブルーボトルコーヒーに行ってきた。

ターナー

https://turner2018.com/turner2018.com

すごく好きで画集をよく見ていたのだけれど、改めて印刷と本物の違いを感じた。質感の違いとか、作品に合った額に入ってるかでこんなにも違うものなんだな...。雲や蒸気や海景や遠方の景色の色使いがが印象的で好きだったのだけれど、建物を含んだ風景のエッチングや詩集の挿絵も良くて惚れ直した。

4月24日からは東京でも展示されるようなので是非行ってくれ!

南禅寺

その後、以前から気になりつつも18時に閉店のためなかなか行けてなかったブルーボトルコーヒーに行くために、烏丸御池駅から東西線に乗り蹴上駅まで。雲一つない快晴だったので山がよく見えてはしゃいでいた。

南禅寺というよりは、南禅寺の周辺の木々が生い茂り木漏れ日が差し込む整備された道が好き。社会人になって平日の昼間に出歩くことがなくなって忘れていたけれど、こういう景色が街のすぐ近くに同居しているから京都は好きなのだよなと思い出した。

平日昼間でも賑わっていた

ブルーボトルコーヒー

ついに京都に出来た!まさかの南禅寺前!しかも18:00閉店ということでなかなか行けずにいたブルーボトルコーヒー京都。コーヒーのお味はいわずもがな、店構えが素敵。

カフェのある建物が奥側にと、道路側に豆などが売られている建物、そしてその間に中庭があり、自由にコーヒーを楽しめる。また行こう。

京都に住んでいると家から電車で3駅程度でこういった景色に会いにいけるので本当にお得、次は自転車でどこかに出かけよう。

ScalaMatsuri 2018 / OSS Hackathon に参加しました

ScalaMatsuri 2018|日本最大級の Scala のカンファレンス

2018年3月16日(金)の Scala OSS ハッカソン / 2018年3月17日~18日の Scalamatsuri2018 に参加しました。楽しかった!

OSS ハッカソン

blog.scalamatsuri.org

ソイヤッて申し込んで良かった。scalikejdbc/scalikejdbcskinny-framework/skinny-framework のプロジェクトへ参加しました。

最終的にハッカソンで取り組んだPRはこれらのPR

@seratchさんにいろいろアドバイスや現状のコードの経緯を聞きつつも、後者はハッカソン時間中にPRを出すに至らず...後日javadocを読み漁って何とかPRを出してマージしていただけました!ハッカソンに参加したからこそ貢献へのとっかかりが掴めたし、シュッとPRを出せました。参加してよかった。 @seratchさんも運営の皆様も本当にありがとうございました!

これからもやっていくぞ

Day1

会場付近の 東京お台場 大江戸温泉物語 | 【公式】大江戸温泉物語グループ|癒しの温泉宿・旅館 に宿泊していました。早めに目が覚めてしまったので、お台場のそこらへんのカフェーで時間をつぶそうと思ったのだけれど休日朝のお台場ほんとに何もないな!!!コンビニでパンを買って海を眺めたりしてた。

LEGACY CODE FROM DAY ONE / @kubukoz さん

https://kubukoz.github.io/legacy-day1/#/

ソフトウェア開発プロジェクト進行におけるアンチパターンのお話

  • コードレビューはしない!
  • コードレビューは時間の無駄。なぜなら俺のコードはいつでも完璧だから
  • nitpickなレビューに一番こだわる
  • 統一的なルールに従わないコードフォーマットの推奨や、高度な技術を取り入れない
  • 早すぎる最適化や、早すぎるモジュール化...

などなどのアンチパターンを面白く話してくださいました。他にもプロジェクト進行におけるアンチパターンやソフトウェアメンテナンスにおけるアンチパターンなどなど、資料面白い。

sbt 1 / @eed3si9n さん

まず Lamport, Leslie. "Time, clocks, and the ordering of events in a distributed system." Communications of the ACM 21.7 (1978): 558-565 を引用してそもそも concurrent の定義を説明して、sbt の DSL ではどのように concurrent な処理を(直感的に)記述できるかということを説明していただいた。非常に分かりやすかった。

そして、sbt1 での 統一的スラッシュ構文や、sbt server による LSP サポート http://eed3si9n.com/ja/sbt-1-1-0-RC1-sbt-server の紹介。scalaで乱立するLSP実装は各所が共同してやっていくワーキンググループができたので、お互い歩み寄っていっているという話を聞いた。


この日は午後から用事があったため、ここで会場を後にした。懇親会に参加できなかったの残念...!

DAY2

朝ごはんです。コーヒーも美味しかった...

JDKのリリースサイクルの変更がScalaにどう影響するか聞きたい

きしださんxuwei-k さんが中心になってお話していただいた。

このあたりのお話?

java 9,10 は短期サポート(半年) Oracle JDK に関しては 11 が 3年のLTS。なので、9,10に関しては手元できちんと動作することをテストしておきつつ、本番環境のバージョンアップはドーンと11まで上げるのが省エネなのではという話を聞いた。 しかし OpenJDK の 11 が LTS という話は特に聞かない気がする。Oracle氏〜

JVM Webアプリケーション メトリクス モニタリング

  • メトリクス取得
  • メトリクスの形式は
    • key value形式 -> (jmx や dropwizard) もう古いぜ
    • key+labels value形式
  • 最低限見てほしいもの
    • heap usage
    • gc lifecycle
    • thread pool
    • connection pool
    • アプリケーション固有のカスタムメトリクス
    • cpu / リクエスト数 / レスポンスタイム / ジョブキュー

などなど

あと3日でJava 10がリリースですが、興味ある人いますか?

出ましたね!

まだ内容追えてない...!

ノベルティ / たこ焼き

何故かたこやき配布してた。美味しかった

個人的に気に入ったノベルティの靴下と箸。珍しい! 箸は開けてみると何も書かれてないただの上等な箸だった! 株式会社ファンコミュニケーションズ さんはそれで良いのか!と思ったけれど逆に強烈に印象に残っているし、この箸使うたびに思い出している。

scala matsuri 2018 本当に楽しかったです。次回は何らかの形で貢献できると良いなと思っています。