SlideShare a Scribd company logo
1 of 29
Download to read offline
distage
1/29
dist✪ge
Modern Staged Dependency Injection for Scala
Modular Functional Programming
with
Context Minimization
through
Garbage Collection
Septimal Mind Ltd
team@7mind.io
1 / 29
distage
The argument: Dependency Injection vs. Functional Programming 2/29
DI is outdated and doesn’t compose with FP?
Many Scala folks think that:
1. DI is heavy and slow
◮ “tests start longer than they run”
2. DI is unsafe
◮ “my program compiles but crashes at runtime after a huge delay”
3. DI doesn’t work for modern FP code
◮ “we cannot inject IO[ , ] into Repository[ [ , ]] ”
4. DI is full of magic and error-prone
◮ “I’ve read 80% of the 5000-page Spring manual but still don’t
understand why I need to put these 12 annotations here. I’ve tried
Guice but it failed with 10-megabyte stacktrace after five minutes
and 300 retries of database connection initialization”
2 / 29
distage
The argument: Dependency Injection vs. Functional Programming 3/29
TLDR
1 import distage._, scalaz.zio.IO
2
3 trait Repository[F[_, _]]
4 class ProductionRepository[F[_, _]] extends Repository[F]
5 class DummyRepository[F[_, _]] extends Repository[F]
6 class App[F[_, _]](repository: Repository[F]) { def run = ??? }
7
8 class MyAppProd[F[_, _]: TagKK] extends ModuleDef {
9 make[Repository[F]].from[ProductionRepository[F]]
10 make[App[F]]
11 }
12 class Main[F[_, _]: TagKK: BIO] extends App {
13 Injector()
14 .produceF[F[Throwable, ?]](
15 new MyAppProd[F], roots=Set(DIKey.get[App[F]])
16 ).use(_.get[App[F]].run)
17 }
18 object Main extends Main[IO]
3 / 29
distage
distage features 4/29
distage: overview
1. Staging: plan all the work before you do anything,
2. Garbage Collection: instantiate reachable instances only,
3. Higher-Kinded Types: inject typeclass instances, use parametricity,
4. Path-Dependent Types support,
5. Lifecycle and Resources: inject any cats.effect.Resource[F, A],
6. Plan introspection: graphviz, text dump, dependency trees,
7. Plan rewriting,
8. Roles: multiple services in one process,
9. Dynamic Plugins1 and Testkit,
10. Circular Dependencies support,
11. Assisted Injection and Trait Augmentation2,
12. Automatic Sets: prepopulate sets with all instances of a class
1
Runtime with compile-time verification
2
Runtime or compile-time generation
4 / 29
distage
distage features 5/29
Garbage Collection for better and faster tests
1. Define all your test and production dependencies as a flat list,
2. Put discrimination tags on test-specific definitions,
3. Only the instances required for your tests will be instantiated,
4. Creation takes milliseconds, not like in Spring,
5. ⇒ Significant savings on test startup time.
6. You don’t need to setup your context, it’s done automatically by
Plugin Loader and Garbage Collector,
7. ⇒ Substantial savings on test setup boilerplate.
5 / 29
distage
distage features 6/29
Example: Garbage Collection and tests
1 class ProductionRepository[F[_, _]] extends Repository[F]
2 class DummyRepository[F[_, _]] extends Repository[F]
3
4 class MyAppPlugin extends PluginDef {
5 make[Repository[IO]].from[ProductionRepository[IO]]
6 make[Repository[IO]].tagged("test").from[DummyRepository[IO]]
7 }
8 class RepoTest extends DistagePluginSpec {
9 "repository" must {
10 "work correctly" in diIO {
11 (repository: Repository[IO]) => // repository is GC root
12 // Repository is DummyRepository - "test" tag prioritized
13 // ProductionRepository will not be instantiated!
14 for { kv <- randomIO[KeyValue]
15 _ <- repository.put(kv)
16 kv2 <- repository.get(kv.key)
17 } yield assert(kv == kv2)
18 }}}
6 / 29
distage
distage features 7/29
Garbage Collection for deployment: flexible monoliths
We may fuse Microservices with Monoliths keeping all their benefits:
1. Develop services (Roles1) separately, even in multirepo,
2. Each Role is a Garbage Collection Root,
3. Build a single Docker image with multiple Roles in it,
4. Pass Roles you want to start as commandline parameters,
5. ⇒ higher computation density, savings on infrastructure,
6. ⇒ substantial development simplification: full environment can be
started on a low-end machine with one command.
1 server1# docker run company/product +analytics
2 server2# docker run company/product +accounting +users
3 developer1# docker run company/product +*
4 developer2# docker run company/product --dummy-repositories +*
1
Previous slides on the subject: https://goo.gl/iaMt43
7 / 29
distage
distage features 8/29
Lifecycle
◮ Applications manage a lot of global resources:
1. Connection pools, thread pools
2. Servers, external endpoints, databases
3. Configurations, metrics, heartbeats
4. External log sinks
◮ They have to be started and closed in integration tests,
◮ We shouldn’t set them up manually for every test,
◮ We want to create reusable components that correctly share a
single resource.
8 / 29
distage
distage features 9/29
Lifecycle: .fromResource
1. Inject any cats-effect Resource
2. Global resources deallocate when the app or test ends
1 object App extends IOApp {
2 val blazeClientModule = new ModuleDef {
3 make[ExecutionContext].from(ExecutionContext.global)
4 addImplicit[Bracket[IO, Throwable]]
5
6 make[Client[IO]].fromResource { ec: ExecutionContext =>
7 BlazeClientBuilder[IO](ec).resource
8 }}
9
10 def run(args: List[String]): IO[ExitCode] =
11 Injector().produceF[IO](blazeClientModule)
12 .use { // Client allocated
13 _.get[Client[IO]].expect[String]("https://google.com")
14 }.as(ExitCode.Success) // Client closed
15 }
9 / 29
distage
distage features 10/29
Effectful creation: .fromEffect
Global mutable state must be created effectfully, but doesn’t have to
be deallocated. e.g. a global parallelism limiter:
1 import distage._, import scalaz.zio._
2
3 case class UploadConfig(maxParallelUploads: Long)
4
5 class UploaderModule extends ModuleDef {
6 make[Semaphore].named("upload-limit").fromEffect {
7 conf: UploadConfig @ConfPath("myapp.uploads") =>
8 Semaphore.make(conf.maxParallelUploads) }
9 make[Uploader]
10 }
11 class Uploader(limit: Semaphore @Id("upload-limit")) {
12 def upload(content: Content): IO[Throwable, Unit] =
13 limit.withPermit(...)
14 }
10 / 29
distage
distage features 11/29
Config support
distage has HOCON configuration extension.
1 case class HostPort(host: String, port: Int)
2
3 class HttpServer(@ConfPath("http.listen") listenOn: HostPort) {
4 // ...
5 }
The extension:
1. Enumerates all the missing references in a Plan,
2. Searches them for a specific @ConfPath annotation,
3. Tries to find corresponding sections in config source,
4. Extends plan with config values,
5. ⇒ Config values are parsed before instantiation begins,
6. ⇒ Problems are shown quickly and all at once,
7. ⇒ Compile-time checker plugin validates config.
11 / 29
distage
distage features 12/29
Dynamic Plugins
Just drop your modules into your classpath:
1 class AccountingModule extends PluginDef {
2 make[AccountingService].from[AccountingServiceImpl]
3 // ...
4 }
Then you may pick up all the modules and build your context:
1 val plugins = new PluginLoaderDefaultImpl(
2 PluginConfig(Seq("com.company.plugins"))
3 ).load()
4 // ... pass loaded modules to Injector
1. Useful while you are prototyping your app,
2. In maintenance phase you may switch to static configuration.
12 / 29
distage
distage features 13/29
Circular dependencies
1. Supported via Proxies,
2. Cyclic by-name parameters (class C(param: => P)) will work
without run-time code-generation,
3. Circular dependency support can be disabled.
Limitations:
1. You cannot use an injected parameter immediately during
initialization,
2. You cannot have non-by-name circular dependencies with final
classes,
13 / 29
distage
distage features 14/29
Trait Augmentation
1 trait UsersService {
2 protected def repository: UsersRepo
3
4 def add(user: User): Unit = {
5 repository.put(user.id, user)
6 }
7 }
We may bind this trait directly, without an implementation class:
1 make[UsersService]
1. Corresponding class will be generated1 by distage,
2. Abstract defs will be wired with values from the object graph,
1
both runtime and compile-time cogen supported
14 / 29
distage
distage features 15/29
Assisted Injection (Factory Methods)
1 class UserActor(sessionId: UUID, sessionRepo: SessionRepo)
2
3 trait ActorFactory {
4 def createActor(sessionId: UUID): UserActor
5 }
1. createActor is a factory method,
2. createActor will be generated by distage,
3. Abstract methods with parameters are treated as factory methods,
4. Non-invasive assisted injection: sessionId: UUID will be taken from
method parameter, sessionRepo: SessionRepo will be wired from
context,
5. Useful for Akka, lot more convenient than Guice,
6. Works in both runtime and compile-time.
15 / 29
distage
distage features 16/29
Extension: Automatic Sets
1. All instances of type T (like AutoCloseable) as a Set[T],
2. Strong and Weak References:
◮ GC collects weak referenced members with no more references
Example: basic lifecycle support: (please use Resource bindings in real
apps!)
1 trait Resource {
2 def start(): Unit
3 def stop(): Unit
4 }
5 trait App { def main(): Unit }
6 locator.run { (resources: Set[Resource], app: App) =>
7 try {
8 resources.foreach(_.start())
9 app.main()
10 } finally { resources.foreach(_.close()) }
11 }
16 / 29
distage
distage internals 17/29
How it works: Plans
distage takes your bindings and then:
1. translates bindings into simple Turing-incomplete DSL (like
make , reference , etc.),
2. represents the DSL statements as Directed Acyclic Graph using
dependecy information and breaking circular dependencies if any,
3. resolves conflicts (one DAG node with several associated
operations),
4. performs garbage collection,
5. applies other transformations (like config reference resolution),
6. turns the DAG back into sequential form — a Plan — with
topological sorting.
7. ⇒ the Plan may be introspected, printed, executed in
compile-time by a code generator or executed in runtime.
17 / 29
distage
distage internals 18/29
Plan Introspection: example context
1 class Cluster
2 trait UsersService
3 trait AccountingService
4 trait UserRepo
5 trait AccountsRepo
6
7 class UserRepoImpl(cluster: Cluster) extends UserRepo
8 class AccountsRepoImpl(cluster: Cluster) extends AccountsRepo
9 class UserServiceImpl(userRepo: UserRepo) extends UsersService
10 class AccountingServiceImpl(accountsRepo: AccountsRepo)
11 extends AccountingService
12
13 class UsersApiImpl(service: UsersService
14 , accountsApi: AccountsApiImpl)
15 class AccountsApiImpl(service: AccountingService
16 , usersApi: UsersApiImpl) // circular dependency
17 class App(uapi: UsersApiImpl, aapi: AccountsApiImpl)
18 / 29
distage
distage internals 19/29
Plan Introspection: example bindings1
1 val definition = new ModuleDef {
2 make[Cluster]
3 make[UserRepo].from[UserRepoImpl]
4 make[AccountsRepo].from[AccountsRepoImpl]
5 make[UsersService].from[UserServiceImpl]
6 make[AccountingService].from[AccountingServiceImpl]
7 make[UsersApiImpl]
8 make[AccountsApiImpl]
9 make[App]
10 }
11 val injector = Injector()
12 val plan = injector.plan(definition)
1
Full code example: https://goo.gl/7ZwHfX
19 / 29
distage
distage internals 20/29
Plan Introspection: graphviz dumps1
1
Generated automatically by GraphDumpObserver distage extension 20 / 29
distage
distage internals 21/29
Plan Introspection: plan dumps
1 println(plan.render) // look for the circular dependency!
21 / 29
distage
distage internals 22/29
Plan Introspection: dependency trees
You may explore dependencies of a component:
1 val dependencies = plan.topology.dependencies
2 println(dependencies.tree(DIKey.get[AccountsApiImpl]))
Circular dependencies are marked with a circle symbol.
22 / 29
distage
distage internals 23/29
Compile-Time and Runtime DI
A Plan:
1 myRepository := create[MyRepository]()
2 myservice := create[MyService](myRepository)
May be interpreted as:
Code tree (compile-time):
1 val myRepository =
2 new MyRepository()
3 val myservice =
4 new MyService(myRepository)
Set of instances (runtime):
1 plan.foldLeft(Context.empty) {
2 case (ctx, op) =>
3 ctx.withInstance(
4 op.key
5 , interpret(action)
6 )
7 }
23 / 29
distage
7mind stack 24/29
dist✪ge
7mind Stack
24 / 29
distage
7mind stack 25/29
distage: status and things to do
distage 0.7:
1. is ready to use,
2. is in production for over 1 year,
3. has all runtime features available,
4. has all compile-time features available except for full compile-time
mode.
What’s next:
1. New Resource-based Roles API,
2. Scala.js support,
3. Compile-time Producer,
4. Isolated Classloaders for Roles (in future),
5. Check our GitHub: https://github.com/pshirshov/izumi-r2.
25 / 29
distage
7mind stack 26/29
distage is just a part of our stack
We have a vision backed by our tools:
1. Idealingua: transport and codec agnostic gRPC alternative with
rich modeling language,
2. LogStage: zero-cost structured logging framework,
3. Fusional Programming and Design guidelines. We love both FP
and OOP,
4. Continous Delivery guidelines for Role-based process,
5. Percept-Plan-Execute Generative Programming approach, abstract
machine and computational model. Addresses Project Planning
(see Operations Research). Examples: orchestration, build
systems.
Altogether these things already allowed us to significantly reduce
development costs and delivery time for our client.
More slides to follow.
26 / 29
distage
7mind stack 27/29
You use Guice?
Switch to distage!
“Given its native support for type classes and higher-kinded types –
both features indispensable to functional programming – DI Stage is
one of the leading dependency injection libraries out there. Bonus
points for being built by a wicked-smart team that contributes to ZIO!”
–– John A. De Goes
27 / 29
distage
7mind stack 28/29
Teaser: LogStage
A simple logging call . . .
1 log.info(s"$user logged in with $sessionId!")
May be rendered as text:
17:05:18 UserService.login user=John Doe logged in with
sessionId=DEADBEEF!
Or as structured JSON:
1 {
2 "user": "John Doe",
3 "sessionId": "DEADBEEF",
4 "_template": "$user logged in with $sessionId!",
5 "_location": "UserService.scala:265",
6 "_context": "UserService.login",
7 }
28 / 29
distage
7mind stack 29/29
Thank you for your attention
distage website: https://izumi.7mind.io/
We’re looking for clients, contributors, adopters and colleagues ;)
About the author:
1. coding for 19 years, 12 years of hands-on commercial engineering
experience,
2. has been leading a cluster orchestration team in Yandex, “the
Russian Google”,
3. Created “Yandex Interstellar Spaceship” – an orchestration
solution to manage 50K+ physical machines across 6 datacenters,
4. Owns an Irish R&D company, https://7mind.io,
5. Contact: team@7mind.io,
6. Github: https://github.com/pshirshov
7. Slides: https://github.com/7mind/slides/
29 / 29

