Architecture using Functional Programming concepts < + >

Similar documents
Kotlin for the Pragmatic Functionalist

ARCHETYPE MODERN ANDROID ARCHITECTURE STEPAN GONCHAROV / DENIS NEKLIUDOV

in Microservices using DDD, Event Sourcing & CQRS Augusto Branquinho Mike Shigueru Matsumoto

Writing Reactive Application using Angular/RxJS, Spring WebFlux and Couchbase. Naresh Chintalcheru

Programming Kotlin. Familiarize yourself with all of Kotlin s features with this in-depth guide. Stephen Samuel Stefan Bocutiu BIRMINGHAM - MUMBAI

Introduction to Coroutines. Roman Elizarov elizarov at JetBrains

JVM ByteCode Interpreter

Concurrent ML. John Reppy January 21, University of Chicago

Background Type Classes (1B) Young Won Lim 6/28/18

Maybe Monad (3B) Young Won Lim 12/21/17

Asynchronous Computations

Fresh Async With Kotlin. Presented at QCon SF, 2017 /Roman JetBrains

UI-Testing, Reactive Programming and some Kotlin.

CMSC 330: Organization of Programming Languages. Operational Semantics

Spring MVC 4.x Spring 5 Web Reactive

Programs as Values Pure Functional Database Access in Scala

Refactoring to Functional. Hadi Hariri

INF 102 CONCEPTS OF PROG. LANGS FUNCTIONAL COMPOSITION. Instructors: James Jones Copyright Instructors.

Introduction to Programming Using Java (98-388)

INF 212 ANALYSIS OF PROG. LANGS FUNCTION COMPOSITION. Instructors: Crista Lopes Copyright Instructors.

The Myx Architectural Style

DHANALAKSHMI SRINIVASAN COLLEGE OF ENGINEERING AND TECHNOLOGY ACADEMIC YEAR (ODD SEM)

Semantic Analysis. Lecture 9. February 7, 2018

S.No Question Blooms Level Course Outcome UNIT I. Programming Language Syntax and semantics

Implementing Recursion

2 years without Java or reload Android development with Kotlin.

Today: Distributed Objects. Distributed Objects

Reaktive Anwendungen mit RxJava. Dr. Michael Menzel

Outline. Introduction Concepts and terminology The case for static typing. Implementing a static type system Basic typing relations Adding context

Die funktionale Zukunft

Futures. Prof. Clarkson Fall Today s music: It's Gonna be Me by *NSYNC

A Long Time Ago 2 / 64

Monads. Prof. Clarkson Fall Today s music: Vámanos Pal Monte by Eddie Palmieri

libcppa Now: High-Level Distributed Programming Without Sacrificing Performance

Tail Calls. CMSC 330: Organization of Programming Languages. Tail Recursion. Tail Recursion (cont d) Names and Binding. Tail Recursion (cont d)

Object-Oriented Concepts and Design Principles

Reactive Programming in Java. Copyright - Syncogni Consulting Pvt Ltd. All rights reserved.

Announcements. My office hours are today in Gates 160 from 1PM-3PM. Programming Project 3 checkpoint due tomorrow night at 11:59PM.

Preface to the Second Edition Preface to the First Edition Brief Contents Introduction to C++ p. 1 A Review of Structures p.

Maybe Monad (3B) Young Won Lim 1/3/18

Designing for Modularity with Java 9

Monad (1A) Young Won Lim 6/26/17

Writing truly testable code. Anton Rutkevich Juno

.NET Advance Package Syllabus

Monad (3A) Young Won Lim 8/9/17

15CS45 : OBJECT ORIENTED CONCEPTS

AP COMPUTER SCIENCE JAVA CONCEPTS IV: RESERVED WORDS

Written Presentation: JoCaml, a Language for Concurrent Distributed and Mobile Programming

Control Structures. Christopher Simpkins CS 3693, Fall Chris Simpkins (Georgia Tech) CS 3693 Scala / 1

CPL 2016, week 6. Asynchronous execution. Oleg Batrashev. March 14, Institute of Computer Science, Tartu, Estonia

Compiler Construction Lent Term 2015 Lectures 10, 11 (of 16)

MANAGING ASYNCHRONY. An Application Perspective

CS558 Programming Languages

Some Advanced ML Features

CS4215 Programming Language Implementation. Martin Henz

Mostly functional programming does not work

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

Heresies and Dogmas in Software Development

Lecture 5: Declarative Programming. The Declarative Kernel Language Machine. September 12th, 2011

The Rise and Rise of Dataflow in the JavaVerse

Engineering Abstractions in Model Checking and Testing. Michael Achenbach Klaus Ostermann

The Reactive Landscape Clement Escoffier, Vert.x Core Developer, Red Hat

DOT NET Syllabus (6 Months)

