From 7dfeb568d8e28d5f845049da59d8ae33dbbdb7c2 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 27 Jan 2025 12:06:39 +0900 Subject: [PATCH] wip --- content/posts/2025-01-27/index.md | 84 +++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 content/posts/2025-01-27/index.md diff --git a/content/posts/2025-01-27/index.md b/content/posts/2025-01-27/index.md new file mode 100644 index 0000000..09ea91a --- /dev/null +++ b/content/posts/2025-01-27/index.md @@ -0,0 +1,84 @@ +--- +author: usbharu +draft: false +categories: + - 技術 +date: 2025-01-12T14:08:58+09:00 +tags: + - Kotlin + - ActivityPub + - Kotlin + - ActivityStreams + - ActivityVocabulary +keywords: + - Kotlin + - ActivityPub + - Kotlin + - ActivityStreams + - ActivityVocabulary +title: Kotlinで作るDSL +relpermalink: posts/2025-01-12/ +url: posts/2025-01-12/ +decription: KotlinでデータとDSLが分離されたタイプのDSLの作成 +--- + +KotlinでひたすらDSLを書いてたらだいぶノウハウが溜まってきたので共有 + +KotlinのDSL作成でググるとこんな記事が出てくると思いますが、大半の人は下の記事を読むだけで作りたいものが作れると思うのでぜひ読んでください。 + +[Kotlin で書く DSL](https://improve-future.com/kotlin-dsl.html) + +[Type-safe builders | Kotlin Documentation](https://kotlinlang.org/docs/type-safe-builders.html) + +## データの実体とDSLが分離されたタイプのDSL + +上で紹介した記事では全部データの実体となるクラスに直接DSLを生やしています。これはこれで綺麗にまとまっていいのかもしれませんが、僕は頭Javaな人なのでBuilderに相当する部分は分けられていてほしいです。特に内部でStringBuilderなどを使うようになってくるとややこしくなってきます。 + +分離すると何が嬉しいかというと +- DSL上の構造と実際のデータ構造が大幅に乖離しているときにDSLを書きやすい +- StringBuilderなどが使いやすい +- データ保持側に手を入れなくていい(責務の分離) +- クソややこしいDSLを書いたときにデータ保持側を読みやすい +- パフォーマンスが向上する場合がある(とりあえずListに溜め込んでbuild時に生成するStringBuilder的なアプローチがとれる) + +逆にデメリットは +- 単純に考えて必要なクラス数が増える(どこまで凝るかによるが2倍以上) +- それに伴う保守性の低下 +- Kotlinのうんこ仕様によるプロパティの露出 + +### メリット + +#### DSL上の構造と実際のデータ構造が大幅に乖離しているときにDSLを書きやすい + +実際のデータにDSLを生やした場合全然関係ないインスタンスを操作することは可能ですが不自然です。しかし、DSL部分を分離するとそのへんの制約は完全になくなって自由になります。 + +#### StringBuilderなどが使いやすい + +上と同じで、データ側がStringBuilderをもともと持っているなら自然に使えますが、持ってない場合StringBuilderの意味がなくなります。 + +#### データ保持側に手を入れなくていい + +そう、責務の分離ってやつです。わざわざ説明するまでもない + +#### クソややこしいDSLを書いたときにデータ保持側を読みやすい + +例えば[一つのオブジェクトのDSLに300行以上あったら](https://github.com/usbharu/activity-streams-serialization/blob/6e34c1ce3f2d070396c908f139b0863312262c45/src/main/kotlin/dev/usbharu/activitystreamsserialization/dsl/ObjectBuilder.kt)すごいややこしくないですか? そういうときに読みやすいです。 + +#### パフォーマンスが向上する場合がある + +StringBuilderがいい例なんですが、一旦Listに溜め込んで、build時にインスタンスの生成するっていうアプローチを取れます。 + +これはKotlin標準のDSL + +```kotlin +val buildString = buildString { + append("hello") + append(" ") + append("world") + + + for (i in 1..10) { + append(i) + } + } +``` \ No newline at end of file