Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
面倒なことはScalaスクリプトにやらせよう / let scala scripts do t...
Search
Takumi Kadowaki
September 16, 2019
Programming
1.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
面倒なことはScalaスクリプトにやらせよう / let scala scripts do the troublesome things
2019/09/13 Scala秋祭り
Takumi Kadowaki
September 16, 2019
More Decks by Takumi Kadowaki
See All by Takumi Kadowaki
Datadog Error Tracking & Claude Code Action で アプリケーションエラーを(半)自動修正 / Datadog Error Tracking & Claude Code Action (semi-)auto-correct application errors
nomadblacky
1
120
Reckoner における Datadog Browser Test の活用事例 / Datadog Browser Test at Reckoner
nomadblacky
0
560
Scala アプリケーションのビルドを改善してデプロイ時間を 1/4 にした話 | How I improved the build of my Scala application and reduced deployment time by 4x
nomadblacky
1
1.3k
Reckoner の Scala プロジェクトにおける オブザーバビリティの取り組み / Observability Initiatives in Reckoner's Scala Project
nomadblacky
0
2.6k
AWS CDK on Scala ~ Scalaでインフラ管理してみたはなし / Manage infrastructure with AWS CDK on Scala
nomadblacky
0
4.8k
Slinky で Scala.js 製 React Webアプリケーションを つくったはなし / How to build a Scala.js React web application in Slinky
nomadblacky
1
5.4k
Other Decks in Programming
See All in Programming
エージェンティックRAGにAWSで入門しよう!
har1101
7
1.1k
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
3
1.1k
柔軟なPDFレイアウトエディタを支える型システム設計 — Discriminated UnionとConditional Typeの実践
minako__ph
4
1.4k
GitHub Copilot CLIのいいところ
htkym
2
1.3k
さぁV100、メモリをお食べ・・・
nilpe
0
130
Oxcを導入して開発体験が向上した話
yug1224
4
290
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
110
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
230
運用エージェントは "作る" から "育てる" へ - 記憶と自己進化の3層設計パターン / self-evolving-agents-three-layer-agent-design
gawa
12
3.5k
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
120
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
190
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
140
Featured
See All Featured
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.3k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
65
56k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.5k
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Discover your Explorer Soul
emna__ayadi
2
1.1k
Mind Mapping
helmedeiros
PRO
1
230
KATA
mclloyd
PRO
35
15k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
0
1.6k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
140
How STYLIGHT went responsive
nonsquared
100
6.2k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.8k
Transcript
面倒なことは Scalaスクリプトにやらせよう 2019/09/16 Scala秋祭り Takumi Kadowaki @blac_k_ey
どなた? Takumi Kadowaki Twitter: @blac_k_ey GitHub: NomadBlacky セプテーニ・オリジナル PYXISチーム所属 広告運用自動化ツールのバックエンド開発が主な仕事
海と温泉とテトリスが好き ScalaMatsuri2019で頒布した「技術読本」に 「ServerlessFramework + Scala」なアプリケーションについて記事を書き ました
突然ですが問題です
DockerHubからあるイメージのタグ一覧をAPIから取得して、 最もサイズの小さいものと大きいものを出力してください { "count": 257, "page": 1, "page_size": 25, "results":
[ { "id": 2255500, "name": "stable", "last_updated": "2019-09-12T14:51:49.113501Z", "full_size": 50665062 }, { "id": 19451, "name": "latest", "last_updated": "2019-09-12T14:51:29.159817Z", "full_size": 50665667 }, ... ] } https://hub.docker.com/api/content/v1/repositories/public/library/nginx/tags
シェルスクリプトで複雑なことをするとつらい… $ curl \ https://hub.docker.com/api/.../nginx/tags \ | jq .results[].full_size ...
(ここで考えるのをやめる) (我々は jq コマンドのプロではない…) (ページングとか考えるとさらにめんどい…) とりあえずシェルスクリプトで…
みんな大好きScala! みんな大好きsbt!
小さいプログラムを書くにはオーバー… • build.sbt ◦ ビルド定義 ◦ 依存解決 • build.properties ◦
sbtバージョンの指定 ◦ プラグイン (sbt-assembly etc.) • src/main/scala/.../Hoge.scala ◦ 目的のコード
世の中には色々なスクリプト言語がある JavaScript Ruby Python Groovy PHP Perl etc...
それでもやっぱりScalaで書きたい〜 JavaScript Ruby Python Groovy PHP Perl
この間を埋めるものはないだろうか… コード量/プロジェクト規模 大 小 Shell Script
そんなあなたに、 Ammonite 大 小 @ コード量/プロジェクト規模 Shell Script
Ammoniteとは? https://ammonite.io lihaoyi/Ammonite • Scala REPL • Script Runner •
File System Library • Shell これらの総称
Ammonite-REPL
http://ammonite.io/#Ammonite-REPL 何はともあれ、まずはインストールしてみよう (Linuxなど ※執筆時の最新版) $ sudo sh -c '(echo "#!/usr/bin/env
sh" && curl -L https://github.com/lihaoyi/Ammonite/releases/download/1.6.9/2.13-1.6.9) > /usr/local/bin/amm && chmod +x /usr/local/bin/amm' && amm コマンドをひとつ実行するだけ! (Macのかた) $ brew install ammonite-repl
Hello World!!
Ammonite-REPLの便利な機能 • シンタックスハイライト • 複数行のコード編集 • Undo & Redo •
Magic Import • browse ◦ 大きな配列など、文字列表現が長い評価結果をページャで確認 • source ◦ REPL上でソースコードを閲覧
Magic Import Maven Central からJarを取得して、すぐにライブラリを使える! import $ivy.`<group_id>::<artifact_id>:<version>` // cats の例
import $ivy.`org.typelevel::cats-core:2.0.0` // sbt との比較 libraryDependencies += "org.typelevel" %% "cats-core" % "2.0.0"
None
Ammonite-Script
Scalaコードをコマンドラインから直接コンパイル・実行! sample.sc println("Hello Ammonite!!")
Scalaコードをコマンドラインから直接コンパイル・実行! sample.sc println("Hello Ammonite!!") Scalaスクリプトでよく使われる拡張子
Scalaコードをコマンドラインから直接コンパイル・実行! sample.sc println("Hello Ammonite!!") $ amm sample.sc amm コマンドの後ろにスクリプトのパ ス
Scalaコードをコマンドラインから直接コンパイル・実行! sample.sc println("Hello Ammonite!!") $ amm sample.sc Compiling (synthetic)/ammonite/predef/DefaultPredef.sc Compiling
/home/blacky/sample.sc Hello Ammonite!! その場でコンパイル &実行!
Scalaコードをコマンドラインから直接コンパイル・実行! sample.sc println("Hello Ammonite!!") $ amm sample.sc Compiling (synthetic)/ammonite/predef/DefaultPredef.sc Compiling
/home/blacky/sample.sc Hello Ammonite!! $ amm sample.sc Hello Ammonite!! 2回目以降はコンパイルしないので実行が早い !
Magic Importとの合わせ技 sample_magic.sc import $ivy.`org.jsoup:jsoup:1.12.1` val doc = org.jsoup.Jsoup.connect("https://www.google.com").get println(doc.getElementsByTag("title"))
$ amm sample_magic.sc <title>Google</title> もちろんスクリプトでも Magic Importが使える!
Ammoniteに含まれるライブラリ依存
デフォルトで使える便利なライブラリたち Ammoniteに含まれている依存はMagicImportをせずとも使えます。 その中でもスクリプトの実装に役立つライブラリを一部紹介します。 $ coursier resolve com.lihaoyi:ammonite_2.13.0:1.6.9 ... com.lihaoyi:ammonite-ops_2.13:1.6.9:default com.lihaoyi:os-lib_2.13:0.3.0:default
com.lihaoyi:requests_2.13:0.2.0:default com.lihaoyi:upickle_2.13:0.7.5:default ... ...
デフォルトで使える便利なライブラリたち • ammonite-ops / os-lib ◦ https://github.com/lihaoyi/os-lib ◦ ファイル操作、サブプロセス実行などを提供 •
requests ◦ https://github.com/lihaoyi/requests-scala ◦ HTTPクライアント • upickle ◦ https://github.com/lihaoyi/upickle ◦ シリアライゼーションライブラリ ◦ MsgPack / JSON に対応
実際の活用例
esa.ioの利用状況をDatadogで可視化してみる Stats取得 メトリクス送信 GitLab CI の Scheduled Jobで 1時間に1回実行
ソースコード スライドには収まりきらなかったのでgistで… https://gist.github.com/NomadBlacky/2c56814a1993e327ed2c2e3d 8da01eed
GitLab CI での実行ログ ./amm esa-stats-to-datadog.sc --team septeni-original Get septeni-original.esa.io stats
... { "members": 55, "posts": 298, "posts_wip": 51, "posts_shipped": 247, "comments": 157, "stars": 197, "daily_active_users": 1, "weekly_active_users": 13, "monthly_active_users": 26 } Post stats to Datadog ... Done!
あとはダッシュボードを作ってあげるだけ
Scala製のDatadog APIクライアントを作りました! Starください!!! https://github.com/NomadBlacky/scaladog (宣伝)
そのほか… • Twitterの「いいね」から画像を取得する ◦ https://github.com/NomadBlacky/ammonite-scripts/blob/master/bin/get-twitter-images.sc • 何度閉じてもダイアログが出てくるScalaスクリプト ◦ https://gist.github.com/NomadBlacky/a70d76f5d699994da83c92775935f3f6 ◦
実行は自己責任でお願いします • ScalaからAWS CDKを叩いてインフラを構築する ◦ http://nomadblacky.hatenablog.com/entry/2019/07/14/194607 ◦ Scalaでインフラを作る!
おわりに
参考資料 • Document ◦ http://ammonite.io/ • GitHub ◦ https://github.com/lihaoyi/ammonite •
Blog ◦ http://www.lihaoyi.com • Video ◦ https://vimeo.com/148552858 • IntelliJ IDEA + AmmoniteでScalaスクリプトの開発を始めよう ◦ 弊社エンジニアブログ ◦ http://labs.septeni.co.jp/entry/2018/12/20/120000
まとめ • 便利なREPLとしてのAmmonite ◦ ちょっとScalaを書いて試したい時にAmmoniteを! ◦ 特に「Magic Import」が便利! • ScalaスクリプトとしてのAmmonite
◦ シェルスクリプトだと面倒、sbtだとオーバーという時の選択肢に! ◦ ざっくり書いてもコンパイラが怒ってくれる ▪ (ちょっとしたテスト代わり) ◦ Java/Scalaの資産が使える! ◦ 何よりScalaでスクリプトを書ける!! ▪ 楽しい!!!!
ちなみに: 最初の問題の回答 import upickle.default._ case class Response(page: Int, page_size: Int,
results: Seq[Tag]) case class Tag(name: String, full_size: Long) implicit val responseReader: Reader[Response] = macroR implicit val tagReader: Reader[Tag] = macroR def fetchAllTags(image: String): Seq[Tag] = Stream.from(1).map { page => read[Response]( requests.get( url = s"https://hub.docker.com/api/content/v1/repositories/public/library/$image/tags", params = Map("page" -> page.toString) ).text ) }.takeWhile(r => r.page < r.page_size) .flatMap(_.results) @main def main(image: String): Unit = { val allTags = fetchAllTags(image) println(allTags.minBy(_.full_size)) println(allTags.maxBy(_.full_size)) }