Programming Languages Third Edition. Chapter 7 Basic Semantics

Programming in C# Course: Course Details ABOUT THIS COURSE AUDIENCE PROFILE. Síguenos en:

List ADT. Announcements. The List interface. Implementing the List ADT

Course Hours

Functional Programming in Java. CSE 219 Department of Computer Science, Stony Brook University

Relation Overriding. Syntax and Semantics. Simple Semantic Domains. Operational Semantics

Introduce C# as Object Oriented programming language. Explain, tokens,

The Environment Model. Nate Foster Spring 2018

Heresies and Dogmas in Software

Why Macros? Scheme-Style Macros: Patterns and Lexical Scope. Macros versus Arbitrary Program Generators. Macros versus Arbitrary Program Generators

State, Object-Oriented Programming Explicit State, Polymorphism (CTM ) Objects, Classes, and Inheritance (CTM )

JavaScript: Sort of a Big Deal,

Inheritance STL. Entity Component Systems. Scene Graphs. Event Systems

Reactive programming: origins & ecosystem. Jonas Chapuis, Ph.D.

Design Patterns. Dr. Rania Khairy. Software Engineering and Development Tool

CSE 70 Final Exam Fall 2009

CPS 506 Comparative Programming Languages. Programming Language

Today: Distributed Middleware. Middleware

JAVA MOCK TEST JAVA MOCK TEST III

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

Reactive Programming with Vert.x

Modern C++ Old Dog, New Tricks Todd L.

OpenACC 2.6 Proposed Features

CS201 - Introduction to Programming Glossary By

Anatomy of a Compiler. Overview of Semantic Analysis. The Compiler So Far. Why a Separate Semantic Analysis?

Absolute C++ Walter Savitch

Modules Matter Most. Robert Harper Carnegie Mellon University. MacQueen Fest Chicago May 2012

Background Type Classes (1B) Young Won Lim 6/14/18

Subclass Gist Example: Chess Super Keyword Shadowing Overriding Why? L10 - Polymorphism and Abstract Classes The Four Principles of Object Oriented

Think of drawing/diagramming editors. ECE450 Software Engineering II. The problem. The Composite pattern

Domain Specific Languages - a user view and an implementation view. does expressiveness imply a compromise on the underlying domain model?

Compaq Interview Questions And Answers

Reactive Programming in Java. Copyright - Syncogni Consulting Pvt Ltd. All rights reserved.

New Programming Paradigms

Weiss Chapter 1 terminology (parenthesized numbers are page numbers)

Introduction to Visual Basic and Visual C++ Introduction to Java. JDK Editions. Overview. Lesson 13. Overview

News and remarks. CS68 Principles of Programming Languages. Contents today. Concurrency. Declarative concurrency. Threads

Transcription:

Architecture using Functional Programming concepts < + > Jorge Castillo @JorgeCastilloPr 1

2 Kotlin and Functional Programming FP means concern separation (declarative computations vs runtime execution), purity, referential transparency, push state aside Many features are also found on FP languages. Kotlin still lacks important FP features (HKs, typeclasses )

3 kategory.io Functional datatypes and abstractions over Kotlin Inspired by typelevel/cats, Scalaz Open for public contribution

4 Let s use it to solve some key problems for many systems Modeling error and success cases Asynchronous code + Threading Side Effects Dependency Injection Testing

Error / Success cases 5

