Chapter 3 - Grokking Simplicity
PLEASE NOTE: Any reference to arrows in this chapter refer to inputs and outputs. Where applicable, I will make reference to the arrows specifically as INPUT or OUTPUT
Additionally, the name of the section and the sentence or paragraph before the image/chart descriptions have been included and placed in parentheses.
Actions, calculations, and data apply to any situation
- "If a nonfunctional programmer were to sketch out the process of shopping, it might look roughly like the following. On the left, we’ll categorize each of the steps into actions, calculations, and data (ACD)."
Grocery Shopping Process: Actions depend on how many times or when they run
- Action: Check fridge (Definitely an action. It matters when I look in the fridge. Tomorrow, there may be less milk)
- Action: Drive to store (For sure an action. Driving twice will use twice as much gas)
-Action: Buy what you need (Buying stuff is an action. When I buy broccoli, no one else can after me, so when I buy matters)
- Action: Drive home (An action. I can't drive home when I'm already at home, so it matters when)
You probably remember this is called a timeline diagram. We'll see it again in full detail in part 2.
- "We can’t accept that everything is an action. Though we might rarely find only actions in extremely simple situations, this one isn’t so simple. We’ve got a good outline of the shopping process. Let’s go through each step and see if we can find what we’re missing."
Grocery Shopping Process
- Check fridge
- Drive to store
- Buy what you need
- Drive home
- Store the food
Buy what you need
- "In fact, this is using a piece of data we generated in the first step: the current inventory. We can break “buying what you need" into a few pieces:"
- Data: Current inventory
- Data: Desired inventory
- Calculation: Inventory "minus" — Inventory "minus is a calculation because for the same inputs it gives the same outputs. Calculations are often decisions, such as this one, which decides what to buy. Separating deciding what to buy from buying it.
- Data: Shopping list
- Action: Buy from list
Drive home
Grocery Shopping Process Calculations
- "Let’s draw out a more complete diagram of the process. We will separate out the actions, calculations, and data into separate columns for clarity. We can also draw arrows to represent data being outputted by and inputted to actions and calculations."
NOTE: There are three columns represented on the page. To illustrate this I've created a table. However for the rest of the chapter, I've created text with arrows to show the inputs and outputs.
| Action | Data | More Explanations |
|---|---|---|
|
Check fridge outputs the current inventory In the data column |
Current Inventory |
Inventory minus two pieces of data as inputs: |
| Drive to store | Desired Inventory | |
|
Buy from list as input |
Shopping list | |
| Drive home |
Brain Break
At the bottom of this section, there is an image containing the following information:
- "Most data goes through many levels of interpretation in its lifetime, from bytes, to characters, to JSON, to user information."
Multiple Levels of Interpretation of a web request
- Bytes -> Characters -> JSON -> Collections -> User info
- Client -> (request received) -> Server (decisions made) -> (action taken) -> Email sent
A new marketing tactic at CouponDog: Referral Plan
Below are two tables that will be referred to throughout the next few sections.
- "The company has a big database table of email addresses. Along with that, they have counted how many times each person has recommended CouponDog to their friends.
They also have a database of coupons. These are ranked as "bad," "good," and "best." The "best" coupons are reserved for people who recommend a lot. Everyone else gets “good” coupons. They never send out "bad" coupons."
Email Database Table: the number of times they have recommended the newsletter to friends
| Rec-count | |
|---|---|
| John@coldmail.com | 2 |
| sam@pmail.com | 16 |
| linda1989@oal.com | 1 |
| jan1940@ahoy.com | 0 |
| mrbig@pmail.co | 24 |
| lol@lol.lol | 0 |
Sam and Mr Big get the "best" coupons because their Rec-count >= 10
Coupon Database Table (This will be referred to later)
| Rec-count | |
|---|---|
| MAYDISCOUNT | good |
| 10PERSENT | bad |
| PROMOTION45 | best |
| IHEARTYOU | bad |
| GETADEAL | best |
| ILIKEDISCOUNTS | Good |
1. Let's start with fetching subscribers from the data base
Coupon Email Process calculations
ACTIONS: 1. Fetch subscribers from DB -> DATA: 1. List of subscribers
2. Fetching the coupons from the database
ACTIONS: Fetch subscribers from DB -> DATA: List of subscribers
ACTIONS: Fetch coupons from DB (this is an event) -> DATA: List of coupons (this is a fact about the event)
3. Generating the emails to send
ACTIONS: Fetch subscribers from DB -> DATA: List of subscribers -> CALCULATIONS: Plan list of emails -> DATA: List of emails
ACTIONS: Fetch coupons from DB -> DATA: List of coupons -> CALCULATIONS: Plan list of emails -> DATA: List of emails
4. Sending the emails
ACTIONS: Fetch subscribers from DB -> DATA: List of subscribers ->CALCULATIONS: Plan list of emails -> DATA: List of emails -> ACTION: Send emails
ACTIONS: Fetch coupons from DB -> DATA: List of coupons -> CALCULATIONS: Plan list of emails -> DATA: List of emails -> ACTION: Send emails
Zooming into generating emails
- "Planning out all of the emails you’re going to send before you send them may feel foreign, but it’s quite common to do so in functional programming. Let’s zoom into this calculation and see how it is made of smaller calculations. Here it is as we’ve already seen it."
DATA: List of subscribers, List of coupons (these are inputs)-> CALCULATIONS: Plan list of emails -> DATA: List of emails (this is an output)
- "First, we could calculate lists of "good" coupons and "best" coupons."
DATA: List of coupons -> CALCULATIONS: Select good coupons, Select best coupons -> DATA: List of good coupons, List of best coupons
- "Then, we could make a calculation that decides whether a subscriber gets the good or best ones."
DATA: Subscriber -> CALCULATIONS: Decide coupon rank (this decision is based on the rule of ref-count >= 10) -> DATA: Coupon rank
- "Now we can put them together to make a calculation that plans a single email given a single subscriber."
DATA: Subscriber -> CALCULATIONS: Decide coupon rank -> DATA: Coupon Rank -> CALCULATIONS: If rank is "good," plan good email; if rank is "best," plan best email -> DATA: Email
OR Subscriber skips "decide coupon rank" and jumps to "if rank is "good/best" plan email.
Implementing the coupon email process
- "Let's start implementing the three boxes— one calculation and two pieces of data— that we see in this section of the diagram:"
DATA: Subscriber -> CALCULATIONS: Decide coupon rank -> DATA: Coupon rank
The subscriber's data from the database
- "We know that the subscriber data comes from a table like we see on the right. In JavaScript, one way to represent this data is as a plain JavaScript object. It would look like this:"
The table referred to here is the "Email Database Table" we saw earlier (also shared below) where the JavaScript illustrates how each row from the table becomes an object:
var subscriber = {
email: "sam@pmail.com",
rec_count: 16
};
| Rec-count | |
|---|---|
| John@coldmail.com | 2 |
| sam@pmail.com | 16 |
| linda1989@oal.com | 1 |
| jan1940@ahoy.com | 0 |
| mrbig@pmail.co | 24 |
| lol@lol.lol | 0 |
The coupon rank is a string
- "We previously decided that the coupon rank would be a string. It could be any type, really, but making it a string is convenient. It corresponds to the values in the rank column of the coupon table."
var rank1 = "best"; //ranks are strings
var rank2 = "good"; //ranks are strings
| Rec-count | |
|---|---|
| MAYDISCOUNT | good |
| 10PERSENT | bad |
| PROMOTION45 | best |
| IHEARTYOU | bad |
| GETADEAL | best |
| ILIKEDISCOUNTS | good |
Deciding a coupon rank is a function
- "Let’s implement one more section of the diagram, which is how to select only coupons of a given rank out of a big list of coupons."
DATA: List of coupons -> CALCULATIONS: Select good coupons, Select best coupons -> DATA: List of good coupons, List of best coupons
The coupon's data from the database
- "Just like we did for a subscriber, we can represent a coupon with a JavaScript object:"
var coupon = {
code: "10PERCENT",
rank: "bad"
};
| Rec-count | |
|---|---|
| MAYDISCOUNT | good |
| 10PERSENT | bad |
| PROMOTION45 | best |
| IHEARTYOU | bad |
| GETADEAL | best |
| ILIKEDISCOUNTS | Good |
The calculation to select coupons by rank is a function
- "We have one more major section of the diagram to implement, which is the one that plans an individual email."
DATA: Subscriber, List of good coupons, List of best coupons -> CALCULATIONS: If rank is "good," plan good email; if rank is "best," plan best email -> DATA: Email