---
title: "Simplicity is Complicated"
url: "https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/simplicity-is-complicated.md"
canonical: "https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/simplicity-is-complicated/"
tags: []
author: "Roy Osherove"
description: "Lesson 4 of 15 in TDD and BDD in Ruby (Day 1 - Basic Building Blocks), 9:33. Free video by Roy Osherove."
usage: "Licensed under CC BY 4.0 — reuse, quote and adapt with attribution (Roy Osherove, link to the original page)."
license: "https://creativecommons.org/licenses/by/4.0/"
---

# Simplicity is Complicated

1. [Courses](https://courses.osherove.com/#courses)
2. [TDD and BDD in Ruby](https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/)
3. Day 1 - Basic Building Blocks

Lesson 4 of 15

Duration: 9:33 [Watch on YouTube](https://www.youtube.com/watch?v=xa3IIbQK8xE)

Learn how to make your test code and production code simpler with some simple rules.

## In this lesson

Roy Osherove explains why he solves things in the [simplest way possible](https://osherove.com/blog/2010/1/6/tdd-4-questions-that-will-help-you-create-the-simplest-thing.html "TDD: 4 questions that will help you create the simplest thing that could possibly work (osherove.com)") but not simpler, since planning too much for the future can make the code bloated and complicated. He measures simplicity visually: a line at the beginning of a method is simpler than one in the middle and less nesting is simpler, as when students replaced all the new delimiters with commas in the first line of the [string calculator](https://osherove.com/tdd-kata-1 "TDD Kata 1 - String Calculator (osherove.com)"). He describes [TDD](https://livebook.manning.com/book/the-art-of-unit-testing-third-edition/chapter-1#sigil_toc_id_27 "Test-driven development (The Art of Unit Testing, 3rd ed., ch. 1)") as breaking down one assumption at a time while wearing two hats, the laziest developer who writes the code and the person who writes the next test that proves an assumption wrong.

## Transcript

1,647 words

[\[00:04\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=4s) Now in the [test-driven development](https://livebook.manning.com/book/the-art-of-unit-testing-second-edition/chapter-1#ch01lev1sec6 "Test-driven development (The Art of Unit Testing, 2nd ed., ch. 1)") process, one of the things that I keep pushing for is simplicity. I keep saying solve things in the [simplest way possible](https://osherove.com/blog/2010/1/6/tdd-4-questions-that-will-help-you-create-the-simplest-thing.html "TDD: 4 questions that will help you create the simplest thing that could possibly work (osherove.com)") but not simpler. And I want to explain what does it mean when I say that something is simple. Now the basic idea is that you shouldn't plan too much for the future because the future is probably going to change. So the risk is that you invest too much in having big upfront design of something and the code becomes bloated and and complicated and then you don't even get the thing that you planned for.

[\[00:39\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=39s) That's a risk that usually we we take a lot. So simplicity is there to try to solve that and also to help us create tests that we might not have thought about. So how do I measure simplicity? It's very hard to measure that but I try to measure it in a visual way. If we have the definition of a method then simplicity at the visual level is something that is shorter and

[\[01:09\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=69s) Less wide. I'm going to say so it has to still be readable. But if you think about it, if you have an existing method and to solve the current test, you want to you can either add a line at the middle of the method or add a line at the beginning of the method. Which one would be simpler? What do you think? At the beginning? Why? >> That's where you start reading. >> That's where you start reading. Well, it's instinctive to say, "Yeah, it's simpler." But if you think about it, it is technically simpler because if you put a line in the middle of a method,

[\[01:47\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=107s) Until you get to that line, you have to go through other lines of code. So to be able to get to that line, you have to perform more operations. More operations is more complexity. If the solution is just a single operation, it's a simpler solution. If your solution needs you to put the line exactly in the right place between two different pieces of execution, it's a more complicated solution. Make sense? At the same time, the more nested something is inside ifs, inside loops, the more complicated it is.

[\[02:20\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=140s) The more complicated it is visually, the more complicated it is probably in terms of complexity. And we can talk about there are algorithms for measuring the complexity of code. Do you do you remember what that's called something complexity? I don't remember the the name now but I do remember it usually but not in mornings. In mornings I usually remember only 50% of the things. So I try to make it the important stuff. So the more nested things are the more complicated they are because they have to happen inside a loop inside an if inside a try catch.

[\[02:57\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=177s) That's more complicated than not having it inside an a for loop at right. So the more to the right things are the more complicated they are. So for example, one of the ways that some that some of my students have solved the [string calculator](https://osherove.com/tdd-kata-1 "TDD Kata 1 - String Calculator (osherove.com)") problem with changing the parame the the the the delimiters is that instead of parsing for the limiters and splitting based on multiple different delimiters, I had a couple of students that just said, okay, when I have a different delimiter, the first line of the method is to replace

[\[03:33\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=213s) All the new delimiters with a comma. And now I don't have to change any line of code because I can already handle commas. Right? So once I have a common delimiter, the first line of code is to replace all the new delimters with commas. And that's it. If you think about it, it's a very very simple solution. It's actually much less complex than trying to find multiple delimters. And so the first line of the method becomes the focal point of changing the the delimiter problem. And what happens is that the that line becomes like cleanup, right?

[\[04:07\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=247s) Get rid of the new lines, prepare the string so that you can handle it just like you used to handle it when it only had commas. So you evacuate the problem into a separate method and it's just the first line of code. And that's a very very simple way to think about it. So when you approach a solution and your solution is to add something at the middle of the method, your approach should be could there be something at the beginning of the method that I could do that would be simpler and that's something that's hard to come by this instinct.

[\[04:40\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=280s) That's one of the things that we will practice more and more questions. So that's one way to look at simplicity. But there's another way. Test-driven development is the continuous breaking down of assumptions in your code. If you think about it, when you write code without TDD, what we are trying to do as developers is to write code as generically as possible. A code that can handle almost anything.

[\[05:10\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=310s) It doesn't know what's going to happen. Whatever the input is, it could be strings, it could be commas, it could be anything, it could be whatever. But when we try to do things in a test-driven way, one of the best ways to accomplish small steps is to decide on having as many assumptions as possible in the code at the beginning. An example is the input will always be empty. That's the first test. So I'm assuming the input will always be empty. And then when that test passes, because I'm just returning zero,

[\[05:44\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=344s) I don't need to check an if because I'm assuming that it will always be empty. Then I can then write a new test that says, actually that's wrong. If I send in a number, that test will fail. And so I'm actually telling the person who wrote the test that they had one assumption too many. And so TDD is a continuous effort in breaking down one assumption at a time and each test breaks down one assumption hopefully. It helps if you think about writing test-driven development when where you are the person who writes the tests and the code but it's actually two people.

[\[06:22\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=382s) You wear two different hats. The person who writes the code makes as many assumptions as possible is the laziest developer in the world has to go home in five minutes. Okay. What would they do? They can just assume. You didn't tell me it was never going to be empty, right? You just told me, look, here's a failing test with an empty string. Okay, there are no other tests. So, I'm just going to assume that's an empty string always. No need to check with an if. Okay, bye. I have to go home. And then you switch hats and say, ah, actually that's not good enough.

[\[06:53\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=413s) That assumption is not always true. For example, I send in a number. And then you switch hats again, okay, a number. So I can assume that if it's not empty, it's definitely that number. And then you write another test says, you can't always assume it's always one, what if I send in two? What if I send in two numbers, etc., etc., etc. So think of it like a wall where you take it down brick by brick, and each brick is an assumption. And what you end up with is the same generic code that you would have ended up with anyway.

[\[07:25\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=445s) But every piece of that code is tested and has a reason to exist. There was a test somewhere that says that assumption cannot be made. Yes, you probably need to loop because you don't know how many numbers there are. But yesterday when we talked about the string calculator, I urged you not to loop. And that's one of the reasons because I wanted you to make the assumption that there are exactly two numbers. And that would force you to write a test that said you can't assume there are always two numbers. Here's three numbers.

[\[07:57\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=477s) Okay, you can't assume the delimiter is always a comma. Here's a different delimter. You can't assume that the numbers are a single character. Here's a number with two characters, etc., etc., etc. So, the more assumptions you learn to make in your code while test driving, the more test you will think about because you are critiquing your own code and saying, I don't like that code. And when we had that first instinct of saying just return zero, just return one, that instinct is the instinct that will cause you to write the test.

[\[08:29\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=509s) It says that's a bad assumption. But we want to make that assumption because we it forces us to write the tests. The the the worst way to write test is when the person who's writing the tests is the person who's writing the code that's being tested. I think we all know that developers should not be trusted to test their own code because they are not objective. By making the assumptions, we are forcing ourselves to be somewhat objective about our code and testing for failure instead of testing for success,

[\[09:05\]](https://www.youtube.com/watch?v=xa3IIbQK8xE&t=545s) Which is the best way of testing, making sure the code doesn't work and then proving the test wrong instead of the other way around. So that's the that's kind of the way because we know we cannot trust ourselves because we always want things to work. We make as many assumptions as possible and we're breaking down through tests. And that's that's one way we make sure that our tests are actually testing the right things and that we don't forget to test some

## Related

- [Measuring Simplicity in TDD](https://osherove.com/blog/2011/1/20/measuring-simplicity-in-tdd.html) · osherove.com

    Roy's post on measuring the simplicity of a solution by how high in the function the code is, how indented it is and how many assumptions it makes, the rules taught here.

- [TDD: 4 questions that will help you create the simplest thing that could possibly work](https://osherove.com/blog/2010/1/6/tdd-4-questions-that-will-help-you-create-the-simplest-thing.html) · osherove.com

    Roy's four questions for finding the simplest thing that could possibly work, the 'as simple as possible but not simpler' idea of this lesson.

- [TDD Kata 1 - String Calculator](https://osherove.com/tdd-kata-1) · osherove.com

    The String Calculator kata, whose delimiter requirements are the lesson's example of simple and complicated solutions.

- [TDD in .NET course - Day 2 Learnings](https://osherove.com/blog/2011/8/11/tdd-in-net-course-day-2-learnings.html) · osherove.com

    Roy's notes from a TDD course day, including TDD as removing assumptions from the code one by one, as described in this lesson.

### Also linked in this lesson

#### The Art of Unit Testing, 3rd ed.

- [Test-driven development](https://livebook.manning.com/book/the-art-of-unit-testing-third-edition/chapter-1#sigil_toc_id_27), ch. 1

#### The Art of Unit Testing, 2nd ed.

- [Test-driven development](https://livebook.manning.com/book/the-art-of-unit-testing-second-edition/chapter-1#ch01lev1sec6), ch. 1

[Previous lesson The Basics of RSpec](https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/the-basics-of-rspec/) [Next lesson Common Questions and Answers about Test Driven Development](https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/common-questions-and-answers-about-test-driven-development/)


---

## About the author

**Roy Osherove**: Senior Solutions Architect at AWS working on AI for production and AI-driven development; author of The Art of Unit Testing and Elastic Leadership, with about 20 years of consulting and training on unit testing, TDD, team leadership and continuous delivery.

### Sites

- [RobotPaper](https://robotpaper.ai/): This blog: AI patterns and anti-patterns, AI and coding agents, and engineering leadership.
- [osherove.com](https://osherove.com): Roy's personal site. Author of The Art of Unit Testing and Elastic Leadership; consulting and training on unit testing, TDD, team leadership and continuous delivery, plus about 20 years of blog posts.
- [The Art of Unit Testing](https://www.artofunittesting.com): The Art of Unit Testing, 3rd Edition (Manning): readable, maintainable, trustworthy unit tests, plus TDD workshops in C#, JavaScript, Java and Kotlin.
- [5whys.com](https://www.5whys.com): Roy's writing on software team leadership: self-organizing teams, surviving chaos, learning mode and the Elastic Leadership model.
- [Pipeline Driven](https://pipelinedriven.org): Continuous delivery and DevOps practices: build patterns, pipeline-friendly testing, DevOps metrics and enterprise DevOps.
- [Elastic Leadership](https://www.elasticleadership.com): Elastic Leadership, Roy's framework for software team leaders (survival, learning and self-organizing modes).

### Social

- X: https://x.com/royosherove
- LinkedIn: https://www.linkedin.com/in/osherove/

### Contact

- Contact form: https://forms.gle/jQSx5KoXvrVA1JCK7

### License

Licensed under CC BY 4.0 — reuse, quote and adapt with attribution (Roy Osherove, link to the original page). License: https://creativecommons.org/licenses/by/4.0/