6 Return type cannot reflect what you get in return Vanilla Java approach: Exceptions + callbacks public class GetHeroesUseCase { public GetHeroesUseCase(HeroesDataSource datasource, Logger logger) { /* */ public void get(int page, Callback<List<SuperHero>> callback) { try { List<SuperHero> heroes = datasource.getheroes(page); callback.onsuccess(heroes); catch (IOException e) { logger.log(e); callback.onerror("some error"); Catch + callback to surpass thread limits Breaks referential transparency: Error type?

Alternative 1: Result wrapper (Error + Success) 7 public Result(ErrorType error, SuccessType success) { this.error = error; this.success = success; public enum Error { NETWORK_ERROR, NOT_FOUND_ERROR, UNKNOWN_ERROR public class GetHeroesUseCase { Wrapper type /*...*/ public Result<Error, List<SuperHero>> get(int page) { Result<Error, List<SuperHero>> result = datasource.getheroes(page); if (result.iserror()) { logger.log(result.geterror()); return result; We are obviously tricking here. We are ignoring async, but at least we have a very explicit return type.

Alternative 2: RxJava 8 public class GetHeroesUseCaseRx { public Single<List<SuperHero>> get() { return datasource.getheroes().map(this::discardnonvalidheroes).doonerror(logger::log); Threading is easily handled using Schedulers Both result sides (error / success) fit on a single stream private List<SuperHero> discardnonvalidheroes(list<superhero> superheroes) { return superheroes; public class HeroesNetworkDataSourceRx { public Single<List<SuperHero>> getheroes() { return Single.create(emitter -> { List<SuperHero> heroes = fetchsuperheroes(); if (everythingisalright()) { emitter.onsuccess(heroes); else if (heroesnotfound()) { emitter.onerror(new RxErrors.NotFoundError()); else { emitter.onerror(new RxErrors.UnknownError()); );

9 Alternative 3: Either<Error, Success> sealed class CharacterError { object AuthenticationError : CharacterError() object NotFoundError : CharacterError() object UnknownServerError : CharacterError() Sealed hierarchy of supported domain errors /* data source impl */ fun getallheroes(service: HeroesService): Either<CharacterError, List<SuperHero>> = try { Right(service.getCharacters().map { SuperHero(it.id, it.name, it.thumbnailurl, it.description) ) catch (e: MarvelAuthApiException) { Left(AuthenticationError) catch (e: MarvelApiException) { if (e.httpcode == HttpURLConnection.HTTP_NOT_FOUND) { Transform Left(NotFoundError) else { on expected domain errors Left(UnknownServerError) on the side outer layer exceptions fun getheroesusecase(datasource: HeroesDataSource, logger: Logger): Either<Error, List<SuperHero>> = datasource.getallheroes().fold( { logger.log(it); Left(it), We fold() over the Either for effects depending { Right(it) )

10 Alternative 3: Either<Error, Success> Presentation code could look like this: fun getsuperheroes(view: SuperHeroesListView, logger: Logger, datasource: HeroesDataSource) { getheroesusecase(datasource, logger).fold( { error -> drawerror(error, view), { heroes -> drawheroes(heroes, view) ) private fun drawerror(error: CharacterError, view: HeroesView) { when (error) { is NotFoundError -> view.shownotfounderror() is UnknownServerError -> view.showgenericerror() is AuthenticationError -> view.showauthenticationerror() private fun drawheroes(success: List<SuperHero>, view: SuperHeroesListView) { view.drawheroes(success.map { RenderableHero( it.name, it.thumbnailurl) ) But still, what about Async + Threading?!

Asynchronous code + Threading 11

12 Alternatives Vanilla Java: ThreadPoolExecutor + exceptions + callbacks. RxJava: Schedulers + observable + error subscription. KATEGORY: IO to wrap the IO computations and make them pure. Make the computation explicit in the return type

13 IO<Either<CharacterError, List<SuperHero>>> IO wraps a computation that can return either a CharacterError or a List<SuperHero>, never both. /* network data source */ fun getallheroes(service: HeroesService, logger: Logger): IO<Either<CharacterError, List<SuperHero>>> = runinasynccontext( f = { queryforheroes(service), onerror = { logger.log(it); it.tocharactererror().left(), onsuccess = { mapheroes(it).right(), Very explicit result type AC = IO.asyncContext() ) We run the task in an async context using kotlinx coroutines. It returns an IO wrapped computation.

14 IO<Either<CharacterError, List<SuperHero>>> /* Use case */ fun getheroesusecase(service: HeroesService, logger: Logger): IO<Either<CharacterError, List<SuperHero>>> = getallheroesdatasource(service, logger).map { it.map { discardnonvalidheroes(it) /* Presentation logic */ fun getsuperheroes(view: SuperHeroesListView, service: HeroesService, logger: Logger) = getheroesusecase(service, logger).unsaferunasync { it.map { maybeheroes -> maybeheroes.fold( { error -> drawerror(error, view), { success -> drawheroes(success, view) ) Effects are being applied here, but that s not ideal!

15 Problem Ideally, we would perform unsafe effects on the edge of the system, where our frameworks are coupled. On a system with a frontend layer, it would be the view impl. Solutions Lazy evaluation. Defer all the things! Declare the whole execution tree based on returning functions

16 By returning functions at all levels, you swap proactive evaluation with deferred execution. presenter(deps) = { deps -> usecase(deps) usecase(deps) = { deps -> datasource(deps) datasource(deps) = { deps -> deps.apiclient.getheroes() But passing dependencies all the way down at every execution level can be painful. Can t we implicitly inject / pass them in a simple way to avoid passing them manually?

Dependency Injection / passing 17

18 Discovering the Reader Monad Wraps a computation with type (D) -> A and enables composition over computations with that type. D stands for the Reader context (dependencies) Its operations implicitly pass in the context to the next execution level. Think about the context as the dependencies needed to run the complete function tree. (dependency graph)

19 Discovering the Reader Monad It solves both concerns: Defers computations at all levels. Injects dependencies by automatically passing them across the different function calls.

20 Reader<D, IO<Either<CharacterError, List<SuperHero>>>> We start to die on types a bit here. We ll find a solution for it! /* data source could look like this */ fun getheroes(): Reader<GetHeroesContext, IO<Either<CharacterError, List<SuperHero>>>> = Reader.ask<GetHeroesContext>().map({ ctx -> runinasynccontext( f = { ctx.apiclient.getheroes(), onerror = { it.tocharactererror().left(), onsuccess = { it.right(), AC = ctx.threading ) ) Explicit dependencies not needed anymore Reader.ask() lifts a Reader { D -> D so we get access to D when mapping

21 Reader<D, IO<Either<CharacterError, List<SuperHero>>>> /* use case */ fun getheroesusecase() = fetchallheroes().map { io -> io.map { maybeheroes -> maybeheroes.map { discardnonvalidheroes(it) /* presenter code */ fun getsuperheroes() = Reader.ask<GetHeroesContext>().flatMap( { (_, view: SuperHeroesListView) -> Context deconstruction getheroesusecase().map({ io -> io.unsaferunasync { it.map { maybeheroes -> maybeheroes.fold( { error -> drawerror(error, view), { success -> drawheroes(view, success) ) ) )

22 Reader<D, IO<Either<CharacterError, List<SuperHero>>>> Complete computation tree deferred thanks to Reader. Thats a completely pure computation since effects are still not run. When the moment for performing effects comes, you can simply run it passing the context you want to use: /* we perform unsafe effects on view impl now */ override fun onresume() { /* presenter call */ Returns a Reader (deferred computation) getsuperheroes().run(heroescontext) On testing scenarios, you just need to pass a different context which can be providing fake dependencies for the ones we need to mock.

23 How to improve the nested types hell? Monads do not compose gracefully. Functional developers use Monad Transformers to solve this. Monad Transformers wrap monads to gift those with other monad capabilities.

24 How to improve the nested types hell? We want to achieve ReaderT<EitherT<IO>> EitherT (Either Transformer) gives Either capabilities to IO. ReaderT (Reader Transformer) gives Reader capabilities to EitherT<IO> We create an alias for that composed type, for syntax: typealias AsyncResult = ReaderT<EitherT<IO>>

25 AsyncResult<D, A> Takes care of error handling, asynchrony, IO operations, and dependency injection. /* data source */ fun <D : SuperHeroesContext> fetchallheroes(): AsyncResult<D, List<SuperHero>> = AsyncResult.monadError<D>().binding { val query = buildfetchheroesquery() val ctx = AsyncResult.ask<D>().bind() runinasynccontext( f = { fetchheroes(ctx, query), onerror = { lifterror<d>(it), onsuccess = { liftsuccess(it), AC = ctx.threading<d>() ).bind() bindings are part of Monad comprehensions. Code sequential async calls as if they were sync. Monad bindings return an already lifted and flatmapped result to the context of the monad.

26 AsyncResult<D, A> /* use case */ fun <D : SuperHeroesContext> getheroesusecase(): AsyncResult<D, List<CharacterDto>> = fetchallheroes<d>().map { discardnonvalidheroes(it) /* presenter */ fun getsuperheroes(): AsyncResult<GetHeroesContext, Unit> = getheroesusecase<getheroescontext>().map { heroestorenderablemodels(it).flatmap { drawheroes(it).handleerrorwith { displayerrors(it) /* view impl */ override fun onresume() { getsuperheroes().unsafeperformeffects(heroescontext) Again on testing scenarios, you just need to pass a different context which can be providing fake dependencies for the ones we need to mock.

27 Extra bullets Two advanced FP styles can be implemented using Kategory. Tagless-Final Free Monads

28 Tagless-Final Remove concrete monad types from your code (IO, Either, Reader) and depend just on behaviors defined by typeclasses. Run your program later on passing in the implementations you want to use for those behaviors on this execution. tagless-final gradle module on sample repo + PR: github.com/jorgecastilloprz/kotlinandroidfunctional/pull/2

29 Free Monads Separates concerns about declaring the AST (abstract syntax tree) based on Free<S, A> in a pure way, and interpreting it later on using an interpreter. Free is used to decouple dependencies, so it also replaces the need for dependency injection. Remember this when defining the algebras. free-monads gradle module + PR: github.com/ JorgeCastilloPrz/KotlinAndroidFunctional/pull/6

30 Some conclusions The patterns we learned today to solve DI, asynchrony, decoupling etc, are shared with any other FP languages. That helps us to share all the concepts and glossary with frontend and backend devs inside the company. On FP its common to fix problems once and use the same solution for further executions, programs or systems.

31 Samples for every style explained Four grade modules on repo github.com/jorgecastilloprz/ KotlinAndroidFunctional nested-monads (Monad Stack) monad-transformers Tagless-Final Free Monads https://medium.com/@jorgecastillopr/

Thank you! Jorge Castillo @JorgeCastilloPr #kotlinconf17 32