iteration cover image

iteration

Latest episodes

undefined
Jul 1, 2019 • 39min

Building Tests

Chapter 4 - Building Tests To do refactoring properly, I need a solid suite of tests to spot my inevitable mistakes. The Value of Self-Testing Code make sure all tests are fully automatic and that they check their own results a suite of tests is a powerful bug detector that decapitates the time it takes to find bugs If you want to refactor, you have to write tests A First Test simplicity of feedback from tests. just dots personally like verbose test output Add Another Test Testing should be risk driven; remember, I'm trying to find bugs, now or in the future. Therefore I don't test accessor methods that just read and write a field. They are so simple that I'm not likely to find a bug there. My focus is to test areas that I'm most worried about going wrong. Probing the Boundaries Seeing what happens when things go wrong Whenever I have a collection of something, ... I like to see what happens when it's empty What happens when negative numbers are passed to a function that expects positive numbers? Division by zero? How do you probe boundaries? Much More Than This When you get a bug report, start by writing a unit test that exposes the bug Picks JP: Taking time off
undefined
Jun 24, 2019 • 40min

Encapsulation

Episode 6 - More Code Examples Drawing from Chapter 7 - Encapsulation A weekly podcast about programming, development, and design through the lens of amazing books, chapter-by-chapter. Encapsulate Record (162) var organization = { name: "JP Sio", country: "USA" }; becomes ⬇️ class Organization { constructor(data) { this._name = data.name; this._country = data.country; } get name() { return this._name; } set name(arg) { this._name = arg; } get country() { return this._country; } set country(arg) { this._country = arg; } } you can hide what is stored and provide methods consumer of class Organization doesn't need to know / care which is stored and which is calculated nice getter and setter methods makes it easier to refactor -> can hide implementation of internals and update the internals while keeping the same external interface Encapsulate Collection (170) class Person { get courses() { return this._courses; } set courses(aList) { this._courses = aList; } } becomes ⬇️ class Person { get courses() { return this._courses.slice(); } addCourse(aCourse) { /*...*/ } } slice() is key here, does not modify the original array - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice common approach is to provide a getting method for the collection to return a copy basically, never mutate the original Replace Primative with Object (174) orders.filter(0 => "high" === o.priority || "rush" === o.priority) becomes ⬇️ orders.filter(o => o.priority.higherThan(new Priority("normal"))); this goes back to "Primitive Obsession" programmers are often hesitant to create their own types and rely only on primitives. i.e. representing a phone number as a string instead of as it's own type A telephone number may be represented as a string for a while, but later it will need special behavior for formatting, extracting the area code, and the like create a new class for that bit of data at first, the class does very little. in fact it probably only wraps a primitive but now you have a place to put behavior specific to its needs Inline Function (115) 🥴 Sometimes it's better to not try to split things apart, sometimes it just complicates things. // before refactor: function getItemPrice(item) { if (itemOnSale(item) == true) { return item.price - 5 } else { return item.price } }; function itemOnSale(product) { if (product.onSale == true) { return true; } else { return false; } }; let original = getItemPrice(sweatshirt); // after refactor: function newGetItemPrice(item) { if (item.onSale == true) { return item.price - 5 } else { return item.price } }; Extract Class (182) 🥴 Talk through HUGE applicant model (in Ruby) Broke this into child objects Applicant Health History Applicant Habits Applicant Lifestyle Applicant Method Applicant Legal Release Picks JP: None :( John: Quad Lock phone mount - bikes
undefined
Jun 17, 2019 • 44min

Bad Smells in Code

