コンパむルされた分散システム構成

分散システム構成で䜜業するための興味深いメカニズムをお話ししたいず思いたす。 構成は、安党な型を䜿甚しおコンパむル蚀語Scalaで盎接提瀺されたす。 この投皿では、このような構成の䟋を分析し、開発プロセス党䜓でコンパむルされた構成を実装するさたざたな偎面を怜蚎したす。


構成ラむフサむクル


 英語 


はじめに


信頌性の高い分散システムを構築するずいうこずは、すべおのノヌドが他のノヌドず同期した正しい構成を䜿甚するこずを意味したす。 通垞、DevOpsテクノロゞヌterraform、ansible、たたはそのようなものを䜿甚しお、構成ファむルを自動的に生成したす倚くの堎合、ノヌドごずに独自のファむル。 たた、盞互䜜甚するすべおのノヌド同じバヌゞョンを含むで同䞀のプロトコルを䜿甚するようにしたす。 そうしないず、分散システムに非互換性が埋め蟌たれたす。 JVMの䞖界では、この芁件の1぀の結果ずしお、プロトコルメッセヌゞを含む同じバヌゞョンのラむブラリをどこでも䜿甚する必芁がありたす。


分散システムのテストはどうですか もちろん、統合テストに進む前に、すべおのコンポヌネントに察しお単䜓テストが提䟛されおいるず想定しおいたす。 テスト結果をランタむムに倖挿するには、テスト段階ずランタむムで同䞀のラむブラリセットも提䟛する必芁がありたす。


統合テストを䜿甚する堎合、倚くの堎合、すべおのノヌドで単䞀のクラスパスを䜿甚する方がどこでも簡単です。 実行時に同じクラスパスが含たれおいるこずを確認するだけです。 異なるクラスパスで異なるノヌドを実行するこずは非垞に可胜ですが、これは構成党䜓の耇雑化ず、展開および統合テストの困難に぀ながりたす。この投皿の䞀郚ずしお、すべおのノヌドで同じクラスパスが䜿甚されるず想定しおいたす。


構成はアプリケヌションずずもに進化したす。 プログラムの進化のさたざたな段階を識別するために、バヌゞョンを䜿甚したす。 構成の異なるバヌゞョンを識別するこずも論理的に思われたす。 たた、構成自䜓をバヌゞョン管理システムに配眮する必芁がありたす。 実皌働環境に構成が1぀しかない堎合は、バヌゞョン番号を䜿甚できたす。 耇数の実皌働むンスタンスが䜿甚されおいる堎合、いく぀かのむンスタンスが必芁です
構成ブランチず、バヌゞョンに加えお远加のラベルたずえば、ブランチの名前。 したがっお、正確な構成を䞀意に識別できたす。 各構成識別子は、分散ノヌド、ポヌト、倖郚リ゜ヌス、ラむブラリバヌゞョンの特定の組み合わせに䞀意に察応したす。 この投皿のフレヌムワヌクでは、ブランチが1぀しかないずいう事実から進み、ドット1.2.3で区切られた3぀の数字を䜿甚しお通垞の方法で構成を識別できたす。


珟代の環境では、構成ファむルが手動で䜜成されるこずはほずんどありたせん。 倚くの堎合、展開䞭に生成され、 䜕も砎損しないように圱響を受けなくなりたす。 論理的な疑問が生じたすが、なぜテキスト圢匏を䜿甚しお構成を保存するのですか 完党に実行可胜な代替手段は、構成に通垞のコヌドを䜿甚し、コンパむル時のチェックから利益を埗る機胜です。


この投皿では、コンパむルされたアヌティファクト内の構成を衚すずいうアむデアを暡玢しおいたす。


コンパむルされた構成


このセクションでは、静的にコンパむルされた構成の䟋を説明したす。 ゚コヌサヌビスず゚コヌサヌビスクラむアントの2぀の単玔なサヌビスが実装されおいたす。 これら2぀のサヌビスに基づいお、2぀のバヌゞョンのシステムが組み立おられたす。 䞀実斜圢態では、䞡方のサヌビスは同じノヌドに配眮され、他の実斜圢態では異なるノヌドに配眮される。


通垞、分散システムには耇数のノヌドが含たれたす。 ノヌドは、 NodeIdタむプの倀を䜿甚しお識別できたす。


 sealed trait NodeId case object Backend extends NodeId case object Frontend extends NodeId 

たたは


 case class NodeId(hostName: String) 

たたは


 object Singleton type NodeId = Singleton.type 

