Brown Bag: Learn the things I'm learning

FP -> DDD -> CA

 

 

August 27, 2020
David Horm
Pronouns: he, him, his
Press 'o' for overview mode
Press 's' for presenter mode

TL;DR

  • Ride-the-Duck Tour
  • Hermit Wisdom?
    or Crazy Talk?
  • Journey with React
  • Functional Programming
  • Domain Driven Design
  • Clean Architecture

Journey

  • Baby
  • Imposter Syndrome
  • Ever-evolving technology
  • Don't Stop Believing

React

Functional Components & Hooks

React Today and Tomorrow and 90% Cleaner React With Hooks

React

  • Functional Components & Hooks
  • useEffect() for Side Effects?
  • useReducer() and Redux uses Immutable objects?
  • useMemo() & Memoized?
  • Ah, using concepts from Functional Programming
## OO Pattern/Principle - Single Responsibility Principle - Open/Closed Principle - Dependency Inversion Principle - Interface Segregation Principle - Factory Pattern - Strategy Pattern - Decorator Pattern - Visitor Pattern

FP Equivalent

  • Functions
  • Functions
  • Functions, also
  • Functions
  • You will be assimilated!
  • Functions again
  • Functions
  • Resistance is futile!
  • Arrow Function Syntax

    
    					function addOne(value) {
    						return value + 1;
    					}
    
    					const addOne = (value) => {
    						return value + 1;
    					};
    
    					const addOne = (oldValue) => { return oldValue + 1; };
    
    					const addOne = (oldValue) => oldValue + 1;
    				

    Make Veggie 🥪: OOP Example

    
    					// ['Loaf of Bread', 'Loaf of Bread', 'Slab Bacon', 'Whole Tomato', 'Head of Lettuce']
    					// => 'The sandwich has: slice of Bread, sliced Tomato, Lettuce leaf, slice of Bread'
    					const makeVeggieSandwich = (ingredients: string[]): string => {
    						let sandwichIngredients = [];
    						for (let i = 0; i < ingredients.length; i++) {
    							if (isVeggieType(ingredients[i])) {
    								const slicedIngredient = getSlicedIngredient(ingredients[i]);
    								sandwichIngredients.push(slicedIngredient);
    							}
    						}
    
    						sortIngredients(sandwichIngredients);
    
    						let sandwich = 'The sandwich has: ';
    						for (let j = 0; j < sandwichIngredients.length; j++) {
    							sandwich += `${sandwichIngredients[j].value}, `;
    						}
    						return sandwich;
    					};
    				

    Make Veggie 🥪: FP Example

    
    					// ['Loaf of Bread', 'Loaf of Bread', 'Slab Bacon', 'Whole Tomato', 'Head of Lettuce']
    					// => 'The sandwich has: slice of Bread, sliced Tomato, Lettuce leaf, slice of Bread'
    					const makeVeggieSandwich = (ingredients: string[]): string => {
    						const sandwich = ingredients
    							.filter(isVeggieType)
    							.map(getSlicedIngredient)
    							.sort(sortIngredients)
    							.reduce(
    								(sandwich, ingredient) => `${sandwich}, ${ingredient.value}`,
    								'The sandwich has: '
    							);
    						
    						return sandwich;
    					};
    				

    Same Input => Same Output

    Mutating data is bad
    
    					let word = 'World';
    					doSomething(word);
    					console.log(`Hello ${word}`); // 'Hello World'?
    				

    Same Input => Same Output

    Mutating data is bad
    
    					let word = 'World';
    					const doSomething = (word) => {
    						a(word); b(word); c(word); d(word); e(word); f(word);
    					};
    					doSomething(word);
    					console.log(`Hello ${word}`); // 'Hello F-Word'?!
    				

    Same Input => Same Output

    Hidden input data is bad
    
    					// impure
    					let minimum = 21;
    					const checkAge = (age) => age >= minimum;
    
    					// pure
    					const checkAge = (age) => {
    						const minimum = 21;
    						return age >= minimum;
    					};
    
    					// pure with currying
    					const checkAge = (age) => (minimum) => age >= minimum;
    					const isOfAge = checkAge(36)(18);
    				

    OOP Error Handling

    
    					// 1 => "Luke Skywalker"
    					const getCharacterName = (id: number): string => {
    						fetch(`https://swapi.dev/api/people/${id}/`)
    						.then((response) => { 
    							if (!response.ok) {
    								throw new Error('HTTP error')
    							}
    
    							response.json()
    							.then((character) => {
    								if (!character) {
    									throw new Error('no character object');
    								}
    	
    								if (!character.name) {
    									throw new Error('No name property');
    								}
    	
    								return character.name;
    							});
    						})
    						.catch((error) => {
    							throw new Error(`Fetch Error: ${error}`);
    						});
    					};
    				

    FP Error Handling

    FP: Additional Resources

    Domain Driven Design

    Ubiquitous Language
    
    					module CardGame =
    						type Suit = Club | Diamond | Spade | Heart
    						type Rank = Two | Three | Four | Five | ...
    						type Card = Suit * Rank
    						type Hand = Card list
    						type Deck = Card list
    
    						type Deal = Deck -> (Deck * Card)
    				

    Domain Driven Design

    Ubiquitous Language
    
    					module CardGame =
    						type Suit = Club | Diamond | Spade | Heart
    						type Rank = Two | Three | Four | Five | ...
    						type Card = Suit * Rank
    						type Hand = Card list
    						type Deck = Card list
    
    						type ShuffledDeck = Card list
    						type Shuffle = Deck -> ShuffledDeck
    						type Deal = ShuffledDeck -> (ShuffledDeck * Card)
    				

    Domain Driven Design

    Make illegal state impossible to represent
    
    					type Contact = {
    						FirstName: string
    						MiddleInitial: string
    						LastName: string
    
    						EmailAddress: string
    						IsEmailVerified: bool
    					}
    				

    Domain Driven Design

    Make illegal state impossible to represent
    
    					type PersonName = {
    						FirstName: String50
    						MiddleInitial: String1 option
    						LastName: String50
    					}
    
    					type EmailContactInfo = {
    						EmailAddress: EmailAddress
    						IsEmailVerified: bool
    					}
    
    					type Contact = {
    						Name: PersonName
    						Email: EmailContactInfo
    					}
    				

    Domain Driven Design

    Make illegal state impossible to represent
    
    					type PersonName = {
    						FirstName: String50
    						MiddleInitial: String1 option
    						LastName: String50
    					}
    
    					type VerifiedEmail = VerifiedEmail of EmailAddress
    
    					type VerificationService = (EmailAddress * VerificationHash) -> VerifiedEmail
    
    					type EmailContactInfo = 
    						| Unverified of EmailAddress
    						| Verified of VerifiedEmail
    					
    					type Contact = {
    						Name: PersonName
    						Email: EmailContactInfo
    					}
    				

    DDD: Additional Resources

    Clean Architecture Influences

    UI
    Business
    Data
    UI
    Business
    Data
    UI
    Business
    Data
    UI
    Domain:
    Use Cases

    Entities
    Data
    Framework:
    React
    Adapter:
    MVC
    Domain:
    Use Cases

    Entities
    Data
    Framework:
    React
    Adapter:
    MVC
    Domain:
    Use Cases

    Entities
    Adapter:
    REST API
    Framework:
    SQL
    Framework:
    Public Website

    Framework:
    Internal App
    Adapter:
    MVC
    Domain:
    Use Cases

    Entities
    Adapter:
    Public API

    Adapter:
    Internal API
    Framework:
    SQL
    Clean Architecture
    by "Uncle Bob" Martin

    Benefits:
    • Independent of Frameworks
    • Testable
    • Independent of UI
    • Independent of Database
    • Independent of any external agency