Chapter 3 - Bad Smells in Code The theme of this chapter: just because you know how to refactor, doesn't mean you know when. This chapter talks about the when. One thing we won't try to give you is precise criteria for when a refactoring is overdue. In our experience, no set of metrics rivals informed human intuition. What we will do is give you indications that there is trouble that can be solved by a refactoring. Mysterious Name there can be ambiguity in your naming in many places: variable, class, function, method, database field, etc Duplicated Code 🔥 keep it dry Long Functions 🔥 Since the early days of programming, people have realized that the longer a function is, the more difficult it is to understand Long Parameter List 🔥 long parameter lists can be confusing Global Data 🔥 the problem with global data is that it can be modified from anywhere in the codebase, making it harder to figure out which code touched it should you need to debug it Mutable Data changes to data often lead to unexpected consequences and tricky bugs mutable data that can be calculated elsewhere is particularly pungent Divergent Change ✅ if you look at a module and say, "well, I will have to change these three functions every time -------- happens" - this is an indication of divergent change divergent change occurs when one module is often changed in different ways for different reasons can be solved with split phase, extract function, extract class, move function Shotgun Surgery ✅ similar to divergent change. every you make a change, you need to make a ton of little edits to a lot of different classes Feature Envy occurs when a function in one module spends more time communicating with functions or data inside another module than it does within its own. Data Clumps grouping data together when it really should be it's own object Primitive Obsession ✅ programmers are often hesitant to create their own types and rely only on primitives. i.e. representing a phone number as a string instead of as it's own type Repeated Switches alleviated with polymorphism Loops use pipelines instead, i.e. filter, map, each, reduce Speculative Generality ✅ editor choice can be spotted when the only users of a function or class are a test case. this is a classic case of premature optimization. "we'll eventually want to add this feature..." Message Chains when a client asks one object for another object, which the client then asks for yet another object, and so on. Middle Man when you have too much delegation (due to all of your great encapsulating of implementation details) the solution is to delegate directly, cut the middle man Insider Trading Large Class ✅ class is doing too much Alternative Classes with Different Interfaces Data Class Refused Bequest Picks: JP: https://classicleatherfobs.co.uk/product-category/porsche/ John: https://c-command.com/toothfairy/
undefined
Jun 10, 2019 • 42min

Refactoring 🛠Getting Into The Weeds

S06E04 - Iteration A weekly podcast about development and design through the lens of amazing books, chapter-by-chapter Refactors Before - Extract Function Change Function Decleration Replace Temp with query Replace conditional with polymorphism Refactoring in Practice Introduce Parameter Object - 140 Structure your parameters This way order doesn’t matter You can set default values Grouping data is more clear in the relationship Replace Constructor with Factory Function 334 - Encapsulating the creation of objects (the initialize) into a factory Function In Ruby: Creating a new User and Organization within a UserOrganizationFactory call / Tangent / Related to FormObjects. In JavaScript: availableVariants - big array with Item, Colors, Sizes - replaced with variantFactory(34,2345,2345,) just passing ID’s Extract Function into class - 182 Consolidate up a bunch of related functions into a parent class Split Phase 154 - Variant of Extract Function When a function is dealing with two different things - look for a way to split it out - was cleaner approach. JavaScript Cart.js - logic of API calls associated with the user input Split this into discrete functions Ruby Notification logic was calling Twilio Encapsulate this into it’s own method Later then it was a service object to itself My Cart.js Story - (Refactoring in Vue / JavaScript) addItem - for adding item to cart removeItem - for removing item from cart increaseItemCount - for adjusting line item decreaseItemCount - for adjusting line item setLineItemCount - for adding to cart an initial value First - Rename Methods (Change Function Declaration) 124 addItem - became - addItemToCart removeItem - became - removeItemFromCart increaseItem - became - increaseLineItemCount decreaseItem - became - decreaseLineItemCount Second - Extract Function 106 Both increaseLineItemCount and decreaseLineItemCount were doing something very similar. So I created a new function of setLineItemQty Both my methods of increaseLineItemCount and decreaseLineItemCount were then calling this setLineItemQty that accepted a qty parameter - function. Second - parameterize Function 310 This did take a refactor of my vue listeners. Since I had this new setLineItemQty that accepted a qty parameter I replaced increaseLineItemCount and decreaseLineItemCount a single function of setLineItemQty Deleted a lot of code Third - Used inline function 106 to simply alias another function. Through the above refactors I realized that addItemToCart was doing the same transactional work as setLineItemQty to 1 I removed the body of addItemToCart and replaced it with setLineItemQty with the default params accordingly. Fourth - Again used inline function 106 to alias another function Through the above refactors I realized that removeItemFromCart was doing the same transactional work as setLineItemQty to 0 I removed the body of removeItemFromCart and replaced it with setLineItemQty with the default params accordingly Fifth - I used I realized that all these functions were just doing the same thing. Adjusting CartLineItemCount. The final refactor simply deleted removeItemFromCart and addItemToCart In closing: Code went from 160 lines to around 60 It’s way DRY It’s way more reusable The interface to my cart.js is now just a single function of setLineItemQty Updated my vue listeners - Every interaction within this front end is just calling setLineItemQty Picks: vue.js - https://vuejs.org/ - Burnout Reddit thrread: https://www.reddit.com/r/cscareerquestions/comments/b6xzr0/how_do_you_keep_from_burning_out_at_your_job/
undefined
Apr 1, 2019 • 43min