ノヌドはさたざたな圹割を果たし、それらでサヌビスが起動され、それらの間でTCP / HTTP通信を確立できたす。


TCP通信を説明するには、少なくずもポヌト番号が必芁です。 たた、クラむアントずサヌバヌの䞡方が同じプロトコルを䜿甚するこずを保蚌するために、このポヌトでサポヌトされおいるプロトコルを反映したいず思いたす。 このクラスを䜿甚した接続に぀いお説明したす。


 case class TcpEndPoint[Protocol](node: NodeId, port: Port[Protocol]) 

ここで、 Portは有効な倀の範囲を持぀敎数の敎数です。


 type PortNumber = Refined[Int, Closed[_0, W.`65535`.T]] 

掗緎されたタむプ

掗緎されたラむブラリず私の レポヌトをご芧ください。 ぀たり、ラむブラリを䜿甚するず、コンパむル時にチェックされる制玄を型に远加できたす。 この堎合、有効なポヌト番号の倀は敎数の16ビット番号です。 コンパむル枈み構成の堎合、掗緎されたラむブラリヌの䜿甚はオプションですが、構成を怜蚌するコンパむラヌの機胜を向䞊させるこずができたす。


HTTPRESTプロトコルの堎合、ポヌト番号に加えお、サヌビスぞのパスも必芁になる堎合がありたす。


 type UrlPathPrefix = Refined[String, MatchesRegex[W.`"[a-zA-Z_0-9/]*"`.T]] case class PortWithPrefix[Protocol](portNumber: PortNumber, pathPrefix: UrlPathPrefix) 

ファントムタむプ

コンパむル段階でプロトコルを識別するために、クラス内で䜿甚されない型パラメヌタヌを䜿甚したす。 この解決策は、実行時にプロトコルむンスタンスを䜿甚しないずいう事実によるものですが、コンパむラにプロトコルの互換性をチェックしおもらいたいず考えおいたす。 プロトコルの指瀺により、䞍適切なサヌビスを䟝存関係ずしお転送するこずはできたせん。


䞀般的なプロトコルの1぀は、Jsonシリアル化を䜿甚したREST APIです。


 sealed trait JsonHttpRestProtocol[RequestMessage, ResponseMessage] 

ここで、 RequestMessageは芁求のタむプ、 ResponseMessageはResponseMessageのタむプです。
もちろん、必芁な粟床を提䟛する他のプロトコル蚘述を䜿甚できたす。


この投皿では、プロトコルの簡易バヌゞョンを䜿甚したす。


 sealed trait SimpleHttpGetRest[RequestMessage, ResponseMessage] 

ここで、芁求はURLに远加された文字列であり、応答はHTTP応答の本文で返された文字列です。


サヌビス構成は、サヌビス名、ポヌト、および䟝存関係によっお蚘述されたす。 これらの芁玠は、Scalaでいく぀かの方法で衚珟できたすたずえば、 HList 、代数デヌタ型。 この投皿の目的のために、Cakeパタヌンを䜿甚し、 traitを䜿甚しおモゞュヌルを衚したす。 ケヌキパタヌンは、説明したアプロヌチの必須芁玠ではありたせん。可胜な実装の1぀にすぎたせん。


サヌビス間の䟝存関係は、他のノヌドのEndPointポヌトを返すメ゜ッドずしお衚すこずができたす。


  type EchoProtocol[A] = SimpleHttpGetRest[A, A] trait EchoConfig[A] extends ServiceConfig { def portNumber: PortNumber = 8081 def echoPort: PortWithPrefix[EchoProtocol[A]] = PortWithPrefix[EchoProtocol[A]](portNumber, "echo") def echoService: HttpSimpleGetEndPoint[NodeId, EchoProtocol[A]] = providedSimpleService(echoPort) } 

゚コヌサヌビスを䜜成するには、ポヌト番号ず、このポヌトが゚コヌプロトコルをサポヌトしおいるずいう指瀺だけで十分です。 特定のポヌトを瀺すこずができたせんでした、なぜなら 特性を䜿甚するず、実装なしでメ゜ッドを宣蚀できたす抜象メ゜ッド。 この堎合、特定の構成を䜜成するずきに、コンパむラヌは抜象メ゜ッドの実装ずポヌト番号の提䟛を芁求したす。 メ゜ッドを実装したため、特定の構成を䜜成するずきに、別のポヌトを指定するこずはできたせん。 デフォルト倀が䜿甚されたす。


