64

What is the difference between building an application Outside In vs building it Inside Out using TDD?

These are the books I read about TDD and unit testing:
Test Driven Development: By Example
Test-Driven Development: A Practical Guide: A Practical Guide
Real-World Solutions for Developing High-Quality PHP Frameworks and Applications
Test-Driven Development in Microsoft .NET
xUnit Test Patterns: Refactoring Test Code
The Art of Unit Testing: With Examples in .Net
Growing Object-Oriented Software, Guided by Tests--->This one was really hard to understand since JAVA isn't my primary language :)

Almost all of them explained TDD basics and unit testing in general, but with little mention of the different ways the application can be constructed.

Another thing I noticed is that most of these books (if not all) ignore the design phase when writing the application. They focus more on writing the test cases quickly and letting the design emerge by itself.

However, I came across a paragraph in xUnit Test Patterns that discussed the ways people approach TDD. There are 2 schools out there Outside In vs Inside Out.

Sadly the book doesn't elaborate more on this point. I wish to know what is the main difference between these 2 cases.
When should I use each one of them?
To a TDD beginner which one is easier to grasp?
What is the drawbacks of each method?
Is there any materials out there that discuss this topic specifically?

1

4 Answers 4

52

Inside-Out and Outside-In are fairly rare terms, more often I have heard/read about Classic school and London school.

  • Inside-Out (Classic school, bottom-up): you begin at component/class level (inside) and add tests to requirements. As the code evolves (due to refactorings), new collaborators, interactions and other components appear. TDD guides the design completely.

  • Outside-In (London school, top-down or "mockist TDD" as Martin Fowler would call it): you know about the interactions and collaborators upfront (especially those at top levels) and start there (top level), mocking necessary dependencies. With every finished component, you move to the previously mocked collaborators and start with TDD again there, creating actual implementations (which, even though used, were not needed before thanks to abstractions). Note that outside-in approach goes well with YAGNI principle.

Neither of the approaches is the one and only; they both have their place depending on what you do. In large, enterprise solutions, where parts of the design come from architects (or exists upfront) one might start with "London style" approach. On the other hand, when you face a situation where you're not certain how your code should look (or how it should fit within other parts of your system), it might be easier to start with some low-end component and let it evolve as more tests, refactorings and requirements are introduced.

Whichever you use, more often than not it is situational.

For further reading, there's Google group post with rather interesting discussion on how this distinction (might have) originated and why London might not be the most appropriate name.

5
  • 4
    Interesting. How did you reach the conclusion that outside in TDD is "mockist" TDD? I very much prefer Outside-In thinking and design and thus testing (see softwareonastring.com/2015/01/10/…) yet the Fowler article firmly puts me with Fowler in the classicist camp. While mockist may always use an outside-in approach, you can't turn it around and say that outside-in design and testing is mockist TDD. Outside-in can be and very much is practised by classicist TDD-ers as well. Mar 28, 2015 at 18:32
  • @jimmy_keen - With outside-in, do you at any point replace the mocks in the higher level tests with the later-created actual implementations? Or do you leave them as mocked dependencies and then exercise the the whole production code as an integration test?
    – thehowler
    Oct 22, 2015 at 17:35
  • 3
    I disagree that Classic/Mockist and Inside-Out/Outside-In are related. They are orthogonal. You can use Inside-Out/Outside-In with either. Jun 30, 2017 at 19:05
  • Agree with Daniel. You are likening two taxonomies that are different. Although Outside-in development is often associated with London (mockist) school, it is not always the case. Oct 25, 2017 at 9:54
  • 2
    I don't think this is a correct description of the outside-in process. It's about testing from the public interfaces without coupling to to internals, as much as possible. Aug 23, 2018 at 8:44
19

Short Answer: As usual it will depend on your coding preference and team approach.