Principles in Refactoring

Chapter 2 Principles in Refactoring A weekly podcast about programming, development, and design through the lens of amazing books, chapter-by-chapter. Define Refactoring “If someone says their code is broken for a couple days while they are refactoring =, you can be pretty sure they aren’t refactoring. Adding Features Vs Refactoring Why should we refactor? Code rot - overtime the code decays - rushed or poorly executed changes Regular refactoring helps keep things in shape Makes things easier to understand (Delegating issues in clean codebase vs rough) Refactoring helps find bugs Refactoring helps us work faster long term - cleaning your workspace Over time adding new features is easier Getting buy in for refactors: Don’t tell your manager / client Build it into your estimates You are being paid for your expertise be confident in somewhat hiding the implementation. (Depends on your role) When to refactor: Prepatory Refactoring Comprehension refactoring Long term refactor - Ech small change leaves everything is a still working state, not just “up to date” In code reviews When to not refactor: If the code is working fine and it doesn’t need to be changed If it works like an API When it will slow down an essential new feature. Legacy Code Refactoring Tools for future episodes? Writing Ruby Gems Renovate Bot Picks JP: Free Event Tickets John: Eero wifi router
undefined
Mar 25, 2019 • 35min

Refactoring - In Practice

In this episode we dive deep into some specific refactors from Refactoring 's Chapter 1. We talk about renaming things, extracting functions, functions, replacing a temp with query and some other hot tips and tricks you can put into your code today. This episode walks through specific code examples from Chapter 1 of Martin Fowler's Refactoring... Some of the refactors Change Function Declaration Rename things Names are hard A few general categories of things you can name predicate? - Should only return true / false - Javascript start with is - ruby question mark - so isValidPhone(number) In Ruby - ! For destructive / dangerous actions - update_recent_activity! - name destructive actions or actions with side effects really well. Formatting? - use - as - number_as_phone(number) or to to_bmi(user.weight, user.height) Extract Function Replace temp w/ query Extending this example: Instead of: accounts = get_accounts(user) transactions = get_transactions(accounts) we can just do: transactions = get_transactions(get_accounts(user)) Replace conditional with polymorphism Notification.deliver! example Picks JP: Thanos JS - https://thanosjs.org/ John: Loom https://www.loom.com/ - and http://www.telestream.net/screenflow/overview.htm
undefined
Mar 18, 2019 • 40min

New Book - Refactoring

Welcome to iteration. A weekly podcast about programming, development, and design through the lens of amazing books, chapter-by-chapter. Refactoring Improving the Design of Existing Code by Martin Fowler (with Kent Beck) Introduction What’s in the book? Who’s it for? What’s refactoring? Refactoring process: Identify a pain, smell a smell, we’ll talk more about when to refactor in later episodes. Separate feature additions from refactors Refactorings are like diets - a lifestyle vs an intensive Test coverage first Small changes continually running tests End goal: lots of small well-named functions that tells a clear story. Considerations + Thoughts Tests let JP in react native move faster Refactoring lets you get things out of your head and into the code. Do this continuously. Performance and refactoring My Pick: How To Code Well - howtocodewell.net Dark Net Diaries https://darknetdiaries.com/ Selection - Apple's Design Process
undefined
Mar 4, 2019 • 47min

In Between Books

S06E01 - DO IT LIVE! This week is a more casual episode where we talk about recent struggles findings and some of our favorite parts of our most recent book. Practical Object-Oriented Programming in Ruby We'll be back episode covering a new book - Refactoring by Martin Fowler A weekly podcast about programming, development, and design through the lens of amazing books, chapter-by-chapter. CH2 - Designing Classes with a single responsibility Chapter 7 - Favorite Takeaways/Examples From POODR Duck Typing - Modules - My Team Came up with: include Listable include Lister Any user type can act as a “Lister” and add things to the list Any object can be “Listable” or “added to a list” Recent Lessons - Always have a staging environment Picks: https://thispersondoesnotexist.com/
undefined
Feb 18, 2019 • 32min

Testing... Testing... 123...