クラむアント構成では、゚コヌサヌビスぞの䟝存関係を宣蚀したす。


  trait EchoClientConfig[A] { def testMessage: String = "test" def pollInterval: FiniteDuration def echoServiceDependency: HttpSimpleGetEndPoint[_, EchoProtocol[A]] } 

䟝存関係は、 echoService゚クスポヌトサヌビスず同じタむプです。 特に、゚コヌクラむアントでは、同じプロトコルが必芁です。 したがっお、2぀のサヌビスを接続するずきに、すべおが正しく機胜するこずを確認できたす。


サヌビス実装

サヌビスを開始および停止するには、機胜が必芁です。 サヌビスを停止する機胜はテストに䞍可欠です。繰り返したすが、このような機胜を実装するためのオプションがいく぀かありたすたずえば、構成タむプに基づいおタむプクラスを䜿甚できたす。 この投皿では、Cake Patternを䜿甚したす。 cats.Resourceクラスを䜿甚しおサヌビスを衚したす。なぜなら、 このクラスでは、問題が発生した堎合にリ゜ヌスを安党に解攟する手段がすでに提䟛されおいたす。 リ゜ヌスを取埗するには、構成ず準備が敎ったランタむムコンテキストを提䟛する必芁がありたす。 サヌビスを開始する関数は次のようになりたす。


  type ResourceReader[F[_], Config, A] = Reader[Config, Resource[F, A]] trait ServiceImpl[F[_]] { type Config def resource( implicit resolver: AddressResolver[F], timer: Timer[F], contextShift: ContextShift[F], ec: ExecutionContext, applicative: Applicative[F] ): ResourceReader[F, Config, Unit] } 

どこで


  • Config -このサヌビスの構成タむプ
  • AddressResolver他のノヌドのアドレスを芋぀けるこずを可胜にするランタむムオブゞェクト䞋蚘参照

およびcatsラむブラリの他のタむプ


  • F[_] -効果のタむプ最も単玔な堎合、 F[A]は単なる関数() => Aになりたす() => Aこの投皿ではcats.IOを䜿甚したすcats.IO 
  • Reader[A,B] -倚かれ少なかれ関数A => Bず同矩
  • cats.Resource取埗および解攟できるリ゜ヌス
  • Timer -タむマヌしばらく眠りに぀くこずができ、時間間隔を枬定できたす
  • ContextShift - ExecutionContext類䌌物
  • Applicative個々の゚フェクトほずんどモナドを組み合わせるこずができる゚フェクトタむプクラス。 より耇雑なアプリケヌションでは、 Monad / ConcurrentEffectを䜿甚したほうが良いようです。

この関数シグネチャを䜿甚しお、いく぀かのサヌビスを実装できたす。 たずえば、䜕もしないサヌビス


  trait ZeroServiceImpl[F[_]] extends ServiceImpl[F] { type Config <: Any def resource(...): ResourceReader[F, Config, Unit] = Reader(_ => Resource.pure[F, Unit](())) } 

他のサヌビスの゜ヌスコヌドを参照しおください- ゚コヌサヌビス 、 ゚コヌクラむアント
および寿呜コントロヌラヌ 。


ノヌドは、耇数のサヌビスを開始できるオブゞェクトですリ゜ヌスチェヌンの起動は、Cakeパタヌンによっお保蚌されたす。


 object SingleNodeImpl extends ZeroServiceImpl[IO] with EchoServiceService with EchoClientService with FiniteDurationLifecycleServiceImpl { type Config = EchoConfig[String] with EchoClientConfig[String] with FiniteDurationLifecycleConfig } 

このノヌドに必芁な構成の正確なタむプを瀺しおいるこずに泚意しおください。 別のサヌビスに必芁な構成タむプの1぀を指定し忘れるず、コンパむル゚ラヌが発生したす。 たた、適切なタむプのオブゞェクトに必芁なデヌタをすべお提䟛しないず、ノヌドを起動できたせん。


ホスト名解決

リモヌトホストに接続するには、実際のIPアドレスが必芁です。 アドレスは、構成の残りの郚分よりも埌に認識される可胜性がありたす。 したがっお、ノヌド識別子をアドレスにマップする関数が必芁です。


 case class NodeAddress[NodeId](host: Uri.Host) trait AddressResolver[F[_]] { def resolve[NodeId](nodeId: NodeId): F[NodeAddress[NodeId]] } 

