SlideShare a Scribd company logo
1 of 46
Download to read offline
SCALA,
FUNCTIONAL PROGRAMMING AND
TEAM PRODUCTIVITY
INTRO
WHO WE ARE
▸ Pavel and Kai
▸ Septimal Mind, an Irish consultancy
▸ Engineer’s productivity is our primary concern
▸ Love Scala and pure FP
▸ Scala contributors
INTRO
WHAT WE DO
▸ We identify productivity issues in SDLC pipeline
▸ We build tools to address these issues
▸ How do we decide to write a new tool?
▸ Prototype should take one engineer at most two weeks
CASE STUDY
CASE STUDY: STARTING POINT (JAN/2018)
▸ Millions of users, +100K each month
▸ About 30 engineers
▸ Back-end: About 10 microservices, multirepo
▸ Front-end: mobile apps, web portal
▸ Scala as Java+ (akka-http, guice), C#, Go, Typescript
CASE STUDY
CASE STUDY: OUTCOME (JUN/2019)
Development costs cut by 50%
(management estimation)
CASE STUDY
WHAT WAS WRONG?
Late problem detection

Actual integration postponed to production
INTRO
WHAT WAS WRONG
▸ A lot of issues discovered in production
▸ Bugs
▸ Component incompatibilities
▸ Frontend incompatibilities
▸ Not enough insights to debug after failure
▸ Hard to just observe the product: 13 repositories
▸ Hard to get people on board
ISSUES
WHAT WAS WRONG?
No Real Continuous Integration
CASE STUDY
CASE STUDY: WHAT WE DID
The problems mentioned are fundamental...
... but we made things better...
...for this particular company
CASE STUDY
CASE STUDY: WHAT WE DID
▸ Formal interfaces: own IDL/DML/RPC compiler
▸ Better insights & metrics: own effort-free structured logging
▸ Convenient monorepo, better GIT flow
▸ Code quality: pure FP and Bifunctor Tagless Final
▸ Asynchronous stacktraces for ZIO
▸ Fast and reliable tests (including integration ones)
▸ "Flexible Monolith", multi-tenant applications
▸ Proper Continuous Integration
▸ Simplified onboarding
CASE STUDY
CASE STUDY: WHAT WE DID
Issue Solution
Late problem detection Early Integration

(IDL, Cheap Simulations, Dual tests, Bifunctor IO, Pure FP, TF)
Complicated onboarding
Better Observability

(Monorepo, Integration Checks, Dual Tests)
Lack of insights
Effortless insights

(Structural Logging, Async Stacktraces)
Code sharing
Observability, No Local Publishing

(Monorepo, Unified Stack, Unified Framework)
ISSUES
CASE STUDY: WHAT WE DID
Let's focus on
Tests and Microservices
ISSUES
WHAT WAS WRONG WITH TESTS
▸ Speed
▸ 600 tests
▸ 20 minutes total
▸ 17 for component startup and shutdown
▸ Interference
▸ Can’t run tests in parallel
▸ Slow External Dependencies
▸ Hard to wire Dummies (Guice)
ISSUES
WHAT WAS WRONG WITH MICROSERVICES
▸ Hard to share & reuse the code
▸ One shared Dev Env, hard to replicate locally
▸ Up to 70% of developer's time spent for retries and startups
▸ Automated Deployments & Orchestration
▸ Hard
▸ Fast, correct startup & shutdown are important...
▸ ...but hard to implement manually (order, variability)
GOALS
GOALS
▸ Improve development workflows
▸ Improve deployment workflows
▸ Continuously Integrate microservice fleet
▸ Improve team collaboration
▸ Simplify onboarding
GOALS
GOALS
How?


— Automatically Reconfigurable Applications
GOALS
GOALS
Product := Build(Components, Goals)
AUTOMATIC 

APPLICATION
COMPOSITION
GOALS
GOALS
▸ Test Business Logic without external dependencies
▸ Test Business Logic with real external dependencies too
▸ Correctly share (memoize) heavy resources between tests
▸ Let a new developer checkout & test immediately
▸ Let front-end engineers run isolated dev envs quickly & easily
DISTAGE FRAMEWORK
DIStage Framework
DISTAGE FRAMEWORK
AUTOMATED APPLICATION COMPOSITION: THE MODEL
object ServiceDemo {
trait Repository[F[_, _]]
class DummyRepository[F[_, _]] extends Repository[F]
class ProdRepository[F[_, _]] extends Repository[F]
class Service[F[_, _]](c: Repository[F]) extends
Repository[F]
class App[F[_, _]](s: Service[F]) {
def run: F[Throwable, Unit] = ???
}
}
DISTAGE FRAMEWORK
AUTOMATED APPLICATION COMPOSITION: DEFINITIONS
def definition[F[_, _]: TagKK] = new ModuleDef {
make[App[F]]
make[Service[F]]
make[Repository[F]].tagged(Repo.Dummy).from[DummyRepository[F]]
make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]]
}
DISTAGE FRAMEWORK
AUTOMATED APPLICATION COMPOSITION: STARTING THE APP
Injector(Activation(Repo -> Prod))
.produceRunF(definition[zio.IO]) {
app: App[zio.IO] =>
app.run
}
DISTAGE FRAMEWORK
AUTOMATED APPLICATION COMPOSITION: THE IDEA
distage app