More Related Content

What's hot

Hexagonal architecture vs Functional core / Imperative shell
Hexagonal architecture vs Functional core / Imperative shellHexagonal architecture vs Functional core / Imperative shell
Hexagonal architecture vs Functional core / Imperative shellThomas Pierrain
 
UDF/UDAF: the extensibility framework for KSQL (Hojjat Jafapour, Confluent) K...
UDF/UDAF: the extensibility framework for KSQL (Hojjat Jafapour, Confluent) K...UDF/UDAF: the extensibility framework for KSQL (Hojjat Jafapour, Confluent) K...
UDF/UDAF: the extensibility framework for KSQL (Hojjat Jafapour, Confluent) K...confluent
 
Unit test your java architecture with ArchUnit
Unit test your java architecture with ArchUnitUnit test your java architecture with ArchUnit
Unit test your java architecture with ArchUnitJeremy Cook
 
PostgreSQL Tutorial For Beginners | Edureka
PostgreSQL Tutorial For Beginners | EdurekaPostgreSQL Tutorial For Beginners | Edureka
PostgreSQL Tutorial For Beginners | EdurekaEdureka!
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with CapabilitiesScott Wlaschin
 
Oracle data pump
Oracle data pumpOracle data pump
Oracle data pumpmarcxav72
 
