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
130
Reckoner における Datadog Browser Test の活用事例 / Datadog Browser Test at Reckoner
nomadblacky
0
580
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.7k
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
Embedded SREと共に達成した会員管理システムのAWS移行 - SRE NEXT 2026 ランチスポンサーセッション
niftycorp
PRO
1
2.6k
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
1
190
霧の中の代数的エフェクト
funnyycat
1
390
Foundation Models frameworkで画像分析
ryodeveloper
1
120
JAWS-UG横浜 #102 AWSサ終供養LT会 成仏できない AWS サービスたち 〜本日、三体供養します〜
maroon1st
0
210
気圧・高度・GPSを記録&可視化するアプリ「Koudo」を作った話
hjmkth
1
360
使用 Meilisearch 建立新聞搜尋工具
johnroyer
0
150
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
220
AI がコードを書く時代における新卒エンジニアの仕事風景 (2026) / New Graduate Engineers in the Era of AI Coding (2026)
sushichan044
0
220
Performance Engineering for Everyone
elenatanasoiu
0
270
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
230
Even G2とAWSで推しのエージェントを召喚しよう!
har1101
1
170
Featured
See All Featured
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
120k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
450
WENDY [Excerpt]
tessaabrams
11
38k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
190
Making the Leap to Tech Lead
cromwellryan
135
10k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
390
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
190
HDC tutorial
michielstock
2
750
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
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)) }