Iteration S05E09 Testing… Testing… 123 Publishing February 18th - Hope everyone had a good Valentine’s Day weekend! A weekly podcast about programming, development, and design through the lens of amazing books, chapter-by-chapter. Introduction Writing changeable code is an art on which practice relies on three different skills. First, you must understand object-oriented design. Poorly designed code is naturally difficult to change. First, you must understand object-oriented design. A poorly designed code is naturally difficult to change. Second, you must be skilled at refactoring code. Finally, the art of writing a changeable code requires the ability to write high-value tests. Tests give you the confidence to refactor constantly. Reasons to test: Finding Bugs Supplying Documentation Deferring Design Decisions Supporting Abstractions Exposing Design Flaws Knowing What to test: “Most developers write too many tests” - OR NONE! hahaha Tests should concentrate on the incoming or outgoing messages that cross an object’s boundaries. Back to the Kitchen Metaphor - Test that ordering a hamburger, returns a hamburger as expected, not that the kitchen staff turns on the grill or slices tomatoes. Incoming messages should be tested for the state they return. Outgoing command messages should be tested to ensure they get sent. Outgoing query messages should not be tested. Knowing When to Test Write tests first, whenever it makes sense to do so Knowing How to test: Testing Styles: Test Driven Development (TDD) and Behavior Driven Development (BDD). Proving the Public Interface Injecting Dependencies as Roles Testing Inheritance - Test your base class - then include the module to test each of the responses that are in the base class. Creating Test Doubles - DiameterDouble - A test double is a stylized instance of a role player that is used exclusively for testing - tend to override the base class in my test helper - I’ve run into silent errors this way. Testing Private Methods - interface. These private messages are like proverbial trees falling in empty forests; they do not exist, in a perfect world they do not need to be tested - testing them is a code smell. Testing Ducks - create a preferred test interface - mechanic and a guide can both prepare - you can establish a single interface and simply pass the different objects into it. Testing Inherited Code Testing Models + Objects Vs interface - where’s the balance? Tests are indispensable. Well-designed applications are highly abstract and under constant pressure to evolve; without tests these applications can neither be understood nor safely changed. The best tests are loosely coupled to the underlying code and test everything once and in the proper place. They add value without increasing costs. Next Episode - Recap of Practical Object-Oriented Design and New book announcement! Picks: NOUN PROJECT - https://thenounproject.com/ **Super Smash Bros Ultimate ** Neil Davis - @Nei1dor Aaron Kelton
undefined
Feb 11, 2019 • 42min

Composition Imposition

Combining Objects with Composition Metz, Sandi. Practical Object-Oriented Design in Ruby A weekly podcast about programming, development, and design through the lens of amazing books, chapter-by-chapter. “Combining the qualities of two existing subclasses, something that inheritance cannot readily accommodate.” We talked about inheritance, then modules, now this builds on top of the idea of modules and pushes it further. Composing a bicycle of parts... Bicycle > has A parts Parts has subclasses of - RoadBikeParts and MountainBikeParts Making the Parts Object More Like an Array - This part was freaky Parts Factory Different Configs within the parts factory > an array of all the keys and attributes - road_config - mountain_config Using all this to make a recumbent bike: Once this is all set up you have this incredibly powerful interface of a bicycle composed of parts: Bicycle.new( size: 'L', parts: PartsFactory.build(recumbent_config)) Composition VS Aggregation A Meal is composed of an appetizer - An appetizer does not survive outside of the meal. When the meal is gone by definition the appetizer is gone. A meal is composed of an appetizer. A band is an aggregate of musicians - when the band breaks up the musicians don’t die. “Composition” encompasses both aggregation and composition - “This distinction between composition and aggregation may have a little practical effect on your code.” Deciding Between Inheritance and Composition “Think of it this way: For the cost of arranging objects in a hierarchy, you get message delegation for free.” When in doubt use Composition over inheritance “The general rule is that faced with a problem that composition can solve, you should be biased towards doing so. If you cannot explicitly defend inheritance as a better solution, use composition.” John’s Pick: Book: "It Doesn’t Have To Be Crazy At Work" -> David Heinemeier Hansen and Jason Fried JP: Kahn Academy - digging into math again Next Week: Final Chapter - Designing Cost-Effective Tests

Get the Snipd
podcast app

Unlock the knowledge in podcasts with the podcast player of the future.
App store bannerPlay store banner

AI-powered
podcast player

Listen to all your favourite podcasts with AI-powered features

Discover
highlights

Listen to the best highlights from the podcasts you love and dive into the full episode

Save any
moment

Hear something you like? Tap your headphones to save it with AI-generated key takeaways

Share
& Export

Send highlights to Twitter, WhatsApp or export them to Notion, Readwise & more

AI-powered
podcast player

Listen to all your favourite podcasts with AI-powered features

Discover
highlights

Listen to the best highlights from the podcasts you love and dive into the full episode