InnoDB MVCC Architecture (by 권건우)
InnoDB MVCC Architecture (by 권건우)InnoDB MVCC Architecture (by 권건우)
InnoDB MVCC Architecture (by 권건우)I Goo Lee.
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOJorge Vásquez
 
04. Console Input Output
04. Console Input Output 04. Console Input Output
04. Console Input Output Intro C# Book
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
L'API Collector dans tous ses états
L'API Collector dans tous ses étatsL'API Collector dans tous ses états
L'API Collector dans tous ses étatsJosé Paumard
 
Layout with Stack View, Table View, and Collection View
Layout with Stack View, Table View, and Collection ViewLayout with Stack View, Table View, and Collection View
Layout with Stack View, Table View, and Collection ViewMake School
 
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Functional Core and Imperative Shell - Game of Life Example - Haskell and ScalaFunctional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Functional Core and Imperative Shell - Game of Life Example - Haskell and ScalaPhilip Schwarz
 
Adding measures to Calcite SQL
Adding measures to Calcite SQLAdding measures to Calcite SQL
Adding measures to Calcite SQLJulian Hyde
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGuillaume Laforge
 

What's hot (20)

Hexagonal architecture vs Functional core / Imperative shell
Hexagonal architecture vs Functional core / Imperative shellHexagonal architecture vs Functional core / Imperative shell
Hexagonal architecture vs Functional core / Imperative shell
 
UDF/UDAF: the extensibility framework for KSQL (Hojjat Jafapour, Confluent) K...
UDF/UDAF: the extensibility framework for KSQL (Hojjat Jafapour, Confluent) K...UDF/UDAF: the extensibility framework for KSQL (Hojjat Jafapour, Confluent) K...
UDF/UDAF: the extensibility framework for KSQL (Hojjat Jafapour, Confluent) K...
 
Unit test your java architecture with ArchUnit
Unit test your java architecture with ArchUnitUnit test your java architecture with ArchUnit
Unit test your java architecture with ArchUnit
 
PostgreSQL Tutorial For Beginners | Edureka
PostgreSQL Tutorial For Beginners | EdurekaPostgreSQL Tutorial For Beginners | Edureka
PostgreSQL Tutorial For Beginners | Edureka
 
Java logging
Java loggingJava logging
Java logging
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
 
Oracle data pump
Oracle data pumpOracle data pump
Oracle data pump
 
InnoDB MVCC Architecture (by 권건우)
InnoDB MVCC Architecture (by 권건우)InnoDB MVCC Architecture (by 권건우)
InnoDB MVCC Architecture (by 권건우)
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIO
 
Flask – Python
Flask – PythonFlask – Python
Flask – Python
 
04. Console Input Output
04. Console Input Output 04. Console Input Output
04. Console Input Output
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Modern JS with ES6
Modern JS with ES6Modern JS with ES6
Modern JS with ES6
 
L'API Collector dans tous ses états
L'API Collector dans tous ses étatsL'API Collector dans tous ses états
L'API Collector dans tous ses états
 
What’s New in Angular 14?
What’s New in Angular 14?What’s New in Angular 14?
What’s New in Angular 14?
 
Layout with Stack View, Table View, and Collection View
Layout with Stack View, Table View, and Collection ViewLayout with Stack View, Table View, and Collection View
Layout with Stack View, Table View, and Collection View
 
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Functional Core and Imperative Shell - Game of Life Example - Haskell and ScalaFunctional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
 
Scala collection
Scala collectionScala collection
Scala collection
 
Adding measures to Calcite SQL
Adding measures to Calcite SQLAdding measures to Calcite SQL
Adding measures to Calcite SQL
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific Languages
 

Similar to ScalaUA - distage: Staged Dependency Injection

Hadoop testing workshop - july 2013
Hadoop testing workshop - july 2013Hadoop testing workshop - july 2013
Hadoop testing workshop - july 2013Ophir Cohen
 
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...7mind
 
Improving the Accumulo User Experience
 Improving the Accumulo User Experience Improving the Accumulo User Experience
Improving the Accumulo User ExperienceAccumulo Summit
 
Hyper-pragmatic Pure FP testing with distage-testkit
Hyper-pragmatic Pure FP testing with distage-testkitHyper-pragmatic Pure FP testing with distage-testkit
Hyper-pragmatic Pure FP testing with distage-testkit7mind
 
Java programming concept
Java programming conceptJava programming concept
Java programming conceptSanjay Gunjal
 
Angular performance slides
Angular performance slidesAngular performance slides
Angular performance slidesDavid Barreto
 
Stopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestStopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestSeb Rose
 
Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3kognate
 
Android MVVM architecture using Kotlin, Dagger2, LiveData, MediatorLiveData
Android MVVM architecture using Kotlin, Dagger2, LiveData, MediatorLiveDataAndroid MVVM architecture using Kotlin, Dagger2, LiveData, MediatorLiveData
Android MVVM architecture using Kotlin, Dagger2, LiveData, MediatorLiveDataWaheed Nazir
 
Gradle - the Enterprise Automation Tool
Gradle  - the Enterprise Automation ToolGradle  - the Enterprise Automation Tool
Gradle - the Enterprise Automation ToolIzzet Mustafaiev
 
[xp2013] Narrow Down What to Test
[xp2013] Narrow Down What to Test[xp2013] Narrow Down What to Test
[xp2013] Narrow Down What to TestZsolt Fabok
 
Meetup 2022 - APIs with Quarkus.pdf
Meetup 2022 - APIs with Quarkus.pdfMeetup 2022 - APIs with Quarkus.pdf
Meetup 2022 - APIs with Quarkus.pdfRed Hat
 
Splunk: Forward me the REST of those shells
Splunk: Forward me the REST of those shellsSplunk: Forward me the REST of those shells
Splunk: Forward me the REST of those shellsAnthony D Hendricks
 
From CoreOS to Kubernetes and Concourse CI
From CoreOS to Kubernetes and Concourse CIFrom CoreOS to Kubernetes and Concourse CI
From CoreOS to Kubernetes and Concourse CIDenis Izmaylov
 
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosUnit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosFlutter Agency
 
Ansible benelux meetup - Amsterdam 27-5-2015
Ansible benelux meetup - Amsterdam 27-5-2015Ansible benelux meetup - Amsterdam 27-5-2015
Ansible benelux meetup - Amsterdam 27-5-2015Pavel Chunyayev
 
BP101 - 10 Things to Consider when Developing & Deploying Applications in Lar...
BP101 - 10 Things to Consider when Developing & Deploying Applications in Lar...BP101 - 10 Things to Consider when Developing & Deploying Applications in Lar...
BP101 - 10 Things to Consider when Developing & Deploying Applications in Lar...Martijn de Jong
 
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...Postman
 

Similar to ScalaUA - distage: Staged Dependency Injection (20)

Hadoop testing workshop - july 2013
Hadoop testing workshop - july 2013Hadoop testing workshop - july 2013
Hadoop testing workshop - july 2013
 
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
 
Improving the Accumulo User Experience
 Improving the Accumulo User Experience Improving the Accumulo User Experience
Improving the Accumulo User Experience
 
Spring boot
Spring bootSpring boot
Spring boot
 
Hyper-pragmatic Pure FP testing with distage-testkit
Hyper-pragmatic Pure FP testing with distage-testkitHyper-pragmatic Pure FP testing with distage-testkit
Hyper-pragmatic Pure FP testing with distage-testkit
 
Java programming concept
Java programming conceptJava programming concept
Java programming concept
 
Angular performance slides
Angular performance slidesAngular performance slides
Angular performance slides
 
Stopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestStopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under Test
 
Why meteor
Why meteorWhy meteor
Why meteor
 
Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3
 
Android MVVM architecture using Kotlin, Dagger2, LiveData, MediatorLiveData
Android MVVM architecture using Kotlin, Dagger2, LiveData, MediatorLiveDataAndroid MVVM architecture using Kotlin, Dagger2, LiveData, MediatorLiveData
Android MVVM architecture using Kotlin, Dagger2, LiveData, MediatorLiveData
 
Gradle - the Enterprise Automation Tool
Gradle  - the Enterprise Automation ToolGradle  - the Enterprise Automation Tool
Gradle - the Enterprise Automation Tool
 
[xp2013] Narrow Down What to Test
[xp2013] Narrow Down What to Test[xp2013] Narrow Down What to Test
[xp2013] Narrow Down What to Test
 
Meetup 2022 - APIs with Quarkus.pdf
Meetup 2022 - APIs with Quarkus.pdfMeetup 2022 - APIs with Quarkus.pdf
Meetup 2022 - APIs with Quarkus.pdf
 
Splunk: Forward me the REST of those shells
Splunk: Forward me the REST of those shellsSplunk: Forward me the REST of those shells
Splunk: Forward me the REST of those shells
 
From CoreOS to Kubernetes and Concourse CI
From CoreOS to Kubernetes and Concourse CIFrom CoreOS to Kubernetes and Concourse CI
From CoreOS to Kubernetes and Concourse CI
 
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosUnit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
 
Ansible benelux meetup - Amsterdam 27-5-2015
Ansible benelux meetup - Amsterdam 27-5-2015Ansible benelux meetup - Amsterdam 27-5-2015
Ansible benelux meetup - Amsterdam 27-5-2015
 
BP101 - 10 Things to Consider when Developing & Deploying Applications in Lar...
BP101 - 10 Things to Consider when Developing & Deploying Applications in Lar...BP101 - 10 Things to Consider when Developing & Deploying Applications in Lar...
BP101 - 10 Things to Consider when Developing & Deploying Applications in Lar...
 
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
 

Recently uploaded

Salesforce Introduced Zero Copy Partner Network to Simplify the Process of In...
Salesforce Introduced Zero Copy Partner Network to Simplify the Process of In...Salesforce Introduced Zero Copy Partner Network to Simplify the Process of In...
Salesforce Introduced Zero Copy Partner Network to Simplify the Process of In...CloudMetic
 
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)Gáspár Nagy
 
Lessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfLessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfSrushith Repakula
 
Community is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletCommunity is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletAndrea Goulet
 
Evolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI EraEvolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI Eraconfluent
 
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAOpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAShane Coughlan
 
Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?Maxim Salnikov
 
BusinessGPT - Security and Governance for Generative AI
BusinessGPT  - Security and Governance for Generative AIBusinessGPT  - Security and Governance for Generative AI
BusinessGPT - Security and Governance for Generative AIAGATSoftware
 
Secure Software Ecosystem Teqnation 2024
Secure Software Ecosystem Teqnation 2024Secure Software Ecosystem Teqnation 2024
Secure Software Ecosystem Teqnation 2024Soroosh Khodami
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024SimonedeGijt
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConNatan Silnitsky
 
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfThe Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfkalichargn70th171
 
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...naitiksharma1124
 