=

set of formulas

Product := Recipe(Materials, ...)

+

set of "root" products

Set(Roots, ...)

+

configuration rules

Activation
DISTAGE FRAMEWORK
AUTOMATED APPLICATION COMPOSITION: THE DIFFERENCE
▸ Like Guice and other DIs, distage
▸ turns application wiring code into a set of declarations
▸ automatically orders wiring actions
DISTAGE FRAMEWORK
AUTOMATED APPLICATION COMPOSITION: THE DIFFERENCE
But not just that
DISTAGE FRAMEWORK
AUTOMATIC CONFIGURATIONS
make[Repository[F]].tagged(Repo.Dummy).from[DummyRepository[F]]
make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]]
DISTAGE FRAMEWORK
AUTOMATIC CONFIGURATIONS
Injector(Activation(Repo -> Repo.Prod))
make[Repository[F]].tagged(Repo.Dummy).from[DummyRepository[F]]
make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]]
DISTAGE FRAMEWORK
AUTOMATIC CONFIGURATIONS
Injector(Activation(Repo -> Repo.Prod))
make[Repository[F]].tagged(Repo.Dummy).from[DummyRepository[F]]
make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]]
DISTAGE FRAMEWORK
RESOURCES
trait DIResource[F[_], Resource] {
def acquire: F[Resource]
def release(resource: Resource): F[Unit]
}
▸ Functional description of lifecycle
▸ Initialisation without mutable state
DISTAGE FRAMEWORK
RESOURCES
// library ...
class DbDriver[F[_]] {
def shutdown: F[Unit]
}
def connectToDb[F[_]: Sync]: DbDriver[F]
// …
class ProdRepository[F[_]](db: DbDriver[F]) extends Repository
// definition ...
make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]]
make[DbDriver[F]].fromResource(DIResource.make(connectToDb)(_.shutdown))
// ...
▸ Graceful shutdown is always guaranteed, even in case of an exception
▸ Docker Containers may be expressed as resources
▸ Embedded replacement for docker-compose
DISTAGE FRAMEWORK
INTEGRATION CHECKS
▸ Check if an external service is available
▸ Tests will be skipped if checks fail
▸ The app will not start if checks fail
▸ Integration checks run before all initialisation
DISTAGE FRAMEWORK
INTEGRATION CHECKS
class DbCheck extends IntegrationCheck {
def resourcesAvailable(): ResourceCheck = {
if (checkPort()) ResourceCheck.Success()
else ResourceCheck.ResourceUnavailable("Can't connect to DB", None)
}
private def checkPort(): Boolean = ???
}
▸ Check if an external service is available
▸ Tests will be skipped if checks fail
▸ The app will not start if checks fail
▸ Integration checks run before all initialisation
DISTAGE FRAMEWORK
DUAL TEST TACTIC
▸ Helps draft business logic quickly
▸ Enforces SOLID design
▸ Does not prevent integration tests
▸ Speeds up onboarding
DISTAGE FRAMEWORK
DUAL TEST TACTIC: CODE
abstract class ServiceTest extends DistageBIOEnvSpecScalatest[ZIO] {
"our service" should {
"do something" in {
service: Service[zio.IO] => for {
// ...
} yield ()
}
}
}
trait DummyEnv extends DistageBIOEnvSpecScalatest[ZIO] {
override def config: TestConfig = super.config.copy(
activation = Activation(Repo -> Dummy))
}
trait ProdEnv extends DistageBIOEnvSpecScalatest[ZIO] {
override def config: TestConfig = super.config.copy(
activation = Activation(Repo -> Prod))
}
final class ServiceProdTest extends ServiceTest with ProdEnv
final class ServiceDummyTest extends ServiceTest with DummyEnv
DISTAGE FRAMEWORK
MEMOIZATION
abstract class DistageTestExample extends DistageBIOEnvSpecScalatest[ZIO] {
override def config: TestConfig = {
super.config.copy(memoizationRoots = Set(DIKey.get[DbDriver[zio.IO]]))
}
"our service" should {
"do something" in {
repository: Repository[zio.IO] =>
//...
}
"and do something else" in {
repository: Repository[zio.IO] =>
//...
}
}
}
DISTAGE FRAMEWORK
MEMOIZATION
▸ DbDriver will be shared across all the tests
▸ Without any singletons
▸ With graceful shutdown
▸ With separate contexts for different configurations
DISTAGE FRAMEWORK
AUTOMATED APPLICATION COMPOSITION: THE DIFFERENCE
▸ verifies correctness ahead of time
▸ supports resources and lifecycle
▸ provides a way to define configurable apps
▸ can perform integration checks ahead of time
▸ can perform graceful shutdown automatically
▸ can share components between multiple tests & entrypoints
DISTAGE:
ROLES
AS MEANS OF
CONTINUOUS INTEGRATION
Yes, Integration
DISTAGE FRAMEWORK
ROLES
class UsersRole extends RoleService[zio.Task] {
override def start(params: RawEntrypointParams, args: Vector[String]): DIResource[zio.Task, Unit] =
DIResource.make(acquire = {
// initialisation
})(release = {
_ =>
// shutdown
})
}
object UsersRole extends RoleDescriptor {
override final val id = "users"
}
# java -jar myapp.jar -u repo:prod -u transport:prod :users :accounts
# java -jar myapp.jar -u repo:dummy -u transport:vm :users :accounts
DISTAGE FRAMEWORK
ROLES
▸ Multiple "microservices" per process
▸ More flexibility for deployments
▸ Simulations
DISTAGE FRAMEWORK
ROLES
▸ Dev environment simulation in one process
▸ Even with in-memory mocks!
▸ Not a replacement for the dev env, but nice addition.
▸ Imperfect simulations are great anyway!
▸ Model imperfectness can be granularly adjusted
REAL CI
CONTINUOUS INTEGRATION
▸ A Microservice Fleet is a Distributed Application
▸ And that application is The Product
▸ Microservices are just components of our Product
▸ We should integrate them continuously too!
▸ But it's hard to start and test a distributed application
REAL CI
DISTRIBUTED APPLICATION SIMULATIONS
▸ Several "microservices" (roles) in one process
▸ Dummies for every Integration Point
▸ Easy configuration
▸ Cheap product models for Continuous Integration
▸ There is no need to fail in production
➡
DISTAGE FRAMEWORK
ROLES AND TEAMS
▸ Multi-tenant applications do not require a Monorepo
▸ It's possible to have a repository per role
▸ Each role repository may define individual role launcher
▸ And there may be one or more launcher repositories
▸ Drawback: unified framework is required
Thank you!
distage example:
https://github.com/7mind/distage-example
Pavel:
https://twitter.com/shirshovp
Kai:
https://twitter.com/kai_nyasha

