Ep 027: Collected Context
► Play EpisodeNate and Christoph reflect on what they learned during the Twitter series.
- 6 months of podcast episodes!
- Situated programs: Part of the real world. Affect and affected by the world around it.
- (04:25) Concept 1: Was very helpful to focus on nailing down the algorithm before diving into the code.
- (06:00) Concept 2: Two kinds of data: operating data and forensic data
- Operating data: information you use for logic. Make it aggressively minimal.
- Forensic data: information you record, off to the side, to tell a story later. Record as much as feasible.
- Don't do logic on the forensic data!
- If you end up writing code to sift through the forensic data in the future, cherry pick out the data need to use and treat that as operational data for that problem.
- "'No' is temporary. 'Yes' is forever."
- (09:45) Concept 3: Use components to wrap integrations
- We wrapped DB and Twitter integrations.
- If a component needs a resource, that resource should be a component.
- Because resources are components, you can substitute the real component with a "faker" component.
- (11:10) Concept 4: Fake resources for productivity
- A "faker" component takes the place of a real component to enable developers to be more productive.
- Faking is not for testing code, it's for effective development.
- Can avoid Internet and latency.
- Can run the code right out of the repo.
- Allows you to explore how the whole system behaves during edge cases and behaviors.
- Allows you to start with useful information or quickly reset back to scenarios.
- "If an edge case is going to be annoying in the wild, you might as well get used to it being annoying during development."
- (13:40) Concept 5: Aggressively decouple decision logic from imperative work
- Push side effects (like I/O) to the "edges", but some situations make that less straightforward.
- Challenge: our algorithm had a tick-tock: side effect, logic, side effect, logic, ...
- Our approach: separate each side effect and only do one at a time.
- (16:10) Concept 6: Watch out for convenient side effects
- Eg. Doing a little bit of I/O in the middle of a function.
- Eg. Get "now" from the system clock in the middle of a function
- (16:35) Concept 7: Side-effect assumptions make your system fragile.
- When you have code in one place that depends on something having been established by code in another place.
- Eg. Knowing the calling function has already done a check.
- There is an implicit umbrella of context. Creates a hidden dependency between those two places.
- When the assumption is violated, there's nothing to stop the code making the assumption from just marching off the cliff.
- Put the guard logic next to the code that needs it.
- (19:15) Concept 8: Make context explicit
- A function should take all of its "knowledge" in as data. It should not assume something has been done for it elsewhere.
- "This forces you to write down all the things that matter instead of assuming something else has put things in place."
- Explicit context allows you to separate out imperative steps.
- "The hidden relationships, the ones that are only in my brain, those are the things that will completely burn me in 6 months."
- (20:45) Concept 9: Favor instructions as data rather than instructions as function names.
- Eg. Our Twitter wrapper only has one
invoke
function. (Inspired by aws-api.) - Function names aren't part of the data. If the "command" name is the function name, how do you match on it? You can't.
- When commands = function names, you have implicit information: "I must have command X because I'm on line Y."
- Observation: the description of the goal is usually more stable than the steps to achieve the goal.
- If all of the instructions are in data, the processing component can completely change how it achieves the goal without the calling component changing how it interacts.
- Eg. Our Twitter wrapper only has one
- (26:00) Concept 10: Treat components within your application as loosely coupled services.
- What is a "microservice"? When you make a request (aka "data"), ship it out, and get a response back (aka "data").
- In Clojure, we can treat component interactions like loosely coupled APIs too: send them rich data, get rich data back.
- Get loose coupling on the inside of the service, not just between services.
- (27:25) We want to help programmer effectiveness and reduce burnout.
- "We want to help you avoid situations where you're beating your head against the wall wondering where things went wrong."
- "One of the great benefits of simple design and Clojure, it allows you create things that are fun to create AND fun to maintain."
Message Queue discussion:
- (29:15) "You know what else is a lot of fun? Hearing from our listeners!"
- We had an issue with our SSL certs. Thanks for the heads up and let us know if you have any tech trouble.
- "Automagically". We can't say we invented it, but we love that word.
- "What is magic? An invisible force with a visible effect. Sound an awful lot like a side effect!"
- "You start wielding the power, it feels GREAT! And then it all starts going wrong."
- Easy does not imply simple. Go watch that talk. (See below.)
Related episodes:
- 020: Data Dessert
- 021: Mutate the Internet
- 022: Evidence of Attempted Posting
- 023: Poster Child
- 024: You Are Here, But Why?
- 025: Fake Results, Real Speed
- 026: One Call to Rule Them All
Clojure in this episode:
nil
Related links: