SlideShare una empresa de Scribd logo
1 de 94
Descargar para leer sin conexión
Towards Functional Programming 🦄
through Hexagonal Architecture 🎯
Habla Computing + CodelyTV
Acercándonos a la Programación Funcional 🦄
a través de la Arquitectura Hexagonal 🎯
Habla Computing + CodelyTV
Text
#SCBCN18
Software Crafters Barcelona - VI Edition
Functional Programming intro based on Hexagonal Architecture
Who we are
@JavierCane@juanshac
Session goal
🤔

Rethinking time
Functional Programming intro based on Hexagonal Architecture
Reviewing different technics to solve the same problems with more modularity
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
🗺 Design principles > 🎯 Hexagonal Architecture
🛀 Clean Architectures
🤯 Ports & adapters
🚫
🗺 Design principles > 🎯 Hexagonal Architecture
Layers & dependency rule
Infrastructure
Application
Domain
🗺 Design principles > 🎯 Hexagonal Architecture
Layered Architecture
Presentation
Domain
Database
🗺 Design principles > 🎯 Hexagonal Architecture
Layered vs Hexagonal
Presentation
Domain
Database
Infrastructure
Application
Domain
🗺 Design principles > 🎯 Hexagonal Architecture
CONTROLLER
REPOS
MODELS
SERVICES
APPLICATION SERVICE
D
A
I
Request flow
IMPLEMENTATION
Acceptance test
Unit test Integration test
🗺 Design principles > 🎯 Hexagonal Architecture
Acceptance test
Unit test Integration test
CONTROLLER
REPOS
MODELS
SERVICES
APPLICATION SERVICE
D
A
I
Request flow
IMPLEMENTATION
🗺 Design principles > 🎯 Hexagonal Architecture
Port
Adapter
VideoPostController
VideoRepository
VideoVideoCreator
D
A
I
DoobieMySqlVideoRepo
Acceptance test
Unit test Integration test
Request flow example
🗺 Design principles > 🎯 Hexagonal Architecture
VideoPostController
VideoRepository
VideoVideoCreator
D
A
I
DoobieMySqlVideoRepo
Acceptance test
Unit test Integration test
Port
Adapter
🗺 Design principles > 🎯 Hexagonal Architecture
Request flow example
Domain Events, CQRS, and Event Sourcing as an optional further step
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
What is a functional architecture?
DSL1
DSL2
DSLN
…
🗺 Design principles > 🦄 Functional Architectures
A FUNCTIONAL LANGUAGE IS A DOMAIN-
SPECIFIC LANGUAGE FOR DEFINING
DOMAIN-SPECIFIC LANGUAGES
The DSLs of your application
• Infrastructure DSLs
• HTTP
• Databases
• Messaging
• Application-specific DSLs
• Use cases
• Repos
• …
HTTP
SERVICE DSL
SQL
REPO DSL
🗺 Design principles > 🦄 Functional Architectures
Are hexagonal and functional architectures like apples and oranges?
HTTP
SERVICE DSL
SQL
REPO DSL
CONTROLLER
SERVICE IMPL.
ORM
DB
ADAPTER/INTERP.
PORT/DSL
🗺 Design principles > 🦄 Functional Architectures
There are no exceptions • Everything is either a port or an adapter
• Every adapter implements a given port
• Adapters are implemented on top of other ports
VideoPostController
VideoRepositoryVideoRepoC
DoobieMySqlVideoRepo
VideoCreator
HTTP
🗺 Design principles > 🦄 Functional Architectures
🎯
🦄
VideoPostController
VideoRepository
VideoCreator
DoobieMySqlVideoRepo
VideoPostController
VideoRepositoryVideoRepoC
DoobieMySqlVideoRepo
VideoCreator
HTTP
🤔 Rethinking time
🗺 Design principles
🗺 Design principles > 🤔 Rethinking time
Final goals
• Decouple from infrastructure
• Testing easiness (test doubles when testing out use cases)
• Change tolerance
• ¡Same goals!
🗺 Design principles > 🤔 Rethinking time
Differences: More decoupling and indirection levels
• Controllers:
• Consistency (APIs for all DSLs) vs. Specific needs
• Conclusion: We need industry standards. PHP-FIG as example to follow
• Application Services:
• Consistency (APIs for all DSLs) vs. Specific needs
• Reuse use case APIs in clients (e.g. user clients)
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
🎯 OOP
👤 Domain models
final case class Video(
id: VideoId,
title: VideoTitle,
quality: VideoQuality
)
👤 Domain models > 🎯 OOP > Video Entity
object Video {
def apply(id: String, title: String, quality: Int): Video =
Video(
VideoId(id),
VideoTitle(title),
VideoQuality(quality)
)
}
final case class Video(
id: VideoId,
title: VideoTitle,
quality: VideoQuality
)
👤 Domain models > 🎯 OOP > Video Entity
object Video {
def apply(id: String, title: String, quality: Int): Video =
Video(
VideoId(id),
VideoTitle(title),
VideoQuality(quality)
)
}
final case class Video(
id: VideoId,
title: VideoTitle,
quality: VideoQuality
)
👤 Domain models > 🎯 OOP > Video Entity
object VideoQuality {
val maxQuality = 50
val minQuality = 0
}
final case class VideoQuality(value: Int) {
require(value <= maxQuality, s"Video quality value greater than $maxQuality")
require(value >= minQuality, s"Video quality value less than $minQuality")
def increase(): VideoQuality = {
if (value >= maxQuality) this
else copy(value + 1)
}
}
OOP: Data+Behaviour
👤 Domain models > 🎯 OOP > VideoQuality Value Object
object VideoQuality {
val maxQuality = 50
val minQuality = 0
}
final case class VideoQuality(value: Int) {
require(value <= maxQuality, s"Video quality value greater than $maxQuality")
require(value >= minQuality, s"Video quality value less than $minQuality")
def increase(): VideoQuality = {
if (value >= maxQuality) this
else copy(value + 1)
}
}
Behaviour
Simpler API
+ domain semantics
+ immutability
👤 Domain models > 🎯 OOP > VideoQuality Value Object
case class Video(
id: VideoId,
title: VideoTitle,
quality: VideoQuality
) {
def increaseQuality(): Video =
copy(quality = quality.increase())
}
VideoQualityIncreaser Video
increaseQuality()
Behaviour
Rich domain model - Tell don’t ask
👤 Domain models > 🎯 OOP > Video Entity
public final class Video {
private VideoId id;
private VideoQuality quality;
// …
public VideoQuality getQuality() {
return quality;
}
public void setQuality(
VideoQuality quality
) {
this.quality = quality;
}
}
VideoQualityIncreaser Video
getQuality()
increaseQuality()
setQuality()
Behaviour
👤 Domain models > 🎯 OOP > Video Entity
setQuality()
getQuality()
increaseQuality()
…Increaser Video
Behaviour
…Increaser Video
Behaviour
👤 Domain models > 🎯 OOP > Video Entity
increaseQuality()
🦄 Functional Programming
👤 Domain models
…Increaser Video
Behaviour
👤 Domain models > 🦄 FP > Video Entity
increaseQuality()
…Increaser
increaseQuality()
Behaviour Video
…
def increaser[V: VideoBehaviour](
video: V): V =
video.increaseQuality()
Increaser
increaseQuality()
LOGIC
VideoBehaviour
Rich domain layer - Tell don’t ask
Do not expose quality property
👤 Domain models > 🦄 FP > Video EntityTYPE CLASSES: API
trait VideoBehaviour[T]{
val maxQuality: Int
val minQuality: Int
def increaseQuality(thing: T): T
}
+Less coupling!
PlainVideo
👤 Domain models > 🦄 FP > Video Entitycase class PlainVideo(
id: VideoId,
title: VideoTitle,
quality: VideoQuality
)
copy(quality=…)
quality
increase
:VideoImpl
VideoBeh
INSTANTIATION
implicit object VideoImpl
extends VideoBehaviour[PlainVideo]{
val maxQuality = 100
val minQuality = 10
def increaseQuality(video: PlainVideo) =
video.copy(quality =
video.quality.increase)
}
Video
Behaviour
👤 Domain models > 🦄 FP > Video Entitycase class Video(
id: VideoId,
title: VideoTitle,
quality: VideoQuality){
def increaseQuality(): Video =
copy(quality = quality.increase())
}
increaseQuality()
:VideoImpl
implicit object VideoImpl
extends VideoBehaviour[Video]{
val maxQuality = Video.maxQuality
def increaseQuality(video: Video) =
video.increaseQuality
}
VideoBeh
INSTANTIATION
👤 Domain models > 🦄 FP > Video Entity
COMPOSITION
def plainVideoIncreaser(video: PlainVideo): PlainVideo =
increaser[PlainVideo](video)
def videoIncreaser(video: Video): Video =
increaser[Video](video)
🤔 Rethinking time
👤 Domain models
& Implementation > 👤 Domain models > 🤔 Rethinking time
Differences on Domain Modelling goals
• 🦄 FP Type classes: APIs with steroids
• Goal: Coupling to behaviours (not to state)
• Decouple behaviour and data
• Support rich domain layers
• 🎯 OOP: High cohesion (behaviour close to related data)
• Modularity because abstractions => More indirection levels (complexity)
• Goal: Rich domain models (data+behaviour)
INSTANTIATION
TYPECLASS: API
COMPOSITION
LOGIC
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
🎯 Hexagonal Architecture
🏗 Layers implementations
final class VideoPostController(creator: VideoCreator) {
def post(id: String, title: String): StandardRoute = {
creator.create(VideoId(id), VideoTitle(title))
complete(HttpResponse(Created))
}
}
VideoPostController - HTTP API Controller
VideoPostController
final class VideoPostController(creator: VideoCreator) {
def post(id: String, title: String): StandardRoute = {
creator.create(VideoId(id), VideoTitle(title))
complete(HttpResponse(Created))
}
}
VideoPostController - HTTP API Controller
VideoPostController
final class VideoCreator(
repository: VideoRepository,
publisher: MessagePublisher
) {
def create(id: VideoId, title: VideoTitle): Unit = {
val video = Video(id, title)
repository.save(video)
publisher.publish(VideoCreated(video))
}
}
VideoCreator - Application Service/Use case
VideoPostController VideoCreator
final class VideoCreator(
repository: VideoRepository,
publisher: MessagePublisher
) {
def create(id: VideoId, title: VideoTitle): Unit = {
val video = Video(id, title)
repository.save(video)
publisher.publish(VideoCreated(video))
}
}
VideoCreator - Application Service/Use case
VideoPostController VideoCreator
trait VideoRepository {
def all(): Future[Seq[Video]]
def save(video: Video): Future[Unit]
}
VideoRepository - Domain contract/Port
VideoPostController VideoRepositoryVideoCreator
DoobieMySqlVideoRepository - Infrastructure implementation/Adapter
VideoPostController VideoRepositoryVideoCreator
DoobieMySqlVideoRepo
final class DoobieMySqlVideoRepository(db: DoobieDbConnection)
(implicit ec: ExecutionContext) extends VideoRepository {
override def all(): Future[Seq[Video]] =
db.read(sql”SELECT…”.query[Video].to[Seq])
override def save(video: Video): Future[Unit] =
sql"INSERT INTO…”.update.run
.transact(db.transactor)
.unsafeToFuture().map(_ => ())
}
🦄 Functional Architectures
🏗 Layers implementations
trait VideoRepository {
def all(): Future[Seq[Video]]
def save(video: Video):
Future[Unit]
}
Domain contract/PortVideoRepository
?
trait VideoRepository {
def all(): cats.IO[Seq[Video]]
def save(video: Video):
cats.IO[Unit]
}
trait VideoRepository {
def all(): Seq[Video]
def save(video: Video): Unit
}
trait VideoRepository {
def all(): Seq[Video]
def save(video: Video): Unit
}
trait VideoRepository {
def all(): Future[Seq[Video]]
def save(video: Video):
Future[Unit]
}
trait VideoRepository {
def all(): cats.IO[Seq[Video]]
def save(video: Video):
cats.IO[Unit]
}
Domain contract/Port
infrastructure leaks
VideoRepository
?
trait VideoRepository[P[_]] {
def all(): P[Seq[Video]]
def save(video: Video): P[Unit]
}
TYPE (CONSTRUCTOR) CLASSES
VideoRepository
?
Domain contract/Port
Infrastructure implementation/Adapter
import scala.concurent.Future
final class DoobieMySqlVideoRepoFuture(
db: DoobieDbConnection[Future])(implicit
ec: ExecutionContext) extends VideoRepository[Future] {
override def all(): Future[Seq[Video]] =
db.read(sql"SELECT ...".query[Video].to[Seq])
override def save(video: Video): Future[Unit] =
sql"INSERT INTO ... ".update.run
.transact(db.transactor)
.map(_ => ())
}
VideoRepository
DoobieVideoRepoFuture
INSTANTIATION
Infrastructure implementation/Adapter
import scala.concurent.Future
final class DoobieMySqlVideoRepoFuture(
db: DoobieDbConnection[Future])(implicit
ec: ExecutionContext) extends VideoRepository[Future] {
override def all(): Future[Seq[Video]] =
db.read(sql"SELECT ...".query[Video].to[Seq])
override def save(video: Video): Future[Unit] =
sql"INSERT INTO ... ".update.run
.transact(db.transactor)
.map(_ => ())
}
VideoRepository
DoobieVideoRepoFuture
INSTANTIATION
Infrastructure implementation/AdapterVideoRepository
DoobieVideoRepoIO
import cats.effect.IO
final class DoobieMySqlVideoRepoIO(
db: DoobieDbConnection[IO]) extends VideoRepository[IO] {
override def all(): IO[Seq[Video]] =
db.read(sql"SELECT ...".query[Video].to[Seq])
override def save(video: Video): IO[Unit] =
sql"INSERT INTO ... ".update.run
.transact(db.transactor)
.map(_ => ())
}
INSTANTIATION
Infrastructure implementation/AdapterVideoRepository
DoobieVideoRepoIO
import cats.effect.IO
final class DoobieMySqlVideoRepoIO(
db: DoobieDbConnection[IO]) extends VideoRepository[IO] {
override def all(): IO[Seq[Video]] =
db.read(sql"SELECT ...".query[Video].to[Seq])
override def save(video: Video): IO[Unit] =
sql"INSERT INTO ... ".update.run
.transact(db.transactor)
.map(_ => ())
}
INSTANTIATION
Infrastructure implementation/AdapterVideoRepository
DoobieVideoRepo (GENERIC) INSTANTIATION
final case class DoobieMySqlVideoRepo[P[_]: Monad]()(
db: DoobieDbConnection[P]) extends VideoRepository[P] {
override def all(): P[Seq[Video]] =
db.read(sql"SELECT …”.query[Video].to[Seq])
override def save(video: Video): P[Unit] =
sql"INSERT …”.update.run
.transact(db.transactor)
.map(_ => ())
}
Infrastructure implementation/AdapterVideoRepository
DoobieVideoRepo (GENERIC) INSTANTIATION
final case class DoobieMySqlVideoRepo[P[_]: Monad]()(
db: DoobieDbConnection[P]) extends VideoRepository[P] {
override def all(): P[Seq[Video]] =
db.read(sql"SELECT …”.query[Video].to[Seq])
override def save(video: Video): P[Unit] =
sql"INSERT …”.update.run
.transact(db.transactor)
.map(_ => ())
}
🤔 Rethinking time
🏗 Layers implementations
Differences on layers implementation
• Same goal: Decouple from infrastructure
• 🦄 FP:
• One step forward to avoid infrastructure leaks
• Again, through type classes: a better API
• More complexity: monads, applicatives, etc.
& Implementation > 🏗 Layers > 🤔 Rethinking time
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
👤
Domain
models
Contents
🗺Design principles
&Implementation details
🦄
Functional
Architectures
🎯
Hexagonal
Architecture
🏗
Layers
implementation
Functional Programming intro based on Hexagonal Architecture
⚡
Error
Handling
🎯 OOP
⚡Error Handling
object VideoQuality {
val maxQuality = 50
val minQuality = 0
}
final case class VideoQuality(value: Int) {
require(value <= maxQuality, s"Video quality value greater than $maxQuality")
require(value >= minQuality, s"Video quality value less than $minQuality")
def increase(): VideoQuality = {
if (value >= maxQuality) this
else copy(value + 1)
}
}
VO: Raise exceptions
for invalid states
⚡Error Handling > 🎯 OOP > Raise exceptions
final class VideoFinder(repository: VideoRepository)
(implicit ec: ExecutionContext) {
def find(id: VideoId): Future[Video] =
repository.search(id).map { videoOption =>
if (videoOption.isEmpty) throw VideoNotFound(id)
else videoOption.get
}
}
Imperativeness
⚡Error Handling > 🎯 OOP > Raise exceptions
trait VideoRepository {
def search(id: VideoId): Future[Option[Video]]
}
final class VideoGetController extends ApiController
{
protected function exceptions(): array
{
return [
VideoNotFound::class => Response::HTTP_NOT_FOUND,
];
}
// …
}
HTTP Mapping
⚡Error Handling > 🎯 OOP > Handle exceptions
🦄 Functional Architectures
⚡Error Handling
Imperativeness
⚡Error Handling > 🦄 FP > Raise errors
Declarativeness
+
final case class VideoFinderRepo[P[_]]()(
implicit repository: VideoRepository[P]
) extends VideoFinder[P] {
def find(id: VideoId)(implicit
E: MonadError[P, VideoFinderError]): P[Video] =
repository.search(id) flatMap { maybeVideo =>
maybeVideo.fold(E.raiseError[Video](VideoNotFound(id))){
video => video.pure[P]
}
}
}
⚡Error Handling > 🦄 FP > Raise errors
final case class VideoFinderRepo[P[_]]()(
implicit repository: VideoRepository[P]
) extends VideoFinder[P] {
def find(id: VideoId)(implicit
E: MonadError[P, VideoFinderError]): P[Video] =
repository.search(id) flatMap { maybeVideo =>
maybeVideo.fold(E.raiseError[Video](VideoNotFound(id))){
video => video.pure[P]
}
}
}
A functional signature doesn’t hide anything!
⚡Error Handling > 🦄 FP > Raise errors
TYPE CLASSES
trait MonadError[F[_], E] {
def raiseError[A](e: E): F[A]
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]
}
⚡Error Handling > 🦄 FP > Raise errors
final case class VideoFinderRepo[P[_]: Monad]()(
implicit repository: VideoRepository[P]
) extends VideoFinder[P] {
def find(id: VideoId)(implicit
E: MonadError[P, VideoFinderError]): P[Video] =
repository.search(id) flatMap { maybeVideo =>
maybeVideo.fold(E.raiseError[Video](VideoNotFound(id))){
video => video.pure[P]
}
}
}
⚡Error Handling > 🦄 FP > Raise errors
final case class VideoFinderRepo[P[_]: Monad]()(
implicit repository: VideoRepository[P]
) extends VideoFinder[P] {
def find(id: VideoId)(implicit
E: MonadError[P, VideoFinderError]): P[Video] =
repository.search(id) flatMap { maybeVideo =>
maybeVideo.fold(E.raiseError[Video](VideoNotFound(id))){
video => video.pure[P]
}
}
}
Imperativeness
⚡Error Handling > 🦄 FP > Raise errors
final case class VideoFinderRepo[P[_]: Monad]()(
implicit repository: VideoRepository[P]
) extends VideoFinder[P] {
def find(id: VideoId)(implicit
E: MonadError[P, VideoFinderError]): P[Video] =
val maybeVideo = repository.search(id) ;
if (videoOption.isEmpty) throw VideoNotFound(id)
else videoOption.get
}
Monadic programming is
imperative programming with steroids!
object FutureBasedController{
case class VideoController(
videoFinder: VideoFinder[Future]
)(implicit ec: ExecutionContext) extends Http4sDsl[Future] {
val service = HttpService[Future] {
case GET -> Root / "videos" / id =>
videoFinder.find(VideoId(id)) flatMap {
case video =>
Ok(video.asJson)
} recoverWith {
case error: VideoNotFound =>
NotFound(error.asJson)
}
}
}
}
⚡Error Handling > 🦄 FP > Raise errors
Future-based
HTTP Mapping
LOGIC
case class VideoController[P[_]: Effect](
videoFinder: VideoFinder[P]
) extends Http4sDsl[P] {
val service = HttpService[P] {
case GET -> Root / "videos" / id =>
videoFinder.find(VideoId(id)) flatMap {
case video =>
Ok(video.asJson)
} handleErrorWith {
case error: VideoNotFound =>
NotFound(error.asJson)
}
}
}
⚡Error Handling > 🦄 FP > Raise errors
Generic
HTTP Mapping
MonadError
API
LOGIC
🤔 Rethinking time
⚡Error Handling
Differences on Error handling
• 🦄 FP:
• FP tell no lies (or, rather, doesn’t hide anything): more robust contracts using
type system
• Declarative: more abstract about how the error will be raised (exceptions,
Option, Either, etc)
& Implementation > ⚡Error Handling > 🤔 Rethinking time
🍕Takeaways
🎯
🦄
VideoPostController
VideoRepository
VideoCreator
DoobieMySqlVideoRepo
VideoPostController
VideoRepositoryVideoRepoC
DoobieMySqlVideoRepo
VideoCreator
HTTP
🍕Takeaways
⚡ Exceptions
🏗 Monolithic interfaces
👤 Rich domain models
🍕Takeaways
⚡ Exceptions
🏗 Monolithic interfaces
👤 Rich domain models
🦄 TypeClasses
⚛ APIs with steroids
🧐 FP as a subsuming paradigm
ℹ More info
References
ℹ More info
👉Formación FP presencial 👈
hablapps.com
👉Cursos en vídeo online 👈
codely.tv/pro/cursos

Más contenido relacionado

La actualidad más candente

DBA Fundamentals Group: Continuous SQL with Kafka and Flink
DBA Fundamentals Group: Continuous SQL with Kafka and FlinkDBA Fundamentals Group: Continuous SQL with Kafka and Flink
DBA Fundamentals Group: Continuous SQL with Kafka and Flink
Timothy Spann
 

La actualidad más candente (20)

TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
AWS DevOps - Terraform, Docker, HashiCorp Vault
AWS DevOps - Terraform, Docker, HashiCorp VaultAWS DevOps - Terraform, Docker, HashiCorp Vault
AWS DevOps - Terraform, Docker, HashiCorp Vault
 
DBA Fundamentals Group: Continuous SQL with Kafka and Flink
DBA Fundamentals Group: Continuous SQL with Kafka and FlinkDBA Fundamentals Group: Continuous SQL with Kafka and Flink
DBA Fundamentals Group: Continuous SQL with Kafka and Flink
 
Domain-Driven Design with ASP.NET MVC
Domain-Driven Design with ASP.NET MVCDomain-Driven Design with ASP.NET MVC
Domain-Driven Design with ASP.NET MVC
 
TypeScript: coding JavaScript without the pain
TypeScript: coding JavaScript without the painTypeScript: coding JavaScript without the pain
TypeScript: coding JavaScript without the pain
 
Reusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modulesReusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modules
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 
Clean architectures with fast api pycones
Clean architectures with fast api   pyconesClean architectures with fast api   pycones
Clean architectures with fast api pycones
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
 
Spring framework IOC and Dependency Injection
Spring framework  IOC and Dependency InjectionSpring framework  IOC and Dependency Injection
Spring framework IOC and Dependency Injection
 
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition!
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition! Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition!
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition!
 
Introduce to Terraform
Introduce to TerraformIntroduce to Terraform
Introduce to Terraform
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 
Building an Interactive Query Service in Kafka Streams With Bill Bejeck | Cur...
Building an Interactive Query Service in Kafka Streams With Bill Bejeck | Cur...Building an Interactive Query Service in Kafka Streams With Bill Bejeck | Cur...
Building an Interactive Query Service in Kafka Streams With Bill Bejeck | Cur...
 
Introduction to Spring Boot
Introduction to Spring BootIntroduction to Spring Boot
Introduction to Spring Boot
 
Spring data jpa
Spring data jpaSpring data jpa
Spring data jpa
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
Introduction to GitHub Actions
Introduction to GitHub ActionsIntroduction to GitHub Actions
Introduction to GitHub Actions
 

Similar a Towards Functional Programming through Hexagonal Architecture

Similar a Towards Functional Programming through Hexagonal Architecture (20)

Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
 
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
 
Customizing the Presentation Model and Physical Renderer in Siebel Open UI
Customizing the Presentation Model and Physical Renderer in Siebel Open UICustomizing the Presentation Model and Physical Renderer in Siebel Open UI
Customizing the Presentation Model and Physical Renderer in Siebel Open UI
 
Modular Web Applications With Netzke
Modular Web Applications With NetzkeModular Web Applications With Netzke
Modular Web Applications With Netzke
 
Advanced #6 clean architecture
Advanced #6  clean architectureAdvanced #6  clean architecture
Advanced #6 clean architecture
 
Protocol-Oriented Programming in Swift
Protocol-Oriented Programming in SwiftProtocol-Oriented Programming in Swift
Protocol-Oriented Programming in Swift
 
Django Introduction & Tutorial
Django Introduction & TutorialDjango Introduction & Tutorial
Django Introduction & Tutorial
 
Microservices Chaos Testing at Jet
Microservices Chaos Testing at JetMicroservices Chaos Testing at Jet
Microservices Chaos Testing at Jet
 
Awesome html with ujs, jQuery and coffeescript
Awesome html with ujs, jQuery and coffeescriptAwesome html with ujs, jQuery and coffeescript
Awesome html with ujs, jQuery and coffeescript
 
Application Architecture April 2014
Application Architecture April 2014Application Architecture April 2014
Application Architecture April 2014
 
Getting started with Appcelerator Titanium
Getting started with Appcelerator TitaniumGetting started with Appcelerator Titanium
Getting started with Appcelerator Titanium
 
Getting started with titanium
Getting started with titaniumGetting started with titanium
Getting started with titanium
 
AWValuePitch, 7_12
AWValuePitch, 7_12AWValuePitch, 7_12
AWValuePitch, 7_12
 
Application Lifecycle Management in a Serverless World
Application Lifecycle Management in a Serverless WorldApplication Lifecycle Management in a Serverless World
Application Lifecycle Management in a Serverless World
 
“ASP.NET Core. Features and architecture”
“ASP.NET Core. Features and architecture” “ASP.NET Core. Features and architecture”
“ASP.NET Core. Features and architecture”
 
Streaming Tech Sweden 2019 - Serverless Media Processing
Streaming Tech Sweden 2019 - Serverless Media ProcessingStreaming Tech Sweden 2019 - Serverless Media Processing
Streaming Tech Sweden 2019 - Serverless Media Processing
 
Test Driven Development with JavaFX
Test Driven Development with JavaFXTest Driven Development with JavaFX
Test Driven Development with JavaFX
 
When Smalltalk Meets the Web
When Smalltalk Meets the WebWhen Smalltalk Meets the Web
When Smalltalk Meets the Web
 
DDD, CQRS and testing with ASP.Net MVC
DDD, CQRS and testing with ASP.Net MVCDDD, CQRS and testing with ASP.Net MVC
DDD, CQRS and testing with ASP.Net MVC
 
Html5 intro
Html5 introHtml5 intro
Html5 intro
 

Último

Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
Epec Engineered Technologies
 
Digital Communication Essentials: DPCM, DM, and ADM .pptx
Digital Communication Essentials: DPCM, DM, and ADM .pptxDigital Communication Essentials: DPCM, DM, and ADM .pptx
Digital Communication Essentials: DPCM, DM, and ADM .pptx
pritamlangde
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Kandungan 087776558899
 
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
mphochane1998
 
Hospital management system project report.pdf
Hospital management system project report.pdfHospital management system project report.pdf
Hospital management system project report.pdf
Kamal Acharya
 

Último (20)

Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPT
 
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
 
💚Trustworthy Call Girls Pune Call Girls Service Just Call 🍑👄6378878445 🍑👄 Top...
💚Trustworthy Call Girls Pune Call Girls Service Just Call 🍑👄6378878445 🍑👄 Top...💚Trustworthy Call Girls Pune Call Girls Service Just Call 🍑👄6378878445 🍑👄 Top...
💚Trustworthy Call Girls Pune Call Girls Service Just Call 🍑👄6378878445 🍑👄 Top...
 
Design For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the startDesign For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the start
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
 
Moment Distribution Method For Btech Civil
Moment Distribution Method For Btech CivilMoment Distribution Method For Btech Civil
Moment Distribution Method For Btech Civil
 
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptxS1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
 
Digital Communication Essentials: DPCM, DM, and ADM .pptx
Digital Communication Essentials: DPCM, DM, and ADM .pptxDigital Communication Essentials: DPCM, DM, and ADM .pptx
Digital Communication Essentials: DPCM, DM, and ADM .pptx
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
 
A CASE STUDY ON CERAMIC INDUSTRY OF BANGLADESH.pptx
A CASE STUDY ON CERAMIC INDUSTRY OF BANGLADESH.pptxA CASE STUDY ON CERAMIC INDUSTRY OF BANGLADESH.pptx
A CASE STUDY ON CERAMIC INDUSTRY OF BANGLADESH.pptx
 
School management system project Report.pdf
School management system project Report.pdfSchool management system project Report.pdf
School management system project Report.pdf
 
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
 
PE 459 LECTURE 2- natural gas basic concepts and properties
PE 459 LECTURE 2- natural gas basic concepts and propertiesPE 459 LECTURE 2- natural gas basic concepts and properties
PE 459 LECTURE 2- natural gas basic concepts and properties
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
Jaipur ❤CALL GIRL 0000000000❤CALL GIRLS IN Jaipur ESCORT SERVICE❤CALL GIRL IN...
Jaipur ❤CALL GIRL 0000000000❤CALL GIRLS IN Jaipur ESCORT SERVICE❤CALL GIRL IN...Jaipur ❤CALL GIRL 0000000000❤CALL GIRLS IN Jaipur ESCORT SERVICE❤CALL GIRL IN...
Jaipur ❤CALL GIRL 0000000000❤CALL GIRLS IN Jaipur ESCORT SERVICE❤CALL GIRL IN...
 
Hospital management system project report.pdf
Hospital management system project report.pdfHospital management system project report.pdf
Hospital management system project report.pdf
 
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced LoadsFEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
 
Theory of Time 2024 (Universal Theory for Everything)
Theory of Time 2024 (Universal Theory for Everything)Theory of Time 2024 (Universal Theory for Everything)
Theory of Time 2024 (Universal Theory for Everything)
 
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKARHAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
 
Double Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torqueDouble Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torque
 

Towards Functional Programming through Hexagonal Architecture