More Related Content

What's hot

Test Driven Development with JavaFX
Test Driven Development with JavaFXTest Driven Development with JavaFX
Test Driven Development with JavaFXHendrik Ebbers
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails AppsRabble .
 
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?Julian Robichaux
 
How to setup unit testing in Android Studio
How to setup unit testing in Android StudioHow to setup unit testing in Android Studio
How to setup unit testing in Android Studiotobiaspreuss
 
Java 9 New Features
Java 9 New FeaturesJava 9 New Features
Java 9 New FeaturesAli BAKAN
 
Introduction maven3 and gwt2.5 rc2 - Lesson 01
Introduction maven3 and gwt2.5 rc2 - Lesson 01Introduction maven3 and gwt2.5 rc2 - Lesson 01
Introduction maven3 and gwt2.5 rc2 - Lesson 01rhemsolutions
 
Efficient JavaScript Unit Testing, JavaOne China 2013
Efficient JavaScript Unit Testing, JavaOne China 2013Efficient JavaScript Unit Testing, JavaOne China 2013
Efficient JavaScript Unit Testing, JavaOne China 2013Hazem Saleh
 
[AnDevCon 2016] Mutation Testing for Android
[AnDevCon 2016] Mutation Testing for Android[AnDevCon 2016] Mutation Testing for Android
[AnDevCon 2016] Mutation Testing for AndroidHazem Saleh
 
Load Testing with k6 framework
Load Testing with k6 frameworkLoad Testing with k6 framework
Load Testing with k6 frameworkSvetlin Nakov
 
Unit Test Android Without Going Bald
Unit Test Android Without Going BaldUnit Test Android Without Going Bald
Unit Test Android Without Going BaldDavid Carver
 
Managed Beans: When, Why and How
Managed Beans: When, Why and HowManaged Beans: When, Why and How
Managed Beans: When, Why and HowRussell Maher
 