^Clinic ^%[+27788225528*Abortion Pills For Sale In birch acres
^Clinic ^%[+27788225528*Abortion Pills For Sale In birch acres^Clinic ^%[+27788225528*Abortion Pills For Sale In birch acres
^Clinic ^%[+27788225528*Abortion Pills For Sale In birch acreskasambamuno
 
What is a Recruitment Management Software?
What is a Recruitment Management Software?What is a Recruitment Management Software?
What is a Recruitment Management Software?NYGGS Automation Suite
 
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Andrea Goulet
 
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio, Inc.
 

Recently uploaded (20)

Salesforce Introduced Zero Copy Partner Network to Simplify the Process of In...
Salesforce Introduced Zero Copy Partner Network to Simplify the Process of In...Salesforce Introduced Zero Copy Partner Network to Simplify the Process of In...
Salesforce Introduced Zero Copy Partner Network to Simplify the Process of In...
 
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
 
Lessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdfLessons Learned from Building a Serverless Notifications System.pdf
Lessons Learned from Building a Serverless Notifications System.pdf
 
Community is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletCommunity is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea Goulet
 
Abortion Clinic In Springs ](+27832195400*)[ 🏥 Safe Abortion Pills in Springs...
Abortion Clinic In Springs ](+27832195400*)[ 🏥 Safe Abortion Pills in Springs...Abortion Clinic In Springs ](+27832195400*)[ 🏥 Safe Abortion Pills in Springs...
Abortion Clinic In Springs ](+27832195400*)[ 🏥 Safe Abortion Pills in Springs...
 
Evolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI EraEvolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI Era
 
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCAOpenChain Webinar: AboutCode and Beyond - End-to-End SCA
OpenChain Webinar: AboutCode and Beyond - End-to-End SCA
 
Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?
 
BusinessGPT - Security and Governance for Generative AI
BusinessGPT  - Security and Governance for Generative AIBusinessGPT  - Security and Governance for Generative AI
BusinessGPT - Security and Governance for Generative AI
 
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
 
Secure Software Ecosystem Teqnation 2024
Secure Software Ecosystem Teqnation 2024Secure Software Ecosystem Teqnation 2024
Secure Software Ecosystem Teqnation 2024
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
 
Abortion Clinic In Polokwane ](+27832195400*)[ 🏥 Safe Abortion Pills in Polok...
Abortion Clinic In Polokwane ](+27832195400*)[ 🏥 Safe Abortion Pills in Polok...Abortion Clinic In Polokwane ](+27832195400*)[ 🏥 Safe Abortion Pills in Polok...
Abortion Clinic In Polokwane ](+27832195400*)[ 🏥 Safe Abortion Pills in Polok...
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeCon
 
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfThe Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
 
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
 
^Clinic ^%[+27788225528*Abortion Pills For Sale In birch acres
^Clinic ^%[+27788225528*Abortion Pills For Sale In birch acres^Clinic ^%[+27788225528*Abortion Pills For Sale In birch acres
^Clinic ^%[+27788225528*Abortion Pills For Sale In birch acres
 
What is a Recruitment Management Software?
What is a Recruitment Management Software?What is a Recruitment Management Software?
What is a Recruitment Management Software?
 
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
 
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
 

ScalaUA - distage: Staged Dependency Injection

  • 1. distage 1/29 dist✪ge Modern Staged Dependency Injection for Scala Modular Functional Programming with Context Minimization through Garbage Collection Septimal Mind Ltd team@7mind.io 1 / 29
  • 2. distage The argument: Dependency Injection vs. Functional Programming 2/29 DI is outdated and doesn’t compose with FP? Many Scala folks think that: 1. DI is heavy and slow ◮ “tests start longer than they run” 2. DI is unsafe ◮ “my program compiles but crashes at runtime after a huge delay” 3. DI doesn’t work for modern FP code ◮ “we cannot inject IO[ , ] into Repository[ [ , ]] ” 4. DI is full of magic and error-prone ◮ “I’ve read 80% of the 5000-page Spring manual but still don’t understand why I need to put these 12 annotations here. I’ve tried Guice but it failed with 10-megabyte stacktrace after five minutes and 300 retries of database connection initialization” 2 / 29
  • 3. distage The argument: Dependency Injection vs. Functional Programming 3/29 TLDR 1 import distage._, scalaz.zio.IO 2 3 trait Repository[F[_, _]] 4 class ProductionRepository[F[_, _]] extends Repository[F] 5 class DummyRepository[F[_, _]] extends Repository[F] 6 class App[F[_, _]](repository: Repository[F]) { def run = ??? } 7 8 class MyAppProd[F[_, _]: TagKK] extends ModuleDef { 9 make[Repository[F]].from[ProductionRepository[F]] 10 make[App[F]] 11 } 12 class Main[F[_, _]: TagKK: BIO] extends App { 13 Injector() 14 .produceF[F[Throwable, ?]]( 15 new MyAppProd[F], roots=Set(DIKey.get[App[F]]) 16 ).use(_.get[App[F]].run) 17 } 18 object Main extends Main[IO] 3 / 29
  • 4. distage distage features 4/29 distage: overview 1. Staging: plan all the work before you do anything, 2. Garbage Collection: instantiate reachable instances only, 3. Higher-Kinded Types: inject typeclass instances, use parametricity, 4. Path-Dependent Types support, 5. Lifecycle and Resources: inject any cats.effect.Resource[F, A], 6. Plan introspection: graphviz, text dump, dependency trees, 7. Plan rewriting, 8. Roles: multiple services in one process, 9. Dynamic Plugins1 and Testkit, 10. Circular Dependencies support, 11. Assisted Injection and Trait Augmentation2, 12. Automatic Sets: prepopulate sets with all instances of a class 1 Runtime with compile-time verification 2 Runtime or compile-time generation 4 / 29
  • 5. distage distage features 5/29 Garbage Collection for better and faster tests 1. Define all your test and production dependencies as a flat list, 2. Put discrimination tags on test-specific definitions, 3. Only the instances required for your tests will be instantiated, 4. Creation takes milliseconds, not like in Spring, 5. ⇒ Significant savings on test startup time. 6. You don’t need to setup your context, it’s done automatically by Plugin Loader and Garbage Collector, 7. ⇒ Substantial savings on test setup boilerplate. 5 / 29
  • 6. distage distage features 6/29 Example: Garbage Collection and tests 1 class ProductionRepository[F[_, _]] extends Repository[F] 2 class DummyRepository[F[_, _]] extends Repository[F] 3 4 class MyAppPlugin extends PluginDef { 5 make[Repository[IO]].from[ProductionRepository[IO]] 6 make[Repository[IO]].tagged("test").from[DummyRepository[IO]] 7 } 8 class RepoTest extends DistagePluginSpec { 9 "repository" must { 10 "work correctly" in diIO { 11 (repository: Repository[IO]) => // repository is GC root 12 // Repository is DummyRepository - "test" tag prioritized 13 // ProductionRepository will not be instantiated! 14 for { kv <- randomIO[KeyValue] 15 _ <- repository.put(kv) 16 kv2 <- repository.get(kv.key) 17 } yield assert(kv == kv2) 18 }}} 6 / 29
  • 7. distage distage features 7/29 Garbage Collection for deployment: flexible monoliths We may fuse Microservices with Monoliths keeping all their benefits: 1. Develop services (Roles1) separately, even in multirepo, 2. Each Role is a Garbage Collection Root, 3. Build a single Docker image with multiple Roles in it, 4. Pass Roles you want to start as commandline parameters, 5. ⇒ higher computation density, savings on infrastructure, 6. ⇒ substantial development simplification: full environment can be started on a low-end machine with one command. 1 server1# docker run company/product +analytics 2 server2# docker run company/product +accounting +users 3 developer1# docker run company/product +* 4 developer2# docker run company/product --dummy-repositories +* 1 Previous slides on the subject: https://goo.gl/iaMt43 7 / 29
  • 8. distage distage features 8/29 Lifecycle ◮ Applications manage a lot of global resources: 1. Connection pools, thread pools 2. Servers, external endpoints, databases 3. Configurations, metrics, heartbeats 4. External log sinks ◮ They have to be started and closed in integration tests, ◮ We shouldn’t set them up manually for every test, ◮ We want to create reusable components that correctly share a single resource. 8 / 29
  • 9. distage distage features 9/29 Lifecycle: .fromResource 1. Inject any cats-effect Resource 2. Global resources deallocate when the app or test ends 1 object App extends IOApp { 2 val blazeClientModule = new ModuleDef { 3 make[ExecutionContext].from(ExecutionContext.global) 4 addImplicit[Bracket[IO, Throwable]] 5 6 make[Client[IO]].fromResource { ec: ExecutionContext => 7 BlazeClientBuilder[IO](ec).resource 8 }} 9 10 def run(args: List[String]): IO[ExitCode] = 11 Injector().produceF[IO](blazeClientModule) 12 .use { // Client allocated 13 _.get[Client[IO]].expect[String]("https://google.com") 14 }.as(ExitCode.Success) // Client closed 15 } 9 / 29
  • 10. distage distage features 10/29 Effectful creation: .fromEffect Global mutable state must be created effectfully, but doesn’t have to be deallocated. e.g. a global parallelism limiter: 1 import distage._, import scalaz.zio._ 2 3 case class UploadConfig(maxParallelUploads: Long) 4 5 class UploaderModule extends ModuleDef { 6 make[Semaphore].named("upload-limit").fromEffect { 7 conf: UploadConfig @ConfPath("myapp.uploads") => 8 Semaphore.make(conf.maxParallelUploads) } 9 make[Uploader] 10 } 11 class Uploader(limit: Semaphore @Id("upload-limit")) { 12 def upload(content: Content): IO[Throwable, Unit] = 13 limit.withPermit(...) 14 } 10 / 29
  • 11. distage distage features 11/29 Config support distage has HOCON configuration extension. 1 case class HostPort(host: String, port: Int) 2 3 class HttpServer(@ConfPath("http.listen") listenOn: HostPort) { 4 // ... 5 } The extension: 1. Enumerates all the missing references in a Plan, 2. Searches them for a specific @ConfPath annotation, 3. Tries to find corresponding sections in config source, 4. Extends plan with config values, 5. ⇒ Config values are parsed before instantiation begins, 6. ⇒ Problems are shown quickly and all at once, 7. ⇒ Compile-time checker plugin validates config. 11 / 29
  • 12. distage distage features 12/29 Dynamic Plugins Just drop your modules into your classpath: 1 class AccountingModule extends PluginDef { 2 make[AccountingService].from[AccountingServiceImpl] 3 // ... 4 } Then you may pick up all the modules and build your context: 1 val plugins = new PluginLoaderDefaultImpl( 2 PluginConfig(Seq("com.company.plugins")) 3 ).load() 4 // ... pass loaded modules to Injector 1. Useful while you are prototyping your app, 2. In maintenance phase you may switch to static configuration. 12 / 29
  • 13. distage distage features 13/29 Circular dependencies 1. Supported via Proxies, 2. Cyclic by-name parameters (class C(param: => P)) will work without run-time code-generation, 3. Circular dependency support can be disabled. Limitations: 1. You cannot use an injected parameter immediately during initialization, 2. You cannot have non-by-name circular dependencies with final classes, 13 / 29
  • 14. distage distage features 14/29 Trait Augmentation 1 trait UsersService { 2 protected def repository: UsersRepo 3 4 def add(user: User): Unit = { 5 repository.put(user.id, user) 6 } 7 } We may bind this trait directly, without an implementation class: 1 make[UsersService] 1. Corresponding class will be generated1 by distage, 2. Abstract defs will be wired with values from the object graph, 1 both runtime and compile-time cogen supported 14 / 29
  • 15. distage distage features 15/29 Assisted Injection (Factory Methods) 1 class UserActor(sessionId: UUID, sessionRepo: SessionRepo) 2 3 trait ActorFactory { 4 def createActor(sessionId: UUID): UserActor 5 } 1. createActor is a factory method, 2. createActor will be generated by distage, 3. Abstract methods with parameters are treated as factory methods, 4. Non-invasive assisted injection: sessionId: UUID will be taken from method parameter, sessionRepo: SessionRepo will be wired from context, 5. Useful for Akka, lot more convenient than Guice, 6. Works in both runtime and compile-time. 15 / 29
  • 16. distage distage features 16/29 Extension: Automatic Sets 1. All instances of type T (like AutoCloseable) as a Set[T], 2. Strong and Weak References: ◮ GC collects weak referenced members with no more references Example: basic lifecycle support: (please use Resource bindings in real apps!) 1 trait Resource { 2 def start(): Unit 3 def stop(): Unit 4 } 5 trait App { def main(): Unit } 6 locator.run { (resources: Set[Resource], app: App) => 7 try { 8 resources.foreach(_.start()) 9 app.main() 10 } finally { resources.foreach(_.close()) } 11 } 16 / 29
  • 17. distage distage internals 17/29 How it works: Plans distage takes your bindings and then: 1. translates bindings into simple Turing-incomplete DSL (like make , reference , etc.), 2. represents the DSL statements as Directed Acyclic Graph using dependecy information and breaking circular dependencies if any, 3. resolves conflicts (one DAG node with several associated operations), 4. performs garbage collection, 5. applies other transformations (like config reference resolution), 6. turns the DAG back into sequential form — a Plan — with topological sorting. 7. ⇒ the Plan may be introspected, printed, executed in compile-time by a code generator or executed in runtime. 17 / 29
  • 18. distage distage internals 18/29 Plan Introspection: example context 1 class Cluster 2 trait UsersService 3 trait AccountingService 4 trait UserRepo 5 trait AccountsRepo 6 7 class UserRepoImpl(cluster: Cluster) extends UserRepo 8 class AccountsRepoImpl(cluster: Cluster) extends AccountsRepo 9 class UserServiceImpl(userRepo: UserRepo) extends UsersService 10 class AccountingServiceImpl(accountsRepo: AccountsRepo) 11 extends AccountingService 12 13 class UsersApiImpl(service: UsersService 14 , accountsApi: AccountsApiImpl) 15 class AccountsApiImpl(service: AccountingService 16 , usersApi: UsersApiImpl) // circular dependency 17 class App(uapi: UsersApiImpl, aapi: AccountsApiImpl) 18 / 29
  • 19. distage distage internals 19/29 Plan Introspection: example bindings1 1 val definition = new ModuleDef { 2 make[Cluster] 3 make[UserRepo].from[UserRepoImpl] 4 make[AccountsRepo].from[AccountsRepoImpl] 5 make[UsersService].from[UserServiceImpl] 6 make[AccountingService].from[AccountingServiceImpl] 7 make[UsersApiImpl] 8 make[AccountsApiImpl] 9 make[App] 10 } 11 val injector = Injector() 12 val plan = injector.plan(definition) 1 Full code example: https://goo.gl/7ZwHfX 19 / 29
  • 20. distage distage internals 20/29 Plan Introspection: graphviz dumps1 1 Generated automatically by GraphDumpObserver distage extension 20 / 29
  • 21. distage distage internals 21/29 Plan Introspection: plan dumps 1 println(plan.render) // look for the circular dependency! 21 / 29
  • 22. distage distage internals 22/29 Plan Introspection: dependency trees You may explore dependencies of a component: 1 val dependencies = plan.topology.dependencies 2 println(dependencies.tree(DIKey.get[AccountsApiImpl])) Circular dependencies are marked with a circle symbol. 22 / 29
  • 23. distage distage internals 23/29 Compile-Time and Runtime DI A Plan: 1 myRepository := create[MyRepository]() 2 myservice := create[MyService](myRepository) May be interpreted as: Code tree (compile-time): 1 val myRepository = 2 new MyRepository() 3 val myservice = 4 new MyService(myRepository) Set of instances (runtime): 1 plan.foldLeft(Context.empty) { 2 case (ctx, op) => 3 ctx.withInstance( 4 op.key 5 , interpret(action) 6 ) 7 } 23 / 29
  • 25. distage 7mind stack 25/29 distage: status and things to do distage 0.7: 1. is ready to use, 2. is in production for over 1 year, 3. has all runtime features available, 4. has all compile-time features available except for full compile-time mode. What’s next: 1. New Resource-based Roles API, 2. Scala.js support, 3. Compile-time Producer, 4. Isolated Classloaders for Roles (in future), 5. Check our GitHub: https://github.com/pshirshov/izumi-r2. 25 / 29
  • 26. distage 7mind stack 26/29 distage is just a part of our stack We have a vision backed by our tools: 1. Idealingua: transport and codec agnostic gRPC alternative with rich modeling language, 2. LogStage: zero-cost structured logging framework, 3. Fusional Programming and Design guidelines. We love both FP and OOP, 4. Continous Delivery guidelines for Role-based process, 5. Percept-Plan-Execute Generative Programming approach, abstract machine and computational model. Addresses Project Planning (see Operations Research). Examples: orchestration, build systems. Altogether these things already allowed us to significantly reduce development costs and delivery time for our client. More slides to follow. 26 / 29
  • 27. distage 7mind stack 27/29 You use Guice? Switch to distage! “Given its native support for type classes and higher-kinded types – both features indispensable to functional programming – DI Stage is one of the leading dependency injection libraries out there. Bonus points for being built by a wicked-smart team that contributes to ZIO!” –– John A. De Goes 27 / 29
  • 28. distage 7mind stack 28/29 Teaser: LogStage A simple logging call . . . 1 log.info(s"$user logged in with $sessionId!") May be rendered as text: 17:05:18 UserService.login user=John Doe logged in with sessionId=DEADBEEF! Or as structured JSON: 1 { 2 "user": "John Doe", 3 "sessionId": "DEADBEEF", 4 "_template": "$user logged in with $sessionId!", 5 "_location": "UserService.scala:265", 6 "_context": "UserService.login", 7 } 28 / 29
  • 29. distage 7mind stack 29/29 Thank you for your attention distage website: https://izumi.7mind.io/ We’re looking for clients, contributors, adopters and colleagues ;) About the author: 1. coding for 19 years, 12 years of hands-on commercial engineering experience, 2. has been leading a cluster orchestration team in Yandex, “the Russian Google”, 3. Created “Yandex Interstellar Spaceship” – an orchestration solution to manage 50K+ physical machines across 6 datacenters, 4. Owns an Irish R&D company, https://7mind.io, 5. Contact: team@7mind.io, 6. Github: https://github.com/pshirshov 7. Slides: https://github.com/7mind/slides/ 29 / 29