SlideShare a Scribd company logo
You are in a maze of deeply
nested maps, all alike
Eric Normand
IN/Clojure 2019
Symptoms
Symptom:
I can’t remember what keys belong in this map
Symptom:
I don’t even know what kind of entity I have
Symptom:
Working with deeply nested data is awkward
{:date #inst "1984-04-03T13:08:42.020"
:name "Soyuz T-11"
:spacecraft "Soyuz"
:destination "Salyut 7"
:crew [{:name "Yuri Malyshev"
:position "Commander"}
{:name "Gennadi Strekalov"
:position "Flight Engineer"}
{:name "Rakesh Sharma"
:position "Research Cosmonaut"}]}
(mapv (fn [mission]
(update mission :crew
(fn [crews]
(mapv (fn [crew]
(update crew :name
string/upper-case))
crews))))
missions)
(mapv (fn [mission]
(update mission :crew
(fn [crews]
(mapv (fn [crew]
(update crew :name
string/upper-case))
crews))))
missions)
maps
(mapv (fn [mission]
(update mission :crew
(fn [crews]
(mapv (fn [crew]
(update crew :name
string/upper-case))
crews))))
missions)
maps update
(mapv (fn [mission]
(update mission :crew
(fn [crews]
(mapv (fn [crew]
(update crew :name
string/upper-case))
crews))))
missions)
maps update
anonymous
functions
(mapv (fn [mission]
(update mission :crew
(fn [crews]
(mapv (fn [crew]
(update crew :name
string/upper-case))
crews))))
missions)
Symptom:
Long, convoluted functions
Technological Solutions
Spec
Specter
Symptoms Spec Specter
What keys?
Deep nesting
What entity?
✔
✔
✔
Long functions
Symptoms Spec Specter
What keys?
Deep nesting
What entity?
✔
✔
✔
Long functions
Underlying Problem:
You're working at the wrong level of
meaning
It’s just data
{:date #inst "1984-04-03T13:08:42.020"
:name "Soyuz T-11"
:spacecraft "Soyuz"
:destination "Salyut 7"
:crew [{:name "Yuri Malyshev"
:position "Commander"}
{:name "Gennadi Strekalov"
:position "Flight Engineer"}
{:name "Rakesh Sharma"
:position "Research Cosmonaut"}]}
{:date #inst "1984-04-03T13:08:42.020"
:name "Soyuz T-11"
:spacecraft "Soyuz"
:destination "Salyut 7"
:crew [{:name "Yuri Malyshev"
:position "Commander"}
{:name "Gennadi Strekalov"
:position "Flight Engineer"}
{:name "Rakesh Sharma"
:position "Research Cosmonaut"}]}
map
{:date #inst "1984-04-03T13:08:42.020"
:name "Soyuz T-11"
:spacecraft "Soyuz"
:destination "Salyut 7"
:crew [{:name "Yuri Malyshev"
:position "Commander"}
{:name "Gennadi Strekalov"
:position "Flight Engineer"}
{:name "Rakesh Sharma"
:position "Research Cosmonaut"}]}
character
Space travel
Bytes
Characters
Clojure Syntax
Clojure Semantics
Space travel (domain)
Bytes
Characters
Clojure Syntax
Clojure Semantics
Reader
read
eval
your code
Clojure core
Libraries
Domain code
(def user-info (reagent/atom {}))
(defn favorite-color-button [color] ;; reagent component
[:button {:on-click (fn []
(swap! user-info assoc :favorite-color color))
:style {:background-color color}}
color])
(defn favorite-color-panel []
[:div
[:h2 "Favorite color"]
[:h3 "Current: " (:favorite-color @user-info)]
[:h3 "Change it by clicking below"]
[favorite-color-button "green"]
[favorite-color-button "blue"]
[favorite-color-button "red"]])
(def user-info (reagent/atom {}))
(defn favorite-color-button [color] ;; reagent component
[:button {:on-click (fn []
(swap! user-info assoc :favorite-color color))
:style {:background-color color}}
color])
(defn favorite-color-panel []
[:div
[:h2 "Favorite color"]
[:h3 "Current: " (:favorite-color @user-info)]
[:h3 "Change it by clicking below"]
[favorite-color-button "green"]
[favorite-color-button "blue"]
[favorite-color-button "red"]])
user-info
favorite-color-button
assoc :favorite-color
(String)
user-info
favorite-color-button
assoc :favorite-color
(String)
favorite-animal-selector
assoc :favorite-animal
(Keyword)
user-info
favorite-color-button
assoc :favorite-color
(String)
favorite-animal-selector
assoc :favorite-animal
(Keyword)
favorite-fruit-selector
assoc :favorite-fruit
(Keyword)
marital-status-indicator
assoc :marital-status
(Keyword)
elementary-school-chooser
assoc :elementary-school
(Integer)
user-info
favorite-color-button
assoc :favorite-color
(String)
favorite-animal-selector
assoc :favorite-animal
(Keyword)
favorite-fruit-selector
assoc :favorite-fruit
(Keyword)
Clojure core
Libraries
Domain code
your head is up here
Clojure core
Libraries
Domain code
your head is up here
your code is down here
(assoc user-info :favorite-color color)
Clojure core and libraries
(defn set-favorite-color [user-info color]
(assoc user-info :favorite-color color))
Clojure core and libraries
domain
(def user-info (reagent/atom {}))
(defn favorite-color-button [color] ;; reagent component
[:button {:on-click (fn []
(swap! user-info assoc :favorite-color color))
:style {:background-color color}}
color])
(defn favorite-color-panel []
[:div
[:h2 "Favorite color"]
[:h3 "Current: " (:favorite-color @user-info)]
[:h3 "Change it by clicking below"]
[favorite-color-button "green"]
[favorite-color-button "blue"]
[favorite-color-button "red"]])
(def user-info (reagent/atom {}))
(defn favorite-color-button [color] ;; reagent component
[:button {:on-click (fn []
(swap! user-info set-favorite-color color))
:style {:background-color color}}
color])
(defn favorite-color-panel []
[:div
[:h2 "Favorite color"]
[:h3 "Current: " (:favorite-color @user-info)]
[:h3 "Change it by clicking below"]
[favorite-color-button "green"]
[favorite-color-button "blue"]
[favorite-color-button "red"]])
(ns my-app.user-info)
(defn set-favorite-color [user-info color]
(assoc user-info :favorite-color color))
(ns my-app.user-info)
(defn set-favorite-color [user-info color]
(assoc user-info :favorite-color color))
(defn set-favorite-animal [user-info animal]
(assoc user-info :favorite-animal animal))
(defn set-favorite-fruit [user-info fruit]
(assoc user-info :favorite-fruit fruit))
Objection:
But Eric, isn't that a lot of code?
(def user-info (reagent/atom {}))
(defn favorite-color-button [color] ;; reagent component
[:button {:on-click (fn []
(swap! user-info assoc :favorite-color color))
:style {:background-color color}}
color])
(defn favorite-color-panel []
[:div
[:h2 "Favorite color"]
[:h3 "Current: " (:favorite-color @user-info)]
[:h3 "Change it by clicking below"]
[favorite-color-button "green"]
[favorite-color-button "blue"]
[favorite-color-button "red"]])
(def user-info (reagent/atom {}))
(defn set-favorite-color [user-info color]
(assoc user-info :favorite-color color))
(defn favorite-color-button [color] ;; reagent component
[:button {:on-click (fn []
(swap! user-info set-favorite-color color))
:style {:background-color color}}
color])
(defn favorite-color-panel []
[:div
[:h2 "Favorite color"]
[:h3 "Current: " (:favorite-color @user-info)]
[:h3 "Change it by clicking below"]
[favorite-color-button "green"]
[favorite-color-button "blue"]
[favorite-color-button "red"]])
Con:
3x the code
Con:
3x the code
Pro:
Find things in ⅓ the time
Probably duplicated operations
Parts can evolve separately
Less to keep in your head
Clojure core
Libraries
Domain code
The biggest regret I hear frequently is
doing data operations everywhere.
Clojure core
Libraries
Domain code
Clojure core
Libraries
Domain code
Clojure core
Libraries
Domain code
Clojure core
Libraries
Domain code
Clojure core
Libraries
Domain Layer 1
Domain Layer 2
Domain Layer 3
Domain Layer 4
{:date #inst "1984-04-03T13:08:42.020"
:name "Soyuz T-11"
:spacecraft "Soyuz"
:destination "Salyut 7"
:crew {:commander {:name "Yuri Malyshev"
:favorite-color "blue"}
:flight-engineer {:name "Gennadi Strekalov"
:favorite-fruit :banana}
:research-cosmonaut {:name "Rakesh Sharma"
:favorite-animal :sheep}}}
You are in a maze of deeply nested maps, all alike
You are in a maze of deeply nested maps, all alike
(assoc-in mission [:crew :research-cosmonaut :training :centrifuge :status] :pass)
(assoc-in mission [:crew :research-cosmonaut :training :centrifuge :status] :pass)
mission
(update-in mission [:crew :research-cosmonaut :training :centrifuge :status] :pass)
person training
(ns my-app.training)
(defn set-status [record training status]
(assoc record training status))
(ns my-app.person
(:require [my-app.training :as training])
(defn set-training-status [person training status]
(update person :training training/set-status training status))
(ns my-app.mission
(:require [my-app.person :as person]))
(defn set-training-status [mission position training status]
(update-in mission [:crew position] person/set-training-status training status))
Clojure core
Libraries
Training
Person
Mission
UI
Law of Demeter
a given object should assume as little as possible about
the structure or properties of anything else (including its
subcomponents)
Objection:
But Eric, aren't you encapsulating?
Isn't the point of Clojure that it's all data?
Summary:
We are encapsulating and it's still data.
Map Entitytension
Map Entitytension
● enumerate keys
● serialize to json
● print
● compare with =
● hash code
● try out data operations at
REPL
Map Entitytension
● enumerate keys
● serialize to json
● print
● compare with =
● hash code
● try out data operations at
REPL
● domain operations
● maintain invariants
● program at a high level
● easier to understand
Chemistry (heat, acids, proteins, starches, etc)
Applying heat
Ingredients (vegetables, meats, oils, spices)
Basics (sauces, masalas, dough)
Dishes
Stratified Design
Chopping
Chemistry (heat, acids, proteins, starches, etc)
Applying heat
Ingredients (vegetables, meats, oils, spices)
Basics (sauces, masalas, dough)
Dishes
Stratified Design
Chopping
changes faster
changes slower
Principle:
separate things according to rates of change
Chemistry (heat, acids, proteins, starches, etc)
Applying heat
Ingredients (vegetables, meats, oils, spices)
Basics (sauces, masalas, dough)
Dishes
Stratified Design
Chopping
Principle:
each layer can only require downward
Chemistry (heat, acids, proteins, starches, etc)
Applying heat
Ingredients (vegetables, meats, oils, spices)
Basics (sauces, masalas, dough)
Dishes
Stratified Design
Chopping
Principle:
each layer can only require downward
Chemistry (heat, acids, proteins, starches, etc)
Applying heat
Ingredients (vegetables, meats, oils, spices)
Basics (sauces, masalas, dough)
Dishes
Stratified Design
Chopping
Principle:
each layer can only require downward
Chemistry (heat, acids, proteins, starches, etc)
Applying heat
Ingredients (vegetables, meats, oils, spices)
Basics (sauces, masalas, dough)
Dishes
Stratified Design
Chopping
Principle:
be careful if you skip layers
Chemistry (heat, acids, proteins, starches, etc)
Applying heat
Ingredients (vegetables, meats, oils, spices)
Basics (sauces, masalas, dough)
Dishes
Stratified Design
Chopping
Principle:
be careful if you skip layers
Constructors
Functions for generating entities
Benefits
● Define the entity's keys
● Check required keys
● Check types
● Check invariants
● Default values
● Calculated values
Constructors
(defn ->person [& {:keys [name
trainings]
:or {trainings []}}]
(assert (string? name))
(let [name (string/trim name)]
(assert (not (empty? name)))
{:name name
:trainings trainings}))
key names
default
type + required
calculation
invariant
Combining Operations
Functions that combine 2 or more entities of the same type
Benefits
● Hardest type of operation first
● Constrain the design (good thing)
● Biggest potential for algebraic reasoning
Combining operations
(ns my-app.training)
(defn combine-training-status [a b]
(cond
(= :pass a) :pass
(= :pass b) :pass
:else :fail))
(defn combine-trainings [a b]
(merge-with combine-training-status a b))
two statuses
two training records
Meaning
Implementation
Sounds
Meaning
Software
Characters
Meaning
Data
you want to be working up here
Meaning
Data
you want to be working up here
but you're stuck down here
Code Smells
Smell:
Deep paths with get-in, update-in, assoc-in
Smell:
Large hashmaps with lots of keys
{:id 1232
:email "eric@lispcast.com"
:phone "504-982-9167"
:street1 "332 Main St"
:street2 "Apartment 54"
:city "New Orleans"
:state "LA"
:zip "70117"
:favorite-color "blue"
:favorite-animal :orangutan
:favorite-fruit :apple}
{:id 1232
:email "eric@lispcast.com"
:phone "504-982-9167"
:street1 "332 Main St"
:street2 "Apartment 54"
:city "New Orleans"
:state "LA"
:zip "70117"
:favorite-color "blue"
:favorite-animal :orangutan
:favorite-fruit :apple}
do these go together?
{:id 1232
:contact-info {:email "eric@lispcast.com"
:phone "504-982-9167"
:address {:street1 "332 Main St"
:street2 "Apartment 54"
:city "New Orleans"
:state "LA"
:zip "70117"}}
:favorites {:color "blue"
:animal :orangutan
:fruit :apple}}
Smell:
Using 3rd party API results directly
{:tags [21 134 353 386 388],
:format "standard",
:date "2017-04-24T11:59:33",
:slug "kjetil-valle-and-bendik-solheim-lambdaconf-2017-interview",
:meta {:_edd_button_behavior []},
:ping_status "closed",
:yst_prominent_words [3680 979 1318 497 505 849 3783 495 3938],
:featured_media 8087,
:content
{:rendered
"<p>......",
:protected false},
:modified_gmt "2018-04-11T11:31:44",
:excerpt
{:rendered
"<p>......",
:protected false},
:type "post",
:custom
{:seen_in_lesson_rss "0",
:markdown_content
"......",
:s3_filename "",
:availability "Paid",
:wistia_download_link "",
:tweet_ids "",
:tweet
"....",
:video_length "",
:footer_script "",
:language "a:1:{i:0;s:7:"Clojure";}",
:inline_featured_image "0",
:last_tweet_time "",
:git_tag "",
:github_repo "",
:header_script "",
:wistia_id "",
:autopause_times ""},
:template "",
:modified "2018-04-11T11:31:44",
:title
{:rendered
"# ...."},
:author 652,
:date_gmt "2017-04-24T11:59:33",
:comment_status "closed",
:categories [123],
:sticky false,
:status "draft",
:link "https://purelyfunctional.tv/?p=8086",
:id 8086,
:_links
{:version-history
{:id 143
:video-id "44fvv3"
:sequence-number "003"
:name "Concurrent Clojure"
:duration 34223
:programming-language 4
:cover nil
:course-id 74
:s3-links {:original {:filename "ConcurrentClojure.mp4"
:filesize 321554}
:hd {:filename "ConcurrentClojure.mp4"
:filesize 321443}
:md {:filename "ConcurrentClojure.mp4"
:filesize 54443}
:phone {:filename "ConcurrentClojure.mp4"
:filesize 3223}}}
Know what level of meaning you are at
● Look for semantic layers
● Avoid crossing semantic layers
● Organize your entities and operations
● Think about combining operations
● Add a layer of indirection between your service and other systems
● Use constructors to make getting it right easier
● Name operations to give things meaning
Eric Normand
Follow Eric on:
Eric Normand @EricNormand
eric@lispcast.comlispcast.com

More Related Content

PPTX
20171014 tips for manipulating filesystem in julia
PDF
Manifests of Future Past
PPTX
Ch3(working with file)
PDF
Andreas Roth - GraphQL erfolgreich im Backend einsetzen
PDF
Shell实现的windows回收站功能的脚本
PDF
HaskellとDebianの辛くて甘い関係
PDF
Ruby - Uma Introdução
PDF
Having Fun Programming!
20171014 tips for manipulating filesystem in julia
Manifests of Future Past
Ch3(working with file)
Andreas Roth - GraphQL erfolgreich im Backend einsetzen
Shell实现的windows回收站功能的脚本
HaskellとDebianの辛くて甘い関係
Ruby - Uma Introdução
Having Fun Programming!

What's hot (20)

TXT
Mkscript sh
ODP
Making a simple jQuery plug-in
KEY
Getting started with Pod::Weaver
PDF
An (Inaccurate) Introduction to Python
PPTX
Migrating to Puppet 4.0
PPTX
Chap 5 php files part-2
PDF
Simple Ways To Be A Better Programmer (OSCON 2007)
PDF
Procesamiento del lenguaje natural con python
PDF
WordCamp Portland 2018: PHP for WordPress
PDF
Thu bernstein key_warp_speed
PDF
MongoDB: Replication,Sharding,MapReduce
PDF
WordPress Cuztom Helper
PDF
Cleanliness is Next to Domain-Specificity
PDF
Talk NullByteCon 2015
PDF
A Python Crash Course
PDF
TDC São Paulo 2016 - Become a jedi with php streams
PPT
Application Modeling with Graph Databases
PPTX
python chapter 1
PPTX
Python chapter 2
PDF
Mengembalikan data yang terhapus atau rusak pada hardisk menggunakan ubuntu
Mkscript sh
Making a simple jQuery plug-in
Getting started with Pod::Weaver
An (Inaccurate) Introduction to Python
Migrating to Puppet 4.0
Chap 5 php files part-2
Simple Ways To Be A Better Programmer (OSCON 2007)
Procesamiento del lenguaje natural con python
WordCamp Portland 2018: PHP for WordPress
Thu bernstein key_warp_speed
MongoDB: Replication,Sharding,MapReduce
WordPress Cuztom Helper
Cleanliness is Next to Domain-Specificity
Talk NullByteCon 2015
A Python Crash Course
TDC São Paulo 2016 - Become a jedi with php streams
Application Modeling with Graph Databases
python chapter 1
Python chapter 2
Mengembalikan data yang terhapus atau rusak pada hardisk menggunakan ubuntu
Ad

Similar to You are in a maze of deeply nested maps, all alike (20)

PDF
Programming Lisp Clojure - 2장 : 클로저 둘러보기
PPTX
The groovy puzzlers (as Presented at JavaOne 2014)
PDF
The Curious Clojurist - Neal Ford (Thoughtworks)
DOCX
findextensions(2).py#!usrlocalbinpython3import sysim.docx
PPT
Scala presentation by Aleksandar Prokopec
ODP
Clojure made really really simple
PDF
Clojure for Data Science
PDF
Pune Clojure Course Outline
PDF
コミュニケーションとしてのコード
ODP
Introduction to R
PDF
From Java To Clojure (English version)
PDF
Introduction to Scala
ODP
Clojure made simple - Lightning talk
PDF
Swift - Krzysztof Skarupa
PDF
Music as data
PDF
David Kopal - Unleash the power of the higher-order components
PDF
Swift & JSON
PDF
Clojure for Java developers - Stockholm
PDF
Intro to programming games with clojure
PDF
talk at Virginia Bioinformatics Institute, December 5, 2013
Programming Lisp Clojure - 2장 : 클로저 둘러보기
The groovy puzzlers (as Presented at JavaOne 2014)
The Curious Clojurist - Neal Ford (Thoughtworks)
findextensions(2).py#!usrlocalbinpython3import sysim.docx
Scala presentation by Aleksandar Prokopec
Clojure made really really simple
Clojure for Data Science
Pune Clojure Course Outline
コミュニケーションとしてのコード
Introduction to R
From Java To Clojure (English version)
Introduction to Scala
Clojure made simple - Lightning talk
Swift - Krzysztof Skarupa
Music as data
David Kopal - Unleash the power of the higher-order components
Swift & JSON
Clojure for Java developers - Stockholm
Intro to programming games with clojure
talk at Virginia Bioinformatics Institute, December 5, 2013
Ad

More from Eric Normand (9)

PDF
The elements of a functional mindset
PDF
All I Needed for Functional Programming I Learned in High School Algebra
PDF
Lies My OO Teacher Told Me
PDF
What is Functional Programming?
PDF
Functional Programming for Business
PDF
A Theory of Functional Programming LambdUp
PDF
Testing stateful, concurrent, and async systems using test.check
PDF
Building Composable Abstractions
PDF
ClojureScript: I can't believe this is JavaScript
The elements of a functional mindset
All I Needed for Functional Programming I Learned in High School Algebra
Lies My OO Teacher Told Me
What is Functional Programming?
Functional Programming for Business
A Theory of Functional Programming LambdUp
Testing stateful, concurrent, and async systems using test.check
Building Composable Abstractions
ClojureScript: I can't believe this is JavaScript

Recently uploaded (20)

PPTX
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
PDF
PREDICTION OF DIABETES FROM ELECTRONIC HEALTH RECORDS
PPTX
M Tech Sem 1 Civil Engineering Environmental Sciences.pptx
PPTX
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
PDF
null (2) bgfbg bfgb bfgb fbfg bfbgf b.pdf
PPTX
Construction Project Organization Group 2.pptx
PDF
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
DOCX
573137875-Attendance-Management-System-original
PDF
Embodied AI: Ushering in the Next Era of Intelligent Systems
PDF
Automation-in-Manufacturing-Chapter-Introduction.pdf
PDF
PPT on Performance Review to get promotions
PDF
BIO-INSPIRED HORMONAL MODULATION AND ADAPTIVE ORCHESTRATION IN S-AI-GPT
PPTX
Artificial Intelligence
PDF
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
PDF
III.4.1.2_The_Space_Environment.p pdffdf
PPT
Mechanical Engineering MATERIALS Selection
PPTX
CARTOGRAPHY AND GEOINFORMATION VISUALIZATION chapter1 NPTE (2).pptx
PPTX
Fundamentals of Mechanical Engineering.pptx
PPTX
Internet of Things (IOT) - A guide to understanding
PPT
Project quality management in manufacturing
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
PREDICTION OF DIABETES FROM ELECTRONIC HEALTH RECORDS
M Tech Sem 1 Civil Engineering Environmental Sciences.pptx
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
null (2) bgfbg bfgb bfgb fbfg bfbgf b.pdf
Construction Project Organization Group 2.pptx
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
573137875-Attendance-Management-System-original
Embodied AI: Ushering in the Next Era of Intelligent Systems
Automation-in-Manufacturing-Chapter-Introduction.pdf
PPT on Performance Review to get promotions
BIO-INSPIRED HORMONAL MODULATION AND ADAPTIVE ORCHESTRATION IN S-AI-GPT
Artificial Intelligence
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
III.4.1.2_The_Space_Environment.p pdffdf
Mechanical Engineering MATERIALS Selection
CARTOGRAPHY AND GEOINFORMATION VISUALIZATION chapter1 NPTE (2).pptx
Fundamentals of Mechanical Engineering.pptx
Internet of Things (IOT) - A guide to understanding
Project quality management in manufacturing

You are in a maze of deeply nested maps, all alike