Architecting your GWT applications with GWT-Platform - Lesson 02
Architecting your GWT applications with GWT-Platform - Lesson 02Architecting your GWT applications with GWT-Platform - Lesson 02
Architecting your GWT applications with GWT-Platform - Lesson 02rhemsolutions
 
Testing Your Application On Google App Engine
Testing Your Application On Google App EngineTesting Your Application On Google App Engine
Testing Your Application On Google App EngineIndicThreads
 
PHP Unit Testing in Yii
PHP Unit Testing in YiiPHP Unit Testing in Yii
PHP Unit Testing in YiiIlPeach
 
Devoxx17 - Préparez-vous à la modularité selon Java 9
Devoxx17 - Préparez-vous à la modularité selon Java 9Devoxx17 - Préparez-vous à la modularité selon Java 9
Devoxx17 - Préparez-vous à la modularité selon Java 9Alexis Hassler
 
Selenium-Browser-Based-Automated-Testing-for-Grails-Apps
Selenium-Browser-Based-Automated-Testing-for-Grails-AppsSelenium-Browser-Based-Automated-Testing-for-Grails-Apps
Selenium-Browser-Based-Automated-Testing-for-Grails-Appschrisb206 chrisb206
 
Супер быстрая автоматизация тестирования на iOS
Супер быстрая автоматизация тестирования на iOSСупер быстрая автоматизация тестирования на iOS
Супер быстрая автоматизация тестирования на iOSSQALab
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Codescidept
 

What's hot (20)

Test Driven Development with JavaFX
Test Driven Development with JavaFXTest Driven Development with JavaFX
Test Driven Development with JavaFX
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails Apps
 
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?
 
How to setup unit testing in Android Studio
How to setup unit testing in Android StudioHow to setup unit testing in Android Studio
How to setup unit testing in Android Studio
 
Java 9 New Features
Java 9 New FeaturesJava 9 New Features
Java 9 New Features
 
Introduction maven3 and gwt2.5 rc2 - Lesson 01
Introduction maven3 and gwt2.5 rc2 - Lesson 01Introduction maven3 and gwt2.5 rc2 - Lesson 01
Introduction maven3 and gwt2.5 rc2 - Lesson 01
 
Efficient JavaScript Unit Testing, JavaOne China 2013
Efficient JavaScript Unit Testing, JavaOne China 2013Efficient JavaScript Unit Testing, JavaOne China 2013
Efficient JavaScript Unit Testing, JavaOne China 2013
 
[AnDevCon 2016] Mutation Testing for Android
[AnDevCon 2016] Mutation Testing for Android[AnDevCon 2016] Mutation Testing for Android
[AnDevCon 2016] Mutation Testing for Android
 
Load Testing with k6 framework
Load Testing with k6 frameworkLoad Testing with k6 framework
Load Testing with k6 framework
 
Unit Test Android Without Going Bald
Unit Test Android Without Going BaldUnit Test Android Without Going Bald
Unit Test Android Without Going Bald
 
Managed Beans: When, Why and How
Managed Beans: When, Why and HowManaged Beans: When, Why and How
Managed Beans: When, Why and How
 
Unit testing - A&BP CC
Unit testing - A&BP CCUnit testing - A&BP CC
Unit testing - A&BP CC
 
Architecting your GWT applications with GWT-Platform - Lesson 02
Architecting your GWT applications with GWT-Platform - Lesson 02Architecting your GWT applications with GWT-Platform - Lesson 02
Architecting your GWT applications with GWT-Platform - Lesson 02
 
Testing Your Application On Google App Engine
Testing Your Application On Google App EngineTesting Your Application On Google App Engine
Testing Your Application On Google App Engine
 
Sling IDE Tooling
Sling IDE ToolingSling IDE Tooling
Sling IDE Tooling
 
PHP Unit Testing in Yii
PHP Unit Testing in YiiPHP Unit Testing in Yii
PHP Unit Testing in Yii
 
Devoxx17 - Préparez-vous à la modularité selon Java 9
Devoxx17 - Préparez-vous à la modularité selon Java 9Devoxx17 - Préparez-vous à la modularité selon Java 9
Devoxx17 - Préparez-vous à la modularité selon Java 9
 
Selenium-Browser-Based-Automated-Testing-for-Grails-Apps
Selenium-Browser-Based-Automated-Testing-for-Grails-AppsSelenium-Browser-Based-Automated-Testing-for-Grails-Apps
Selenium-Browser-Based-Automated-Testing-for-Grails-Apps
 