Inside out coding is great because you always have something working. The downside is that it doesn’t necessarily help you get to a radically different place. It is harder to chart a course this way. Similarly, writing code outside in has the downside of not necessarily having the benefit of rapid iterative development, and not necessarily seeing all of the opportunities and patterns that may arise from deep in the structure of the code.

I have come to believe that both styles of development are important, and that it is in fact helpful to have a mix of styles on a team. The idea is that inside out is great for creating building blocks, and the outside in thinking provides form structure and direction.

Part of my reasoning is coming from a very popular school of thought that currently promotes iterative development, which is often synonymous with inside out development. I believe iterative development is great when you don’t have too far to go. But I think that big picture thinking, as opposed to a purely iterative process is invaluable to certain types of innovation and to getting to a less obvious place. Properly managed, inside out and outside in together can be a very effective combination.

9

You should add Agile Prinicples, Patterns and Practices in C# to that list. I don't know why he tacked on "in C#" on the end. The books is not the language at all and the only reason it didn't get 5 stars on amazon is from people who were disappointed in C#-ness of his examples.

The author, advocates that whenever possible you should try to write code outside-in and rely heavily on evolutionary design, and I agree with his statement. His reasoning is that as we add functionality, our design will always evolve. If we start with low-level components as features are added, we'll realize those components are not doing what we'd like them to do, or that things need to be moved around. This could get rather expensive especially if every time you move functionality from one class into another, you need to do the same move in all the unit test projects.

On the other hand, if you determine what your application is supposed to do in the first place, you code for external interface. As features get added and code under test grows in size, you refactor your application into more classes, but while this refactoring effort is going on, the original unit tests you've written remain valid. So you start completely on the outside and continue refactoring into more and more low-level classes, while adding additional unit tests to those inner classes, but you would rarely have to move around and rewrite your unit tests.

However, if you identify a specific low-level subsystem that your application will need (and maybe your company already has a need for such subsystem in other applications), this would be the time to start with a low-level building block first and then build the app on top of that.

7

As I see it, the concept of Outside-in development really spreads on 2 levels. Gerard Meszaros briefly describes them as "outside-in design" and "outside-in/inside-out coding".

  • The first level is an organizational and process level. Outside-in design is meant as opposed to top-down (waterfall/taylorist) and bottom-up. With an outside-in approach, we focus on the end user's perspective. We start with story tests, ATDD or BDD tests and go "inward" inferring technical tests and code. So outside-in design is typically what you would do in an Agile context. Dan North has a great talk about BDD, top-down, bottom-up and outside-in approaches.

  • The second level is technical and has to do with applicative layers. Outside-in coding basically means starting from the UI and going inwards to the central layer (usually the business/domain layer). It's meant as opposed to inside-out coding which is starting from the central layer and coding the external layers last.

So you could have outside-in design with either outside-in coding or inside-out coding.

Where I disagree with Meszaros is when he associates inside-out coding with integration testing, arguing that in an inside-out context "we don't actually test the outer software in isolation of the inner software". But I believe nothing prevents you to do so. You can perfectly choose to test your outer layer objects by mocking out the inner layer objects even if the production code for those already exists. You just have to add interfaces and mocks on top of the existing concrete objects instead of writing the interfaces, mocking them and then creating the implementations later as you would do with outside-in coding.

In other words, mockist or classicist style TDD is IMO an orthogonal concern to outside-in/inside out coding. You can perfectly use a mockist style together with an inside out approach. The reason behind this is that mockist/classicist style is about code dependencies while outside-in/inside-out coding is about applicative layers.

Another important thing is that dependencies aren't only across layers, they also exist between objects in the same layer. For instance, you might want to start with one object in your central business layer (inside-out approach) and use mocks to isolate your object from other business layer objects it talks to. This happens a lot with IoC - the abstractions your object depends upon are often declared in the same layer, but concrete implementations are in a different layer.

Robert "Uncle Bob" Martin briefly mentions inside-out coding and how it doesn't necessarily conflict with a decoupled architecture in his post "Clean Architecture".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.