other than RTB, such as creativity, become important •Glaze provide basic functions such as bidding, delivery and measurement required by RTB as SaaS •Glaze goal is to be able to focus on the intrinsic strengths of the customer's products なぜGlazeを作っているのかは本題ではないので簡単に説明し ます
to make DSP with Adtech Studio ... • Out motivation is to create something that can withstand long-term maintenance • We have decided to introduce DDD as a proper design method 長期的に持続できるシステムを作るためにDDDを選択しました
development • Coded only the domain layer • Working with a small team • We discussed the domain model deeply Domain modeling (2~3 persons) Mob programming (4~5 persons) 開発の初期は小さなチームでドメインモデリングに集中しまし た 2018/05 2018/08 2018/10 Development continues… (4~8 persons)
done, we proceeded development with mob programming • Coding until one function works completely • Working with a middle team • We proceeded with agreement on architecture and coding conventions Domain modeling (2~3 persons) Mob programming (4~5 persons) ドメインモデリングが終わった後はモブプログラミングでチーム 内の意識を合わせながら開発を進めました 2018/05 2018/08 2018/10 Development continues… (4~8 persons)
• Conway’s Law & Inverse Conway Maneuver • Bounded context ≒ Microservice boundary • If you are wondering if you should split BC, I think it is better to proceed without splitting Make one team responsible for one BC
Context •I think I should separate repositories by BC correctly •Spark applications are split because they have different paradigms •The project is not divided into applications because it is still small
trait Implicits { implicit def codecToDoobieMeta[T, S](implicit codec: Codec[T, S], ev: Meta[S]): Meta[T] = Meta[S].imap(r => codec.decode(r).getOrElse(throw new IllegalArgumentException(s"invalid format: $r")))(codec.encode) } Codecを用意するとこの定義によりDoobieのMeta型クラスへ暗 黙変換されます If you prepare Codec, this definition will implicitly convert to Doobie's Meta type class
import org.scanamo.error.TypeCoercionError trait Implicits { implicit def codecToDynamoFormat[T, S](implicit codec: Codec[T, S], f: DynamoFormat[S]): DynamoFormat[T] = DynamoFormat.xmap[T, S] { r => codec.decode(r).toRight(TypeCoercionError(new IllegalArgumentException(s"invalid format: $r"))) } { codec.encode } } ScanamoのDynamoFormat型クラスへの変換も同時に利用可 能になります Conversion to Scanamo's DynamoFormat type class will also be available at the same time
put in the domain layer only about things that can be converted to primitives • Codec is not defined for an entity and a value object consisting of multiple value objects • It is expected that primitive representations will not change even if complex representations such as JSON are shaken in the future プリミティブと変換できるものについてのみドメイン層に置くこと にしました
between layers, so development was speeding up • There is no need to write separate conversions with Doobie (RDB) and Scanamo (KVS) これにより大きなデメリットもなく開発スピードが向上したと思い ます
was placed in the application layer, and in the domain layer the corresponding case class was written • Reduced development speed with conversion code hell • Moved .proto to the domain layer and used ScalaPB generated case class as domain event 変換コードのメンテナンスが非常に辛かったのでドメイン層に 置くことにしました
such as Protocol Buffers and Avro is not fit with DDD • The advantage of code autogeneration disappears when isolated from domain • There are also cases where the generated code is used in the domain layer • I think that the problem is unlikely to occur because Protocol Buffers is schema compatible at the time of modification 割り切って自動生成コードをドメイン層で利用するのもありだと 思います