Супер быстрая автоматизация тестирования на iOS
Супер быстрая автоматизация тестирования на iOSСупер быстрая автоматизация тестирования на iOS
Супер быстрая автоматизация тестирования на iOS
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 

Similar to Scala, Functional Programming and Team Productivity

Javaone - Gradle: Harder, Better, Stronger, Faster
Javaone - Gradle: Harder, Better, Stronger, Faster Javaone - Gradle: Harder, Better, Stronger, Faster
Javaone - Gradle: Harder, Better, Stronger, Faster Andres Almiray
 
Real-World DevOps — 20 Practical Developers Tips for Tightening Your Operatio...
Real-World DevOps — 20 Practical Developers Tips for Tightening Your Operatio...Real-World DevOps — 20 Practical Developers Tips for Tightening Your Operatio...
Real-World DevOps — 20 Practical Developers Tips for Tightening Your Operatio...VictorSzoltysek
 
Testing your application on Google App Engine
Testing your application on Google App EngineTesting your application on Google App Engine
Testing your application on Google App EngineInphina Technologies
 
Testing Vue Apps with Cypress.io (STLJS Meetup April 2018)
Testing Vue Apps with Cypress.io (STLJS Meetup April 2018)Testing Vue Apps with Cypress.io (STLJS Meetup April 2018)
Testing Vue Apps with Cypress.io (STLJS Meetup April 2018)Christian Catalan
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introductionRasheed Waraich
 
Real world Webapp
Real world WebappReal world Webapp
Real world WebappThings Lab
 
Anatomy of a Build Pipeline
Anatomy of a Build PipelineAnatomy of a Build Pipeline
Anatomy of a Build PipelineSamuel Brown
 
AWS Webcast - Build Agile Applications in AWS Cloud for Government
AWS Webcast - Build Agile Applications in AWS Cloud for GovernmentAWS Webcast - Build Agile Applications in AWS Cloud for Government
AWS Webcast - Build Agile Applications in AWS Cloud for GovernmentAmazon Web Services
 
Microsoft SQL Server Testing Frameworks
Microsoft SQL Server Testing FrameworksMicrosoft SQL Server Testing Frameworks
Microsoft SQL Server Testing FrameworksMark Ginnebaugh
 
DevOps in Practice: When does "Practice" Become "Doing"?
DevOps in Practice: When does "Practice" Become "Doing"?DevOps in Practice: When does "Practice" Become "Doing"?
DevOps in Practice: When does "Practice" Become "Doing"?Michael Elder
 
Spring Native and Spring AOT
Spring Native and Spring AOTSpring Native and Spring AOT
Spring Native and Spring AOTVMware Tanzu
 
Scala, docker and testing, oh my! mario camou
Scala, docker and testing, oh my! mario camouScala, docker and testing, oh my! mario camou
Scala, docker and testing, oh my! mario camouJ On The Beach
 
Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)Jared Burrows
 
From 0 to DevOps in 80 Days [Webinar Replay]
From 0 to DevOps in 80 Days [Webinar Replay]From 0 to DevOps in 80 Days [Webinar Replay]
From 0 to DevOps in 80 Days [Webinar Replay]Dynatrace
 
A Fabric/Puppet Build/Deploy System
A Fabric/Puppet Build/Deploy SystemA Fabric/Puppet Build/Deploy System
A Fabric/Puppet Build/Deploy Systemadrian_nye
 
Building JBoss AS 7 for Fedora
Building JBoss AS 7 for FedoraBuilding JBoss AS 7 for Fedora
Building JBoss AS 7 for Fedorawolfc71
 

Similar to Scala, Functional Programming and Team Productivity (20)

Javaone - Gradle: Harder, Better, Stronger, Faster
Javaone - Gradle: Harder, Better, Stronger, Faster Javaone - Gradle: Harder, Better, Stronger, Faster
Javaone - Gradle: Harder, Better, Stronger, Faster
 
Real-World DevOps — 20 Practical Developers Tips for Tightening Your Operatio...
Real-World DevOps — 20 Practical Developers Tips for Tightening Your Operatio...Real-World DevOps — 20 Practical Developers Tips for Tightening Your Operatio...
Real-World DevOps — 20 Practical Developers Tips for Tightening Your Operatio...
 
Testing your application on Google App Engine
Testing your application on Google App EngineTesting your application on Google App Engine
Testing your application on Google App Engine
 
Intro to DevOps
Intro to DevOpsIntro to DevOps
Intro to DevOps
 
React Native
React NativeReact Native
React Native
 
Testing Vue Apps with Cypress.io (STLJS Meetup April 2018)
Testing Vue Apps with Cypress.io (STLJS Meetup April 2018)Testing Vue Apps with Cypress.io (STLJS Meetup April 2018)
Testing Vue Apps with Cypress.io (STLJS Meetup April 2018)
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
 