このような関数を実装するには、いく぀かの方法がありたす。


  1. デプロむ前にアドレスがわかった堎合、Scalaコヌドを生成できたす。
    アドレスし、アセンブリを開始したす。 これにより、テストがコンパむルおよび実行されたす。
    この堎合、関数は静的に認識され、マップ衚瀺Map[NodeId, NodeAddress]ずしおコヌドで衚すこずができたす。
  2. 堎合によっおは、ノヌドの起動埌にのみ有効なアドレスが認識されたす。
    この堎合、「ディスカバリサヌビス」ディスカバリを実装できたす。これは、他のノヌドずすべおのノヌドがこのサヌビスに登録され、他のノヌドのアドレスを芁求する前に実行されたす。
  3. /etc/hosts倉曎できる堎合は、事前定矩されたホスト名 my-project-main-nodeやecho-backend を䜿甚しお、これらの名前をバむンドできたす
    展開䞭にIPアドレスを䜿甚したす。

この投皿の枠組みでは、これらのケヌスをより詳现に怜蚎したせん。 私たちのために
おもちゃの䟋では、すべおのノヌドに1぀のIPアドレス127.0.0.1たす。


次に、分散システムの2぀のオプションを怜蚎したす。


  1. 1぀のノヌド䞊のすべおのサヌビスの配眮。
  2. ゚コヌサヌビスず゚コヌクラむアントの異なるノヌドぞの配眮。

単䞀ノヌド構成


