Magnolia Tech

techっぽいことを書くブログです

sbt 1.0時代のPlugin事情

sbt-scalatraというsbt pluginを1.0対応させるためにやったことをまとめておきます。

sbt 1.0対応作業一覧

sbt 1.0対応のpluginをゼロから作るときの詳しい解説は、公式ドキュメントにきちんと書かれているので、まずはそれを読む。

sbt Reference Manual — Plugins

ここでは既にsbt 0.13系のPluginをアップデートしてsbt 1.0対応したときのことを書く。ざっと以下のような作業を行った。

  1. AutoPlugin化
  2. project/pluginをアップデートする
  3. 複数のsbtのバージョンに対応させる
  4. plugin間の依存関係の定義
  5. pluginを自動で有効にする
  6. settingsの対応
  7. deprecatedなメソッドの書き換え

AutoPlugin化

sbt 1.0以降はAutoPluginしかサポートされなくなるので、従来Plugin classを継承していた箇所をAutoPlugin classの継承へ書き換える。

単純に書き換えるだけでOK。

これを…

object ScalatraPlugin extends Plugin {

こう書き換える。

object ScalatraPlugin extends AutoPlugin {

AutoPlugin自体の詳しい解説はAPI Documentや、AutoPlugin登場時の解説記事を読むと分かりやすい。

http://www.scala-sbt.org/1.0.2/api/sbt/AutoPlugin.html

http://eed3si9n.com/ja/sbt-preview-auto-plugins

project/plugin.sbtをアップデートする

project/plugin.sbtに書かれているsbt pluginのバージョンをsbt 1.0対応したものへアップデートする。

sbt 1.0への対応状況はsbtのWikiを参照すると良い。きちんとアップデートされている。

github.com

ここで一つでも使用しているsbt pluginがsbt 1.0対応できていなければ1.0対応のコンパイルが通らないため、先にそちらのpluginをアップデートするか、issue上げて直してもらうか、PR送るか、という3択となる(もしくは使うのを止める)。

plugin間の依存関係の定義

AutoPluginでは、Plugin同士の依存関係を定義できる。

例えばsbt-scalatraのScalatraPluginは、xsbt-web-pluginJettyPluginに依存していて、ScalatraPluginを有効にすれば自動的にJettyPluginも有効になる(AutoPlugin化される前は明示的に別々に有効にする必要が有った)。

依存するPluginは、project/plugin.sbtではなくbuild.sbtに定義する。その際addSbtPluginではなく、libraryDependenciesを使う。

sbtの複数バージョンに対応させるため、build.sbtに以下のように定義する(xsbt-web-pluginに依存する場合の指定例です)。sbtとScalaのバージョンがターゲットのsbtのバージョンによって自動的に選択される。

libraryDependencies += {
  Defaults.sbtPluginExtra(
    "com.earldouglas" % "xsbt-web-plugin" % "4.0.0",
    (sbtBinaryVersion in pluginCrossBuild).value,
    (scalaBinaryVersion in pluginCrossBuild).value
  )
},

なぜかsbtのドキュメントにはsbtPluginExtraのことが書かれていないが、以下のブログを読むと構造が分かる。

始める sbt - プラグインの使用

実際のplugin間の依存関係は、以下のようにrequiresをオーバーライドすることで定義する。

import sbt._
object ScalatraPlugin extends AutoPlugin {
  override def requires = JettyPlugin

複数のsbtのバージョンに対応させる

当面sbt 0.13も利用され続けると思われるので、0.13系と1.0系の両方に対応させるためには、build.sbtにcrossSbtVersionsを定義し、クロスビルドを有効にする。

例えば以下のように記述すれば、0.13.16と、1.0.2に対応したバイナリを作成する。

crossSbtVersions := Seq("0.13.16", "1.0.2"),

普通にcompileするとproject/build.propertiesのバージョンを参照するので、^comile^scriptedのように先頭に'^'を付けてコマンドを実行する。

project/build.propertiesに指定するバージョンは、crossSbtVersionsに指定したバージョンのうち、どちらかと必ず合わせた方が良い。そうしないと無駄に色々なバージョンのsbtをダウンロードすることになる。

pluginを自動で有効にする

下記のように定義すると、Pluginは自動的に有効になる。

override def trigger = allRequirements

triggerをオーバライドしない場合、build.sbtの中で明示的にpluginを有効にする。

enablePlugins(ScalatraPlugin)

例えば一つのbuild.sbtに複数のサブプロジェクトが有り、特定のサブプロジェクトでしか有効にする必要が無いPluginであれば明示的に有効させるべきだし、ソースコードフォーマッターのようにプロジェクト横断的に使うものであれば明示的に有効にさせる必要は無いかもしれない。その辺りはユースケース次第だが、どちらにしてもドキュメントには明示した方が良い。

settingsの対応

AutoPluginより前はpluginごとに色々な設定名が使われていたが、AutoPlugin化以降は、MyPlugin.projectSettingsみたいにpluginのclass名に続けてprojectSettings又はbuildSettingsという名称で統一された。

互換性のため、既存のsettingsの名称を変える必要は無いが、以下のようにprojectSettingsに代入しておくことでprojectSettings形式で使えるようにする方が良い。

override lazy val projectSettings = scalatraSettings

またsettingsを使って有効にしたいtaskKeyやsettingKeyはautoImportに定義する。

deprecatedなメソッドの書き換え

sbt 0.13でdeprecatedになっているメソッドはsbt 1.0では削除されている。そのため下記のドキュメントを参考にソースコードを書き換える。

sbt Reference Manual — Migrating from sbt 0.12.x

互換性の関係からどうしても一つのソースコードにまとめられない場合は、それぞれのsbtのバージョンに対応したディレクトリを用意することで、sbtのバージョン別ソースコードを用意することができる(sbtのAPIが変わったものや、Scala 2.10と2.12の非互換など)。

src/main/scala-sbt-0.13/

src/main/scala-sbt-1.0/

具体的なコード例は、sbt-scalatraの例を参考にすると良い。

github.com

おわりに

一つ一つの作業は単純だけど、特にsbt 1.0で内部構造が大きく変わっているものなど、クラスの階層構造が変わっていたり、別リポジトリへ移っていたりと、意外と移動先を探すのが大変だった。

そこはひたすらsbt自体のソースを見るしかない。あとsbt自体のドキュメントがかなりの量あるので、それを読み込むのがけっこう大変だった。

とりあえずsbt 1.0にアップデートしないとJava9で動作しないので、前に進むしかない。ソフトウェアエンジニアに後退する、という選択肢は無いので進もう!

MacBook Pro 2017モデル 13″の電源アダプタを快適に持ち運ぶ

MacBook Pro 2017モデル 13″を購入した。

USB PDになれば純正以外の充電器が選び放題で、外出用のサードパーティー製の充電器とケーブルを買うぞ!と意気込んだものの、MacBook Proで使うとなると結局これ!という物が無いのが実情…

thewirecutter.com

しょうがないので、純正の充電器とケーブルを持ち運んでいるけど、以前の充電器と違ってType-Cの充電器では電源ケーブルを巻き取ることができないし、純正USBケーブルはしなやかさに欠けていて、まとめづらい。

クルッと巻いてケーブルバンドで固定して、コクヨのSHELLBROというペンケースに、ケーブルと充電器を収納して運んでいます。いまのところ、これが一番カバンの中で収まりが良い。

オウルテック 結束マジックテープ OWL-SKSN03

オウルテック 結束マジックテープ OWL-SKSN03

クラウドファンディングで良さそうなアクセサリケースを見つけたけど、すぐに入手できないので、様子見。

www.makuake.com

Markdown Night 2017 Summerというイベントを開催しました

やるぞ!という話になって2ヶ月あまり、ついに開催しました。

早速色々とまとめて頂いているので、イベントの様子はそちらをご覧頂ければと思います。

スライドも既にアップされていますので、見逃した方はそちらをご覧下さい。

tech.mercari.com

togetter.com

blog.bitjourney.com

当日は80人近くの方に参加頂き、懇親会含めて、非常に盛況でした。 会場・懇親会を提供頂いたメルカリ様、並びに運営をサポート頂いた社員の方に感謝致します。

少しタイムテーブル的に余裕が無かったかな、という点が反省でしたが、次回に生かしていきたいと思います。

第2回の開催は今回の反響次第ですが、我こそはMarkdownについて話したい!という方がいらっしゃましたらご連絡下さい。

※読み・書き・そろばん・markdownという標語(?)を意外と拾って頂いたのでちょっと嬉しかった…

「現場で役立つシステム設計の原則」を読んだ

細々と書き直したので、最初の公開の時とちょっと変わっています。


最近ようやくこの手の「良い設計」をちゃんと解説してくれる書籍が出版されるようになってきて、良い時代になったなぁ。データベースであればドメインを定義したり、正規化といった、ある程度定型的な観点が有る手法が有るので割と以前から良い設計に対するアプローチが明確だった気がするけど、アプリケーションになるとなぜか、あまり見かけなかった。

今までコードを書いたことが無い人が読んでも、今一つ納得感が無いような気がするけど、一度でも他人のコードの改修に苦労したことが有れば、発見が有る本。

全編に渡って素晴らしい知見が多いのだけど、まずはChapter1の「小さくまとめてわかりやすくする」だけでもしっかり読んだ方がいい。特に値オブジェクト重要。

値オブジェクトを使ったリファクタリングと機能追加を体験するだけでも、ソフトウェアの複雑さのコントロールについての一番大事なポイントが理解できるんじゃないかと。ソフトウェアの機能追加を安定的に行っていくためには、影響範囲をどうやって正しく特定するか?ということに尽きるんだけど、それが型レベルで追跡し易くなるだけで格段に楽になるし、想定外の値が混入していないことも保証されるので、安心できる。

複雑なソフトウェアに対するリファクタリングと機能追加をみっちりやる体験講座が有れば良いのに!

Chapter2以降も良い話が満載だけど、まずはChapter1を腹落ちするまでコードを書いた方がいいんじゃないかと。

良い設計を行うために

設計の話ということで、先日のBuildersconでしんぺいさんが発表された「複雑なJavaScriptアプリケーションに立ち向かうためのアーキテクチャ」というトーク本編とQAの中でとても良い言葉が有ったので、その話とリンクするのですが…

techblog.reraku.co.jp

スライドに出てくる「設計に正解は無い」という言葉と、QAの中で出てきた「良い設計か否かは機能追加するまで分からない」という言葉は大事だな、と。○○すればOKなんてことは無くて、未来にどんなことが起きる得るか、それをしっかり考えて(かつ、考えすぎず)その環境においてベストな設計を自らの意思で選択することが大事なんじゃないかと思うわけです。

あと「機能追加するまで良い設計か分からない」ということは裏を返せば、過去の機能追加で苦労した所をしっかり振り返っておけば、自分たちに必要な保守性や、拡張性はおのずと分かるハズです。

Markdown Night 2017 Summerというイベントを開催する

Builderscon Tokyo 2017の興奮も覚めやらぬ中、Markdown Night 2017 Summerというイベントを開催することにしました。

connpass.com

普段吉祥寺.pmというイベントを定期的に開催しているけど、そろそろ別の形式のイベントもやってみたい、ということでgfxさんの発案に乗っかり、更にはメルカリ様の会場提供という嬉しい展開も有り、なかなか盛り上がる予感です。

Builderscon 2017に行ってきた

去年のBuilderscon2016は行けなかったけど、今年はチケットを確保してYAPC::Asia 2014以来の日吉へ。

builderscon.io

参加できたのは8月4日の二日目のみ、懇親会は不参加と限定的な参加でしたが、非常に面白いトークを聴くことができました。

DeepLearningによるアイドル顔識別を支える技術

牧さんのオープニングを聞いたら間髪を入れずすぎゃーんさんのトークへ。 最後の方のデモで「これは認識するかな?」とすぎゃーんさんが発言していて、「自分で識別してるよね?」ってかけ声が一番のハイライト。

speakerdeck.com

管理画面を作ったり、色々なハックが有ったりと、さざまななノウハウの上に成立してて、ほんと凄い。

まさに脱ドルオタされたすぎゃーんさん卒業公演にふさわしい内容でした(顔認識は続けるそうなので、卒業じゃないけど)。

「アイドルとはなにか?」「実用的とはいったい」などなど、名言の多いトークでした。

マイクロチームでの高速な新規開発を支える開発・分析基盤

色々な制約の中で、新しいサービスを立ち上げるための数々の工夫点が端的にまとまっていました。

speakerdeck.com

やらないことを明確に決めているところと、最初から分析基盤をきちっと作り込んでおくこと(ログとか)の大事さがよく分かりました。

実践的で学びが多い。

複雑なJavaScriptアプリケーションに立ち向かうためのアーキテクチャ

最も実践的な学びの多かったトーク。これはあーだこーだ言ってもしょうがないので、設計を生業とする人は全員スライド見た方が良い、JavaScript関係無いと言えば、関係無い。もっと本質的な話。

speakerdeck.com

QAで良い設計ができたと分かるタイミングは?みたいな話があって、「機能追加をするとき」って回答が一番良かった。だからこそ機能追加する時に、やりづらかったところと、やりやすかった所は必ず次の開発に生かすためにも残すべきだと思う。

RDBアンチパターン リファクタリング

builderscon 2017ベストトークのそーだいさんのトーク。これもとにかく読んだ方がいい。

speakerdeck.com

マジカルな設計を天才がなんとかしてしまう展開は「あーーーー」って思ってしまった。

横山光輝三国志 全文検索システム

直接発表が聞け無かったけど、TwitterのTLがこれで埋まった力作。

docs.google.com

オンプレ、クラウドを組み合わせて作るビックデータ基盤 -データ基盤の選び方-

これもTwitterのTLがけっこう気になった。まだスライドが出ていないのか、見つけられなかった。

お昼ご飯

f:id:magnoliak:20170805201113j:plain

スポンサーセッションのお弁当がもの凄い行列だったので、gfxさん、かるぱさん、かじさんと歴戦のPerl Mongerな方々と外へご飯を食べに行きました。

意外とイベントの懇親会で夜話す機会は有ってもお昼ご飯を食べながらテックトークする機会が無かったので貴重な体験でした。

終わりに

カンファレンスのお楽しみと言えばノベルティです。特にトートバックは色々と使えて嬉しい。

f:id:magnoliak:20170805203913j:plain

あと、個人スポンサーで参加したのでパーカーと、しゃもじを頂きました。

f:id:magnoliak:20170805201001j:plain

見透かされている!と思うほどのピッタリのやつが出てきたので、これ最高です。

1日目、3日目も色々と面白そうなトークが目白押しで、TwitterのTLも大変なことになっていたので、ぜひ来年も参加したい。

USB Type-Cへ移行するためのメモ

MacBook ProのUSB Type-C搭載モデルへ移行するための買い物メモ。USB Type-Cはあまりに難しい。

7/8 追記 USB PDのケーブル最大長を間違えていたので修正(2.0m -> 4.0m)。ついでにモバイルバッテリのことを追記。

充電

USB PDという規格に対応しているので、色々なサードパーティー製が選べるはずが…という状況。

充電器

いまのところサードパーティー製のUSB PD規格にちゃんと対応した充電器はほとんど流通しておらず、ほぼAnker一択の模様。ただし、30Wモデルなので、充電スピードはMacBook Pro付属のものより遅くなる。純正よりは軽いし、価格も安価なので外出先で使う分には良いかも。

参考にしたのはこのサイト。

hanpenblog.com

ケーブル

MacBook Proの純正電源アダプタは61W以上ので、充電には5AをサポートしたUSBケーブルが必要となる。Apple純正のケーブルは当然5A対応だが、明示的にPD 5A対応と書かれたケーブルは意外と少なく、それ以外のケーブルでは3Aまでとなる。

前述のAnkerの充電器は30Wなので、そちらと一緒に使うなら5Aのケーブルは不要といえば不要だが、純正電源アダプタに使うことも考えて5A対応のものを買っておいた方がよさそう。

ただし、そうすると選択肢はほとんど無い。ELECOMあたりがよく売られている。

特に1.0mを超えるものが無い。USB PDの規格上は4.0mまで対応するが、USB 3.1 Gen2のケーブル最大長が1.0mなので、両方に対応すると1.0mまでとなるため(Gen1だと2.0mまでだが、USB PD 5A対応かつ、USB 3.1 Gen1対応で2.0mのケーブルは見つけられなかった)。

ストレージ接続用と共用せず、充電用と割り切った方が良さそう。

なので、Appleはわざわざ「USB-C 充電ケーブル」という言い方をしている。実際にはデータ転送はできるが、あくまでUSB 2.0の規格(最大480Mbps)までしか転送できない。

アップル USB-C充電ケーブル(2m) MLL82AM/A

アップル USB-C充電ケーブル(2m) MLL82AM/A

モバイルバッテリ

USB PD採用の最大の利点はノートPCのモバイルバッテリが汎用化したことではないかと思う。Ankerからリリースされている以下のモバイルバッテリがメジャーな模様。今すぐ必要な場面は無いが、旅行のときには良さそう。

周辺機器の接続

USB Type-A

まだまだUSB Type-A端子が必要に場面も多いので、HUBが必要になる。Touch Bar無しモデルだとUSB Type-Cの端子も二つしか無いので、なるべく集約したいがそうすると、ELECOMのこのモデルくらいしか選択肢が無い。

なぜなら、USB Type-Cの端子が給電用と、周辺機器接続用の両方が用意されているのはこの製品くらいしかなく、たいていはどちらか片方しか無いから。

USB Type-C

ストレージ等を接続するためにはUSB 3.1 Gen2対応のケーブルを用意する必要が有る。5AのUSB PDにも対応しているものが良さそう。

これも選択肢は少ない。ELECOMが用意している。周辺機器接続用なので、0.5mで十分かな。

HDDケースにはUSB 3.1 Gen2対応がいくつか出ている。

HDMI

常時外部ディスプレイを接続することは無いけど、勉強会等で発表する時に必要になる。かさばらないように、単体のHDMI変換アダプタが良さそう。

オルタネートモード

USB Type-Cにはオルタネートモードという別の規格の信号を流す機能が用意されている。Thunderbolt3とか、DisplayPortとか…当面使うことも無さそうなので、割愛。

ただし、端子は同じでもケーブルが異なる(Thunderbolt3は専用のケーブルが必要)等、注意が必要。

Thunderbolt 3 Express Dock HD

金に糸目をつけなければ、このDockが最強と思われるが、4万円超え。

www.belkin.com

おわりに

USB Type-Cはとにかく規格が色々有って、ややこしい。スマートフォンの充電くらいであれば適当に繋がるが、PC用は規格を理解して使わないと、全然思った通りに動かない可能性が高い。

特にケーブル類は買ったらすぐに規格名を書いたタグを付けておかないと絶対に混乱する。