Rajiv Profile
Rajiv ProfileRajiv Profile
Rajiv Profile
 
Real world Webapp
Real world WebappReal world Webapp
Real world Webapp
 
Anatomy of a Build Pipeline
Anatomy of a Build PipelineAnatomy of a Build Pipeline
Anatomy of a Build Pipeline
 
AWS Webcast - Build Agile Applications in AWS Cloud for Government
AWS Webcast - Build Agile Applications in AWS Cloud for GovernmentAWS Webcast - Build Agile Applications in AWS Cloud for Government
AWS Webcast - Build Agile Applications in AWS Cloud for Government
 
Microsoft SQL Server Testing Frameworks
Microsoft SQL Server Testing FrameworksMicrosoft SQL Server Testing Frameworks
Microsoft SQL Server Testing Frameworks
 
DevOps in Practice: When does "Practice" Become "Doing"?
DevOps in Practice: When does "Practice" Become "Doing"?DevOps in Practice: When does "Practice" Become "Doing"?
DevOps in Practice: When does "Practice" Become "Doing"?
 
Spring Native and Spring AOT
Spring Native and Spring AOTSpring Native and Spring AOT
Spring Native and Spring AOT
 
Scala, docker and testing, oh my! mario camou
Scala, docker and testing, oh my! mario camouScala, docker and testing, oh my! mario camou
Scala, docker and testing, oh my! mario camou
 
Pyramid deployment
Pyramid deploymentPyramid deployment
Pyramid deployment
 
Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)
 
From 0 to DevOps in 80 Days [Webinar Replay]
From 0 to DevOps in 80 Days [Webinar Replay]From 0 to DevOps in 80 Days [Webinar Replay]
From 0 to DevOps in 80 Days [Webinar Replay]
 
A Fabric/Puppet Build/Deploy System
A Fabric/Puppet Build/Deploy SystemA Fabric/Puppet Build/Deploy System
A Fabric/Puppet Build/Deploy System
 
Building JBoss AS 7 for Fedora
Building JBoss AS 7 for FedoraBuilding JBoss AS 7 for Fedora
Building JBoss AS 7 for Fedora
 

Recently uploaded

Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 

Recently uploaded (20)

Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 