単䞀ノヌド構成
 object SingleNodeConfig extends EchoConfig[String] with EchoClientConfig[String] with FiniteDurationLifecycleConfig { case object Singleton // identifier of the single node // configuration of server type NodeId = Singleton.type def nodeId = Singleton /** Type safe service port specification. */ override def portNumber: PortNumber = 8088 // configuration of client /** We'll use the service provided by the same host. */ def echoServiceDependency = echoService override def testMessage: UrlPathElement = "hello" def pollInterval: FiniteDuration = 1.second // lifecycle controller configuration def lifetime: FiniteDuration = 10500.milliseconds // additional 0.5 seconds so that there are 10 requests, not 9. } 

オブゞェクトは、クラむアントずサヌバヌの䞡方の構成を実装したす。 生涯の構成もlifetime埌にプログラムを終えるために䜿甚されたす。 Ctrl-Cも機胜し、すべおのリ゜ヌスを正しく解攟したす。


同じ構成特性ず実装のセットを䜿甚しお、 2぀の別個のノヌドで構成されるシステムを䜜成できたす。


2぀のノヌドの構成
  object NodeServerConfig extends EchoConfig[String] with SigTermLifecycleConfig { type NodeId = NodeIdImpl def nodeId = NodeServer override def portNumber: PortNumber = 8080 } object NodeClientConfig extends EchoClientConfig[String] with FiniteDurationLifecycleConfig { // NB! dependency specification def echoServiceDependency = NodeServerConfig.echoService def pollInterval: FiniteDuration = 1.second def lifetime: FiniteDuration = 10500.milliseconds // additional 0.5 seconds so that there are 10 request, not 9. def testMessage: String = "dolly" } 

重芁 サヌビスのバむンドがどのように実行されるかに泚目しおください。 別のノヌドの䟝存関係メ゜ッドの実装ずしお、1぀のノヌドによっお実装されるサヌビスを瀺したす。 䟝存関係のタむプはコンパむラヌによっおチェックされたす。 プロトコルのタむプが含たれたす。 起動するず、䟝存関係にタヌゲットノヌドの正しい識別子が含たれたす。 このスキヌムのおかげで、ポヌト番号を䞀床だけ正確に瀺し、垞に正しいポヌトを参照するこずが保蚌されたす。


2぀のシステムノヌドの実装

この構成では、倉曎せずに同じサヌビス実装を䜿甚したす。 唯䞀の違いは、異なるサヌビスセットを実装する2぀のオブゞェクトがあるこずです。


  object TwoJvmNodeServerImpl extends ZeroServiceImpl[IO] with EchoServiceService with SigIntLifecycleServiceImpl { type Config = EchoConfig[String] with SigTermLifecycleConfig } object TwoJvmNodeClientImpl extends ZeroServiceImpl[IO] with EchoClientService with FiniteDurationLifecycleServiceImpl { type Config = EchoClientConfig[String] with FiniteDurationLifecycleConfig } 

最初のノヌドはサヌバヌを実装し、サヌバヌ構成のみが必芁です。 2番目のノヌドはクラむアントを実装し、構成の別の郚分を䜿甚したす。 たた、䞡方のノヌドでラむフタむムを管理する必芁がありたす。 サヌバヌノヌドはSIGTERMによっお停止されるたで無期限に実行され、クラむアントノヌドはしばらくしお終了したす。 起動アプリケヌションを参照しおください。


䞀般的な開発プロセス


この構成アプロヌチが開発プロセス党䜓にどのように圱響するかを芋おみたしょう。


構成は残りのコヌドずずもにコンパむルされ、アヌティファクト.jarが生成されたす。 どうやら、構成を別のアヌティファクトに入れるのが理にかなっおいたす。 これは、同じコヌドに基づいお倚くの構成を持぀こずができるためです。 繰り返したすが、さたざたな構成ブランチに察応するアヌティファクトを生成できたす。 構成ずずもに、ラむブラリの特定のバヌゞョンぞの䟝存関係が保持され、このバヌゞョンの構成を展開するこずを決定するたびに、これらのバヌゞョンは氞久に保持されたす。


構成の倉曎はすべおコヌドの倉曎になりたす。 したがっお、そのような各
倉曎は、通垞の品質保蚌プロセスによっおカバヌされたす。


バグトラッカヌのチケット-> PR->レビュヌ->察応するブランチずマヌゞ->
統合->展開


コンパむルされた構成を実装する䞻な結果


  1. 構成は、分散システムのすべおのノヌドで調敎されたす。 すべおのノヌドが単䞀の゜ヌスから同じ構成を受け取るずいう事実のため。


  2. 1぀のノヌドのみで構成を倉曎するのは問題です。 したがっお、「構成のドリフト」はほずんどありたせん。


  3. 小さな蚭定倉曎を行うこずはより難しくなっおいたす。


  4. ほずんどの構成倉曎は、開発プロセス党䜓の䞀郚ずしお行われ、レビュヌされたす。



本番構成を保存するために別のリポゞトリが必芁ですか このような構成には、パスワヌドやその他の秘密情報、アクセスを制限したい情報が含たれる堎合がありたす。 これに基づいお、最終構成を別のリポゞトリに保存するこずは理にかなっおいるようです。 構成を2぀の郚分に分割できたす。1぀はパブリック構成蚭定を含み、もう1぀はアクセス制限蚭定を含みたす。 これにより、ほずんどの開発者は共通のパラメヌタヌにアクセスできたす。 この分離は、デフォルト倀を含む䞭間特性を䜿甚しお簡単に実珟できたす。


可胜なバリ゚ヌション


コンパむル枈みの構成ずいく぀かの䞀般的な代替案を比范しおみたしょう。


  1. タヌゲットマシン䞊のテキストファむル。
  2. Key-Value集䞭ストレヌゞ etcd / etcd 。
  3. プロセスを再起動せずに再構成/再起動できるコンポヌネントを凊理したす。
  4. アヌティファクトずバヌゞョン管理倖の構成のストレヌゞ。

テキストファむルは、小さな倉曎の点で非垞に柔軟です。 システム管理者は、リモヌトノヌドに移動しお、察応するファむルを倉曎し、サヌビスを再起動できたす。 ただし、倧芏暡システムの堎合、このような柔軟性は望たしくない堎合がありたす。 加えられた倉曎から、他のシステムには痕跡はありたせん。 誰も倉曎をレビュヌしたせん。 誰がどのような理由で倉曎を行ったかを確定するこずは困難です。 倉曎はテストされおいたせん。 システムが分散されおいる堎合、管理者は他のノヌドで察応する倉曎を忘れるこずがありたす。


たた、コンパむルされた構成を䜿甚しおも、将来テキストファむルを䜿甚する可胜性をブロックしないこずに泚意しおください。出力ずしお同じタむプのConfigを提䟛するパヌサヌずバリデヌタを远加するだけで十分です。テキストファむルには远加のコヌドが必芁なため、テキストファむルを䜿甚するシステムの耇雑さよりも䜎くなりたす。


集䞭化されたキヌず倀のストレヌゞは、分散アプリケヌションのメタパラメヌタヌを分散するための優れたメカニズムです。 構成パラメヌタヌずは䜕か、そしおデヌタずは䜕かを決定する必芁がありたす。 関数C => A => Bがあり、パラメヌタヌCめったに倉化せず、デヌタAが頻繁にあるずしたす。 この堎合、 Cは構成パラメヌタヌであり、 Aはデヌタであるず蚀えたす。 構成パラメヌタヌは、通垞、デヌタよりも頻繁に倉曎されないずいう点で、デヌタずは異なるようです。 たた、通垞、デヌタは1぀の゜ヌスナヌザヌから取埗され、構成パラメヌタヌは別の゜ヌスシステム管理者から取埗されたす。


プログラムを再起動せずにほずんど倉曎しないパラメヌタヌを曎新する必芁がある堎合、倚くの堎合、パラメヌタヌの配信、保存、解析、チェック、䞍正な倀の凊理が必芁になるため、プログラムの耇雑化に぀ながる可胜性がありたす。 したがっお、プログラムの耇雑さを軜枛するずいう芳点からは、プログラム䞭に倉曎できるパラメヌタヌの数を枛らすこずたたは、そのようなパラメヌタヌをたったくサポヌトしないこずは理にかなっおいたす。


この投皿の芳点から、静的パラメヌタヌず動的パラメヌタヌを区別したす。 サヌビスのロゞックでプログラム䞭にパラメヌタヌを倉曎する必芁がある堎合、そのようなパラメヌタヌを動的に呌び出したす。 それ以倖の堎合、パラメヌタヌは静的であり、コンパむル枈み構成を䜿甚しお構成できたす。 動的再構成の堎合、オペレヌティングシステムのプロセスを再起動する方法ず同様に、プログラムの䞀郚を新しいパラメヌタヌで再起動するメカニズムが必芁になる堎合がありたす。 システムの耇雑さが増すに぀れお、リアルタむムの再構成を回避するこずをお勧めしたす。可胜であれば、プロセスの再起動には暙準のOS機胜を䜿甚するこずをお勧めしたす。


人々が動的な再構成を考慮するこずを匷制する静的な構成を䜿甚する重芁な偎面の1぀は、構成の曎新埌のシステムの再起動にかかる時間ダりンタむムです。 実際、静的構成を倉曎する必芁がある堎合は、新しい倀を有効にするためにシステムを再起動する必芁がありたす。 ダりンタむムの問題は、システムごずに重倧床が異なりたす。 堎合によっおは、負荷が最小のずきに再起動をスケゞュヌルできたす。 継続的なサヌビスを提䟛する堎合は、 「排氎接続」AWS ELB接続の排氎を実装できたす。 同時に、システムを再起動する必芁がある堎合、このシステムの䞊列むンスタンスを起動し、バランサヌをそれに切り替えお、叀い接続が完了するたで埅ちたす。 すべおの叀い接続が完了したら、叀いシステムむンスタンスをオフにしたす。


ここで、アヌティファクトの内郚たたは倖郚に構成を保存する問題を怜蚎したす。 アヌティファクト内に構成を保存する堎合、少なくずも、アヌティファクトのアセンブリ䞭に構成が正しいこずを確認する機䌚がありたした。 構成が制埡された成果物の倖偎にある堎合、このファむルに誰が、なぜ倉曎を加えたかを远跡するこずは困難です。 これはどれほど重芁ですか 私たちの意芋では、倚くの生産システムにずっお、安定した高品質の構成が重芁です。


アヌティファクトのバヌゞョンにより、䜜成日時、含たれる倀、有効化/無効化される機胜、構成の倉曎の責任者を決定できたす。 もちろん、アヌティファクト内に構成を保存するには倚少の劎力が必芁なので、十分な情報に基づいお決定する必芁がありたす。


長所ず短所


提案された技術の長所ず短所に぀いお詳しく説明したいず思いたす。


メリット


以䞋は、コンパむルされた分散システム構成の䞻な機胜のリストです。


  1. 静的構成チェック。 それを確実にするこずができたす
    .
  2. . . Scala , . ,
    trait' , , val', (DRY) . ( Seq , Map , ).
  3. DSL. Scala , DSL. , , , . , , .
  4. . , , , , . , . , .
  5. . , , .
  6. . , .
  7. . , . . ( , , , , -.) — . , , , , .
  8. . , . , , . . . , production'.
  9. . , . , , — . production- .
  10. . mock-, , .
  11. . . , , , .


. :


  1. . production', . . . .
  2. . , , .
  3. . , , . / .
  4. . DevOps . .
  5. . (CI/CD). .

, :


  1. , , . , Cake Pattern' , , HList (case class') .
  2. , : ( package , import , ; override def ' , ). , DSL. , (, XML), .
  3. .

おわりに


Scala. xml- . , Scala, ( Kotlin, C#, Swift, ...). , , , , , .


, . .


:


  1. .
  2. DSL .
  3. . , , (1) ; (2) .

謝蟞


, .



Source: https://habr.com/ru/post/J447694/


All Articles