Scala, Functional Programming and Team Productivity

  • 2. INTRO WHO WE ARE ▸ Pavel and Kai ▸ Septimal Mind, an Irish consultancy ▸ Engineer’s productivity is our primary concern ▸ Love Scala and pure FP ▸ Scala contributors
  • 3. INTRO WHAT WE DO ▸ We identify productivity issues in SDLC pipeline ▸ We build tools to address these issues ▸ How do we decide to write a new tool? ▸ Prototype should take one engineer at most two weeks
  • 4. CASE STUDY CASE STUDY: STARTING POINT (JAN/2018) ▸ Millions of users, +100K each month ▸ About 30 engineers ▸ Back-end: About 10 microservices, multirepo ▸ Front-end: mobile apps, web portal ▸ Scala as Java+ (akka-http, guice), C#, Go, Typescript
  • 5. CASE STUDY CASE STUDY: OUTCOME (JUN/2019) Development costs cut by 50% (management estimation)
  • 6. CASE STUDY WHAT WAS WRONG? Late problem detection
 Actual integration postponed to production
  • 7. INTRO WHAT WAS WRONG ▸ A lot of issues discovered in production ▸ Bugs ▸ Component incompatibilities ▸ Frontend incompatibilities ▸ Not enough insights to debug after failure ▸ Hard to just observe the product: 13 repositories ▸ Hard to get people on board
  • 8. ISSUES WHAT WAS WRONG? No Real Continuous Integration
  • 9. CASE STUDY CASE STUDY: WHAT WE DID The problems mentioned are fundamental... ... but we made things better... ...for this particular company
  • 10. CASE STUDY CASE STUDY: WHAT WE DID ▸ Formal interfaces: own IDL/DML/RPC compiler ▸ Better insights & metrics: own effort-free structured logging ▸ Convenient monorepo, better GIT flow ▸ Code quality: pure FP and Bifunctor Tagless Final ▸ Asynchronous stacktraces for ZIO ▸ Fast and reliable tests (including integration ones) ▸ "Flexible Monolith", multi-tenant applications ▸ Proper Continuous Integration ▸ Simplified onboarding
  • 11. CASE STUDY CASE STUDY: WHAT WE DID Issue Solution Late problem detection Early Integration
 (IDL, Cheap Simulations, Dual tests, Bifunctor IO, Pure FP, TF) Complicated onboarding Better Observability
 (Monorepo, Integration Checks, Dual Tests) Lack of insights Effortless insights
 (Structural Logging, Async Stacktraces) Code sharing Observability, No Local Publishing
 (Monorepo, Unified Stack, Unified Framework)
  • 12. ISSUES CASE STUDY: WHAT WE DID Let's focus on Tests and Microservices
  • 13. ISSUES WHAT WAS WRONG WITH TESTS ▸ Speed ▸ 600 tests ▸ 20 minutes total ▸ 17 for component startup and shutdown ▸ Interference ▸ Can’t run tests in parallel ▸ Slow External Dependencies ▸ Hard to wire Dummies (Guice)
  • 14. ISSUES WHAT WAS WRONG WITH MICROSERVICES ▸ Hard to share & reuse the code ▸ One shared Dev Env, hard to replicate locally ▸ Up to 70% of developer's time spent for retries and startups ▸ Automated Deployments & Orchestration ▸ Hard ▸ Fast, correct startup & shutdown are important... ▸ ...but hard to implement manually (order, variability)
  • 15. GOALS GOALS ▸ Improve development workflows ▸ Improve deployment workflows ▸ Continuously Integrate microservice fleet ▸ Improve team collaboration ▸ Simplify onboarding
  • 19. GOALS GOALS ▸ Test Business Logic without external dependencies ▸ Test Business Logic with real external dependencies too ▸ Correctly share (memoize) heavy resources between tests ▸ Let a new developer checkout & test immediately ▸ Let front-end engineers run isolated dev envs quickly & easily
  • 21. DISTAGE FRAMEWORK AUTOMATED APPLICATION COMPOSITION: THE MODEL object ServiceDemo { trait Repository[F[_, _]] class DummyRepository[F[_, _]] extends Repository[F] class ProdRepository[F[_, _]] extends Repository[F] class Service[F[_, _]](c: Repository[F]) extends Repository[F] class App[F[_, _]](s: Service[F]) { def run: F[Throwable, Unit] = ??? } }
  • 22. DISTAGE FRAMEWORK AUTOMATED APPLICATION COMPOSITION: DEFINITIONS def definition[F[_, _]: TagKK] = new ModuleDef { make[App[F]] make[Service[F]] make[Repository[F]].tagged(Repo.Dummy).from[DummyRepository[F]] make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]] }
  • 23. DISTAGE FRAMEWORK AUTOMATED APPLICATION COMPOSITION: STARTING THE APP Injector(Activation(Repo -> Prod)) .produceRunF(definition[zio.IO]) { app: App[zio.IO] => app.run }
  • 24. DISTAGE FRAMEWORK AUTOMATED APPLICATION COMPOSITION: THE IDEA distage app
 =
 set of formulas
 Product := Recipe(Materials, ...)
 +
 set of "root" products
 Set(Roots, ...)
 +
 configuration rules
 Activation
  • 25. DISTAGE FRAMEWORK AUTOMATED APPLICATION COMPOSITION: THE DIFFERENCE ▸ Like Guice and other DIs, distage ▸ turns application wiring code into a set of declarations ▸ automatically orders wiring actions
  • 26. DISTAGE FRAMEWORK AUTOMATED APPLICATION COMPOSITION: THE DIFFERENCE But not just that
  • 28. DISTAGE FRAMEWORK AUTOMATIC CONFIGURATIONS Injector(Activation(Repo -> Repo.Prod)) make[Repository[F]].tagged(Repo.Dummy).from[DummyRepository[F]] make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]]
  • 29. DISTAGE FRAMEWORK AUTOMATIC CONFIGURATIONS Injector(Activation(Repo -> Repo.Prod)) make[Repository[F]].tagged(Repo.Dummy).from[DummyRepository[F]] make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]]
  • 30. DISTAGE FRAMEWORK RESOURCES trait DIResource[F[_], Resource] { def acquire: F[Resource] def release(resource: Resource): F[Unit] } ▸ Functional description of lifecycle ▸ Initialisation without mutable state
  • 31. DISTAGE FRAMEWORK RESOURCES // library ... class DbDriver[F[_]] { def shutdown: F[Unit] } def connectToDb[F[_]: Sync]: DbDriver[F] // … class ProdRepository[F[_]](db: DbDriver[F]) extends Repository // definition ... make[Repository[F]].tagged(Repo.Prod).from[ProdRepository[F]] make[DbDriver[F]].fromResource(DIResource.make(connectToDb)(_.shutdown)) // ... ▸ Graceful shutdown is always guaranteed, even in case of an exception ▸ Docker Containers may be expressed as resources ▸ Embedded replacement for docker-compose
  • 32. DISTAGE FRAMEWORK INTEGRATION CHECKS ▸ Check if an external service is available ▸ Tests will be skipped if checks fail ▸ The app will not start if checks fail ▸ Integration checks run before all initialisation
  • 33. DISTAGE FRAMEWORK INTEGRATION CHECKS class DbCheck extends IntegrationCheck { def resourcesAvailable(): ResourceCheck = { if (checkPort()) ResourceCheck.Success() else ResourceCheck.ResourceUnavailable("Can't connect to DB", None) } private def checkPort(): Boolean = ??? } ▸ Check if an external service is available ▸ Tests will be skipped if checks fail ▸ The app will not start if checks fail ▸ Integration checks run before all initialisation
  • 34. DISTAGE FRAMEWORK DUAL TEST TACTIC ▸ Helps draft business logic quickly ▸ Enforces SOLID design ▸ Does not prevent integration tests ▸ Speeds up onboarding
  • 35. DISTAGE FRAMEWORK DUAL TEST TACTIC: CODE abstract class ServiceTest extends DistageBIOEnvSpecScalatest[ZIO] { "our service" should { "do something" in { service: Service[zio.IO] => for { // ... } yield () } } } trait DummyEnv extends DistageBIOEnvSpecScalatest[ZIO] { override def config: TestConfig = super.config.copy( activation = Activation(Repo -> Dummy)) } trait ProdEnv extends DistageBIOEnvSpecScalatest[ZIO] { override def config: TestConfig = super.config.copy( activation = Activation(Repo -> Prod)) } final class ServiceProdTest extends ServiceTest with ProdEnv final class ServiceDummyTest extends ServiceTest with DummyEnv
  • 36. DISTAGE FRAMEWORK MEMOIZATION abstract class DistageTestExample extends DistageBIOEnvSpecScalatest[ZIO] { override def config: TestConfig = { super.config.copy(memoizationRoots = Set(DIKey.get[DbDriver[zio.IO]])) } "our service" should { "do something" in { repository: Repository[zio.IO] => //... } "and do something else" in { repository: Repository[zio.IO] => //... } } }
  • 37. DISTAGE FRAMEWORK MEMOIZATION ▸ DbDriver will be shared across all the tests ▸ Without any singletons ▸ With graceful shutdown ▸ With separate contexts for different configurations
  • 38. DISTAGE FRAMEWORK AUTOMATED APPLICATION COMPOSITION: THE DIFFERENCE ▸ verifies correctness ahead of time ▸ supports resources and lifecycle ▸ provides a way to define configurable apps ▸ can perform integration checks ahead of time ▸ can perform graceful shutdown automatically ▸ can share components between multiple tests & entrypoints DISTAGE:
  • 39. ROLES AS MEANS OF CONTINUOUS INTEGRATION Yes, Integration
  • 40. DISTAGE FRAMEWORK ROLES class UsersRole extends RoleService[zio.Task] { override def start(params: RawEntrypointParams, args: Vector[String]): DIResource[zio.Task, Unit] = DIResource.make(acquire = { // initialisation })(release = { _ => // shutdown }) } object UsersRole extends RoleDescriptor { override final val id = "users" } # java -jar myapp.jar -u repo:prod -u transport:prod :users :accounts # java -jar myapp.jar -u repo:dummy -u transport:vm :users :accounts
  • 41. DISTAGE FRAMEWORK ROLES ▸ Multiple "microservices" per process ▸ More flexibility for deployments ▸ Simulations
  • 42. DISTAGE FRAMEWORK ROLES ▸ Dev environment simulation in one process ▸ Even with in-memory mocks! ▸ Not a replacement for the dev env, but nice addition. ▸ Imperfect simulations are great anyway! ▸ Model imperfectness can be granularly adjusted
  • 43. REAL CI CONTINUOUS INTEGRATION ▸ A Microservice Fleet is a Distributed Application ▸ And that application is The Product ▸ Microservices are just components of our Product ▸ We should integrate them continuously too! ▸ But it's hard to start and test a distributed application
  • 44. REAL CI DISTRIBUTED APPLICATION SIMULATIONS ▸ Several "microservices" (roles) in one process ▸ Dummies for every Integration Point ▸ Easy configuration ▸ Cheap product models for Continuous Integration ▸ There is no need to fail in production ➡
  • 45. DISTAGE FRAMEWORK ROLES AND TEAMS ▸ Multi-tenant applications do not require a Monorepo ▸ It's possible to have a repository per role ▸ Each role repository may define individual role launcher ▸ And there may be one or more launcher repositories ▸ Drawback: unified framework is required