πŸš€ Does TDD Really Lead to Good Design? (Sandro Mancuso)

DevTernity Conference
9 Dec 201857:59

Summary

TLDRThe speaker reflects on their 14-year journey with Test-Driven Development (TDD), emphasizing its impact on good software design. They discuss the TDD cycle, the importance of design decisions, and the emergence of design through TDD. The talk explores different TDD styles like Classicist and Outside-In, and how they influence design. It also touches on the use of mocks as a design tool and the concept of 'inflection point' in design to balance simplicity and future-proofing. The speaker concludes by highlighting the importance of understanding design principles to effectively use TDD.

Takeaways

  • 🎯 The speaker emphasizes the importance of Test-Driven Development (TDD) in shaping good software design over the past 14 years.
  • πŸ”„ The speaker's initial skepticism towards TDD transformed into a deep appreciation after experiencing the benefits of its structured approach to design and development.
  • πŸ“š Influenced by the book 'Thinking Fast and Slow', the speaker began to question and reassess the foundations of his professional practices, including TDD.
  • πŸ€” The speaker highlights the need for developers to understand where design decisions come from when test-driving code and the impact of different TDD styles on design.
  • πŸ”§ TDD is described as a workflow rather than a design tool itself, with design emerging through the process of writing tests and making them pass.
  • πŸ”‘ The speaker identifies 'Just-in-Time Design' as the initial design decisions made before TDD, which are critical for setting the direction of the code.
  • 🌟 The Classicist and Outside-In approaches to TDD are explained, showing how they both follow the TDD cycle but differ in where and how design decisions are made.
  • πŸ›  The use of mocks in TDD is presented as a design tool to help define interfaces and interactions between components, rather than just a testing tool.
  • 🧐 The importance of understanding the domain and business requirements is underscored for making informed design decisions before writing tests.
  • πŸ” The concept of 'Inflection Point' in design is introduced, which is about finding the balance between simplicity and future-proofing the software without over-engineering.
  • πŸ”„ The speaker concludes that TDD, when combined with a good understanding of design principles, can greatly enhance the development process and result in higher quality software.

Q & A

  • What is the main topic of the speaker's talk?

    -The main topic of the talk is the speaker's journey and insights into Test-Driven Development (TDD), its impact on software design, and the different styles of TDD.

  • How long has the speaker been involved in software design?

    -The speaker has been involved in software design for 22 years.

  • What inspired the speaker to initially try TDD?

    -The speaker was inspired to try TDD after a conversation with someone who suggested that TDD could complement the speaker's interest in software design.

  • What was the speaker's initial reaction to TDD?

    -The speaker initially thought TDD was weird and unnecessary, believing it to be too slow and cumbersome for their design process.

  • What book impacted the speaker's perspective on TDD and design?

    -The book 'Thinking, Fast and Slow' by Daniel Kahneman had a profound impact on the speaker's perspective on TDD and design.

  • What does the speaker mean by 'emergent design'?

    -'Emergent design' refers to the design that evolves from the code as the system is being developed, rather than being pre-planned in detail.

  • What are the two main styles of TDD mentioned in the talk?

    -The two main styles of TDD mentioned are 'Classicist' and 'Outside-In'.

  • What is the difference between 'Classicist' and 'Outside-In' TDD approaches?

    -The 'Classicist' approach focuses on writing a failing test and making it pass with the simplest possible code, then refactoring, while the 'Outside-In' approach starts from the outer layers of the system and works inwards, defining interfaces and interactions using mocks.

  • How does the speaker view the role of design in TDD?

    -The speaker views design in TDD as a combination of 'just-in-time design' decisions made upfront and 'emergent design' that evolves through the TDD cycle.

  • What is the significance of understanding 'composition' vs. 'aggregation' in TDD?

    -Understanding 'composition' vs. 'aggregation' is crucial in TDD for determining the unit under test and making informed design decisions about class responsibilities and interactions.

  • What is the 'inflection point' in software design according to the speaker?

    -The 'inflection point' in software design is the optimal balance between starting with a simple solution and preparing for future requirements without over-engineering or under-engineering.

Outlines

00:00

🎨 Embracing TDD and Software Design Evolution

The speaker reflects on their journey with Test-Driven Development (TDD) and software design, starting from their initial skepticism about TDD to full adoption. They discuss the impact of TDD on design, the importance of understanding different TDD styles, and how TDD can lead to good design. The speaker emphasizes the need to question assumptions and to pay attention to where design decisions come from during test-driving code.

05:02

πŸ›  Exploring TDD Styles and Their Impact on Design

This paragraph delves into the different styles of TDD, such as Classicist and Outside-In, and how they affect the design process. The speaker explains the Classicist approach, which involves writing a failing test, making it pass with the simplest solution, and then refactoring. They also discuss the importance of understanding the type of feature being built and how it influences the choice of TDD style, ultimately affecting the design outcome.

10:03

🌱 Just-In-Time Design and Emergent Design in TDD

The speaker introduces the concepts of Just-In-Time design, where design decisions are made as TDD progresses, and Emergent design, which arises from the iterative process of writing and refactoring tests. They discuss the evolution of design from simple tests to more complex systems, emphasizing the importance of making upfront design decisions before starting TDD to avoid refactoring challenges later on.

15:05

πŸ” Analyzing Unit Size and Design Decisions in TDD

The paragraph focuses on the importance of determining the appropriate size of a unit under test in TDD. It discusses the challenges of growing units that encompass multiple classes and how this can complicate testing and refactoring. The speaker highlights the need to understand the difference between composition and aggregation when making design decisions, which can guide the choice of unit size in TDD.

20:08

πŸ›€οΈ Navigating Design Decisions and TDD Workflows

The speaker discusses the workflow of TDD as a design tool, emphasizing the importance of making design decisions before writing tests. They explore the use of mocks in TDD as a way to define interfaces and relationships between classes, and how this can lead to better design. The paragraph also touches on the challenges of maintaining tests as the system evolves and the need for clear design decisions to avoid widespread test failures.

25:11

πŸ—οΈ Applying Composition and Aggregation in TDD Design

This paragraph examines the concepts of composition and aggregation in the context of TDD, explaining how these relationships inform design decisions. The speaker provides examples of how to determine whether classes should be tested together or mocked, and how understanding these relationships can lead to more cohesive and maintainable code.

30:14

πŸ›’ Checkout Scenario: A Deep Dive into TDD Design

The speaker presents a detailed example of a checkout scenario to illustrate TDD design decisions. They discuss the complexity of payment processing, order management, delivery, and notifications, and how to apply TDD to each aspect. The paragraph emphasizes the importance of understanding business requirements and how they influence the design and testing process.

35:15

πŸ”— Understanding Dependencies and Design in TDD

The paragraph explores the dependencies between classes in TDD and how they affect design. The speaker discusses the use of mocks to define interfaces and the importance of understanding the business domain to make informed design decisions. They also highlight the need to balance the level of abstraction in the system to avoid overly complex or overly simplistic designs.

40:16

πŸ“ˆ Finding the Inflection Point in TDD Design

The speaker introduces the concept of the 'inflection point' in TDD, which is the optimal balance between simplicity and future-proofing in design. They discuss the importance of understanding the reasons behind design decisions and how to optimize for changeability or other factors without over-investing in the design upfront.

45:18

🌟 The Power of TDD and Design Mastery

In the concluding paragraph, the speaker emphasizes the transformative power of TDD and the importance of mastering design skills to make TDD more effective. They encourage understanding different TDD styles and having a solid foundation in design to achieve synergy between TDD and design, ultimately leading to better software development practices.

Mindmap

Keywords

πŸ’‘Test-Driven Development (TDD)

Test-Driven Development (TDD) is a software development methodology where tests are written before the actual code, ensuring that the code meets the desired requirements. In the video, the speaker discusses their journey with TDD, emphasizing its role in achieving good software design. TDD is central to the talk as the speaker reflects on how TDD has influenced their design decisions over the years.

πŸ’‘Agile

Agile is a set of principles for software development that emphasizes flexibility, collaboration, and customer feedback. The speaker mentions getting in touch with Agile about 14 years ago, which signifies a shift in their approach to software development. Agile methodologies, including TDD, are highlighted as catalysts for rethinking traditional software design processes.

πŸ’‘Extreme Programming

Extreme Programming (XP) is a type of Agile software development characterized by tight feedback loops, simplified design, and frequent releases. The speaker recalls their initial encounter with XP, which introduced them to TDD. XP is presented as a precursor to the speaker's adoption of TDD and a significant influence on their development practices.

πŸ’‘Design Patterns

Design Patterns are reusable solutions to common software design problems. The speaker questions the role of TDD in relation to design patterns, pondering whether TDD leads to good design or if the design decisions are influenced by pre-existing knowledge of design patterns. The concept is integral to understanding the speaker's exploration of the relationship between TDD and software design.

πŸ’‘Refactoring

Refactoring is the process of restructuring existing computer code without changing its external behavior to improve nonfunctional attributes of the software. The speaker discusses refactoring as a phase in the TDD cycle where the code is improved for readability and maintainability. It is depicted as a critical step in the evolution of software design through TDD.

πŸ’‘Emergent Design

Emergent Design is a design approach where the design of a system emerges through continuous refactoring and adding new features. The speaker refers to this concept when explaining how design evolves in TDD, particularly in the classicist approach, where the initial design is simple and becomes more complex as more tests are added.

πŸ’‘Classicist TDD

Classicist TDD is one of the TDD styles that focuses on writing a failing test and then making it pass with the simplest possible code. The speaker contrasts this with outside-in TDD, discussing the differences in how design decisions are made and how the system evolves in each approach. Classicist TDD is used to illustrate the concept of emergent design.

πŸ’‘Outside-In TDD

Outside-In TDD is another TDD style where tests are written from the perspective of the system's external interactions. The speaker explains this approach as starting from the system's boundary and working inwards, making design decisions about which behaviors to keep within a class and which to delegate to others. It's presented as a methodical way to define interfaces and system boundaries.

πŸ’‘Mocking

Mocking is a technique used in TDD where certain objects or functions are simulated to isolate the unit of code being tested. The speaker discusses mocking as a design tool that helps in making decisions about the system's architecture and the interactions between components. It's highlighted as a means to define interfaces and understand the system's composition and aggregation.

πŸ’‘Composition vs. Aggregation

In object-oriented design, composition and aggregation are two different types of relationships between classes. The speaker uses these concepts to explain how to decide the boundaries of a unit in TDD. Composition implies a part-whole relationship, where the parts (classes) are tightly coupled to the whole, whereas aggregation suggests a looser connection. Understanding these relationships helps in making informed design decisions during TDD.

πŸ’‘Design Decisions

Design Decisions refer to the choices made during software development that affect the system's architecture and functionality. The speaker emphasizes the importance of making these decisions before writing tests in TDD. The narrative of the video revolves around how TDD influences or is influenced by these design decisions, and the speaker's journey to understanding their role in the development process.

Highlights

Introduction to the speaker's journey with TDD and software design over 22 years.

The speaker's initial skepticism towards TDD and how it was overcome through a month-long trial.

The realization that TDD leads to good design, a concept the speaker has repeatedly emphasized over the years.

The influence of 'Thinking Fast and Slow' on the speaker's approach to questioning professional practices, including TDD.

The importance of understanding where design decisions come from during test-driven code.

The distinction between different styles of TDD and their impact on software design.

The classicist TDD approach and its focus on simplicity and emergent design.

The outside-in TDD approach and its emphasis on behavior and design from the system's boundary inward.

The role of composition and aggregation in determining the unit of test in TDD.

The use of mocks as a design tool to define interfaces and interactions in TDD.

The concept of 'just-in-time design' as opposed to emergent design in TDD.

The importance of making design decisions before writing tests to avoid wasteful refactoring.

The challenges of maintaining tests as the system evolves, especially with larger units of test.

The idea of using TDD to explore and understand complex business flows and requirements.

The balance between upfront design and letting design emerge through TDD.

The 'inflection point' in design, where the balance between simplicity and future-proofing is considered.

The conclusion that TDD is a phenomenal tool when combined with a solid foundation in software design.

Transcripts

play00:00

[Music]

play00:16

hello so the reason for this talk one of

play00:23

the reasons that I'm doing on the

play00:23

whiteboard is thought I could not

play00:25

prepare these lights right so it was too

play00:27

complicated for me to go through

play00:29

everything I wanted to say but I think I

play00:33

went through phases in my developer

play00:37

career since the beginning I was very

play00:40

inch into software design since I

play00:42

started that goes back 22 years ago

play00:47

about 12 years ago almost 14 years ago

play00:52

actually when I moved to the UK someone

play00:55

that was when I got in touch with the

play00:58

whole agile thing I heard about this

play01:00

thing about extreme programming I

play01:02

thought it was very cool but it was too

play01:05

weird and and then someone said like you

play01:09

like so much software design why don't

play01:11

you try this thing called TDD and I said

play01:14

because I don't need that why would I do

play01:17

that it sounds very stupid to me and

play01:19

then someone said you know but try it

play01:22

wholeheartedly really really try it for

play01:25

a month it was painful extremely painful

play01:29

because I felt that everything that I

play01:31

was doing was it slow so I can visualize

play01:34

the design already I can visualize the

play01:36

solution so why don't I just go for it

play01:38

and if people really care too much about

play01:42

it I write a test afterwards and then

play01:43

someone said nope do it and I've done it

play01:47

and I've done it for a few months close

play01:51

to three months and I never looked back

play01:54

so I want to make it clear in this talk

play01:57

that's all though I'm talking about the

play02:01

design aspects of TDD or how to evolve

play02:03

an application how to evolve the design

play02:06

of an application through TDD this is

play02:09

not a talk against TDD I just make it

play02:12

very very clear what happened was for me

play02:15

I said many times if you go back to some

play02:17

of the talks that I have or

play02:19

things that I read I wrote you will see

play02:21

me over the past twelve years saying TDD

play02:25

leads to good design TDD leads to good

play02:28

design and I've been repeating that over

play02:30

and over and over again about two or

play02:33

three years ago I read a book called

play02:37

Thinking Fast and Slow Fast and Slow

play02:45

this book was I slapping my face it made

play02:51

me realize that I do a lot of things

play02:53

without questioning that I was not

play02:55

special that I was not smarter than

play02:57

anyone else

play02:58

but it really made me rethink about

play03:02

everything I took for granted including

play03:05

my professions like I do TDD why do I do

play03:08

that why do I think that it leads to

play03:10

good design and then I and I start

play03:12

paying attention of my design decisions

play03:16

while one test-driving code where do

play03:18

they come from

play03:19

which DD style do I use and then I also

play03:22

was paying attention at other people

play03:25

other developers where did the design

play03:29

decisions come from when they are test

play03:31

driving their code there are different

play03:33

styles of TDD how do they impact the

play03:35

design so and then there's a lot of

play03:38

people that I respect that use different

play03:40

approaches and they get stuff done but I

play03:43

was interested to know where the design

play03:45

comes from so why I don't think that

play03:51

that puzzled me is did it is a very

play03:54

simple thing right so normally the flow

play03:57

would be your writer write a failing

play04:00

test you make it pass you make it better

play04:03

right in a nutshell this is the TDD

play04:08

cycle so we quite often say that this is

play04:12

a design tool I'm changing my mind a bit

play04:15

I prefer to think about as a software

play04:20

design a software development workflow

play04:22

is a way of working design needs to

play04:26

emerge somehow but this I love this read

play04:30

them one of the things that I like the

play04:31

most in TDD

play04:32

is this rhythm working very small

play04:34

increment always in safe steps right I

play04:36

always know where I am but I treat that

play04:39

more as a workflow than a design and

play04:42

I'll try to explain why so normally in

play04:50

the traditional TDD approach so there

play04:53

are two just to give some context there

play04:57

are that's not I haven't tried that I

play05:01

tried all the pans and stuff I just

play05:03

didn't try to chewy raise anything so

play05:05

there are normally two is it big enough

play05:12

at the back classicist so one of these

play05:17

stars there are there are different led

play05:18

styles this is important to understand

play05:20

because one of the reasons that people

play05:22

don't they everyone understands this but

play05:26

one of the reasons that they don't use

play05:29

that in a nice way to emerge you to

play05:31

create good designs is because they they

play05:35

don't understand where the design should

play05:36

come from and also why there are

play05:38

different types of things that we are

play05:40

building we might be building an

play05:42

algorithm we might be building a

play05:43

business feature you might be building

play05:46

integration with other systems the the

play05:49

type of feature that we are building

play05:51

impact or well choosing one of the CTD

play05:56

styles if it's if that's these Styles

play05:59

not suitable to what you are building

play06:01

you have problems and I think that a lot

play06:03

of people don't understand that there

play06:05

are different styles of T DT so one of

play06:07

them is called classicists there is the

play06:08

original one created by Kent back that

play06:11

was back in the late nineties if I'm not

play06:13

wrong

play06:13

so and the other one is called outside

play06:16

in outside in so they are significantly

play06:23

different in these styles they both

play06:26

follow this loop in here but in the

play06:31

classicist approach normally what we do

play06:34

we write a failing test and you go as

play06:36

fast as possible from red to green you

play06:39

do the simplest thing could possibly

play06:40

work just make it work

play06:43

duplicate hard code do what

play06:45

ever but just make it work once it works

play06:49

then you go to the refactoring phases

play06:51

see let's see the mess that I created if

play06:54

I create the master I can identify so ok

play06:57

now it's time to clean up so design in

play07:00

the in the closest approach happens here

play07:06

this is what I call emergent design when

play07:10

you are building the system when you are

play07:12

trying to make it work you don't care

play07:13

about anything you just care about

play07:15

making it work once it works you evolve

play07:20

your design how do you do that

play07:22

so TDD doesn't prescribe I even asked

play07:25

Ron Jeffries a few years ago it's like

play07:28

what is the guideline here because this

play07:30

is the problem that I have when I got to

play07:33

this stage what we are saying is like I

play07:37

forgot to start the timer and well what

play07:43

is the guideline here so make it better

play07:45

it's a bit too generic one of the things

play07:48

that people take as guidelines they will

play07:51

talk about the four rules of simple

play07:55

design so they will be like pass all the

play08:00

tests reviews intention no duplication

play08:03

and fewer elements JB is probably

play08:07

somewhere in the audience he has a

play08:09

slightly different version of it that

play08:10

summarizes a thing that reduce that to

play08:12

two steps and stuff is very interesting

play08:14

Murat Mike my main concern

play08:16

point was is this part of this or this

play08:22

this is just a design guideline where

play08:24

does it come

play08:25

what about solid were about DDD were

play08:28

about coupling and cohesion or about

play08:31

Canadians were about all those other

play08:32

things design patterns so for me those

play08:37

design guidelines are not necessarily

play08:39

part of TDD TDD gives you this workflow

play08:42

as say hey we specify what you want what

play08:44

you're you want the code to do make sure

play08:47

that you make it work and then you get

play08:49

better but this is vague for me in order

play08:53

for for me for people to do it just to

play08:56

be successful with TDD

play08:58

they need to understand this so what

play09:06

people say well but it's helping with

play09:11

your design it certainly has an

play09:14

influence because you are forced to

play09:15

specify first the the boundaries and

play09:21

stuff but when you think about for

play09:23

example there is a business there is a

play09:25

behavior that I need to add to my code

play09:28

when I write this test I need to design

play09:31

decide which class or function will

play09:34

contain that code what is the interface

play09:37

what is the parameters was the return

play09:39

type which layer this class is in the

play09:42

bigger picture those are all design

play09:44

decisions that regardless which is style

play09:47

of to disease you are using you need to

play09:49

make up front oh you already decided

play09:51

where the codes gonna be what we will

play09:54

help you in here is the internals of

play09:56

that code that you might further define

play09:59

but the inception the trigger where the

play10:03

code that will trigger that behavior you

play10:05

are designing what I called just in time

play10:07

so the the code that emerge from the

play10:11

refactoring I call emergent design but

play10:13

the design decisions that we make

play10:15

before TDD I called just-in-time design

play10:19

so but we very often we don't think that

play10:24

classes or defining the class to find a

play10:27

method they're not with parameters and

play10:29

return type they are all design so let

play10:33

me explore this a bit so there is a

play10:37

class assisted eg another name that some

play10:39

people give to do a church across assist

play10:42

is the Chicago School some people call

play10:47

Detroit school Cleveland school

play10:49

somewhere in the US a school outside in

play10:52

quite often is also called London school

play11:00

or ma kissed which I don't like at all I

play11:04

really don't like these as a name

play11:07

but there is a difference why those two

play11:11

things were created all those different

play11:14

styles there is another one that I don't

play11:15

like to put it it's called TDD as if you

play11:17

meant it I think that is too crazy to

play11:19

talk about so the one thing that is

play11:25

important to understand is that those

play11:27

different TDD styles they are not

play11:30

opposing each other there's not like

play11:32

either or most people there are the the

play11:37

best 3d practitioners that I know they

play11:39

normally mix and match the truth right

play11:41

okay so basically the decision is

play11:43

according to what we are doing we will

play11:45

pick one style and it gets so automatic

play11:48

in our heads that we don't even think

play11:49

about that anymore we just oh this is

play11:52

what I want to build I'm gonna test

play11:54

drive this way this that model it's

play11:56

gonna this is what I want to build I'm

play11:58

gonna test drive in a different way so

play11:59

that is the the difference but like let

play12:02

me try to explain to you let me focus

play12:04

first on the classicist approach let's

play12:10

talk about how design emerge in these

play12:12

kind of TDD normally what you do here

play12:19

are your tests you write your first test

play12:22

according to this test you need to put

play12:25

that behavior somewhere so the class

play12:29

emerged so this test is forcing you to

play12:32

think about where do I want to put the

play12:34

behavior that I'm test driving so this

play12:36

is the first design decision where the

play12:39

behavior goes the second design decision

play12:42

is how do i trigger this behavior that's

play12:44

when the public method emerged so what

play12:50

should I pass if anything to this method

play12:53

that's when the parameters in word do I

play12:55

expect something back that's when there

play12:58

is return type in cause assists in

play13:00

general well but it's what we call a

play13:03

state-based test what do I mean by that

play13:07

normally you will have an input so you

play13:10

instantiate you put your system in a

play13:12

certain state will you invoke your

play13:15

system with some data and you check the

play13:18

next state so

play13:21

so you are always checking state so

play13:22

normally the the test here is an assert

play13:24

that something is equals something else

play13:26

or different from some something else so

play13:28

this is what is called a state base the

play13:31

thing so how does design evolve we write

play13:34

a very simple test we make the simplest

play13:36

thing could possibly work and then

play13:38

probably in the first test there's not

play13:40

much a refactor you probably hard-coded

play13:42

or did something like that and then what

play13:44

happens is we start adding tests and as

play13:47

we add more test these things becomes

play13:50

more complicated and it evolves so every

play13:53

test that I adhere more behavior will

play13:55

come to here at some point this public

play13:58

method will be a bit complicated there

play14:01

will be a lot of things going on in one

play14:03

of the refactoring phases what we are

play14:05

going to do we are going to extract a

play14:06

method like private if you're talking

play14:10

about functions you might extract

play14:11

another function and then you keep on

play14:13

doing tests and then you are adding you

play14:17

are extracting these private methods and

play14:19

they are meant to just explain what the

play14:22

public method is doing so the public

play14:24

method instructions become more

play14:26

high-level in terms of abstraction and

play14:29

the details goes to the private but at

play14:32

some point as the system grows quite

play14:36

often we start having a need to test

play14:38

these private methods we start adding so

play14:40

much behavior in here that it's becoming

play14:43

a bit complicated well the class is

play14:45

becoming messy and then what we end up

play14:47

doing one of the refactoring stages so

play14:48

you know let's extract these private

play14:52

methods to another class and that's when

play14:59

your design is started following the

play15:02

difference the the the impact that this

play15:04

has is that these started as a unit so

play15:07

there is a there's we always discuss

play15:09

what is the size of a unit what is the

play15:11

unit under test in course this is this

play15:14

is more vague so well I would say that

play15:17

the other one is also but like it starts

play15:20

with a class or a function and as we

play15:22

extract what happens is that the unit

play15:25

under test becomes bigger and that's

play15:28

fine so

play15:34

in systems in the closest approach very

play15:37

rarely we use mocks right so we just

play15:39

test the whole thing as a unit and we

play15:42

keep evolving like that one of the

play15:47

beauties of this style of TDD is that

play15:49

there's no upfront design so we just use

play15:52

emergent design so there's there's a

play15:54

bare minimum a fart from upfront design

play15:56

that is the definition of this class

play15:59

I'll talk about class and methods

play16:00

because it's easier and in the

play16:03

definition of the method but everything

play16:05

else emerged from the code you have and

play16:08

this is a good thing because this

play16:10

constraint over engineering you only

play16:14

design just enough for what we need and

play16:16

the design emerge from your code so it's

play16:19

much easier to do this style because

play16:22

this is style doesn't know about

play16:23

internals it knows inputs and outputs so

play16:26

writing tests like that is much easier

play16:28

evolving these is a little bit easier

play16:32

the what how when do I use this style

play16:40

when I want to explore so when I want to

play16:46

explore example I have a small algorithm

play16:49

I know that given this input I expect

play16:52

this output I don't know what ISM in

play16:54

reaching data whatever it is calculates

play16:57

a discount or whatever that is right so

play16:58

there will be some data coming in some

play17:01

processing enrichment whatever that is

play17:02

and there will be some data coming out

play17:04

different inputs different outputs when

play17:06

I when I have this kind of situation I

play17:09

like to use this style and also when for

play17:14

example sometimes you have there is an

play17:16

input and there is an output but it's a

play17:17

very complex logic or flow to come up

play17:20

with these transformation from input to

play17:22

output but there's no domain concepts

play17:25

there's no nouns and verbs I cannot

play17:27

really have uncurse in terms of domain

play17:30

so when I in things like that you cannot

play17:32

visualize a solution so this is style

play17:35

working very small increments and let

play17:37

that code emerge is when I use this or I

play17:41

prefer this style

play17:43

so things get very complicated if you

play17:48

try to apply this style to business

play17:53

features or to see some that have a more

play17:55

complex domain let's assume that this is

play17:58

feature one right so we started like

play18:00

that and then you have feature two and

play18:03

let's assume that this is your domain

play18:04

yeah so feature two comes along and then

play18:08

you're gonna write some tests and then

play18:11

for this feature here you're gonna start

play18:13

from your module D and you start adding

play18:17

behaviors start adding turn starting

play18:19

test so these gets a bit complicated a

play18:22

few private methods are created at some

play18:25

point you decide to move one of them to

play18:27

Class E and then you say if those

play18:33

classes are as soon as in your domain a

play18:38

class is extracted now this class here

play18:42

that the lifecycle of this class is

play18:45

detach it from where it came from as you

play18:49

evolve your domain those things now our

play18:52

concepts our domain concepts and you

play18:55

might want to reuse some of them and you

play18:58

might be you might be not that you will

play19:00

depend of the complexity of your domain

play19:02

and and how features interrelate but you

play19:06

might be in a situation where now

play19:10

feature one in the future too they share

play19:16

let's say these product validation these

play19:20

whatever whatever this is right so there

play19:24

might be because these now is a domain

play19:26

concept and is used in different future

play19:28

so this has a strong role in your domain

play19:31

let's say there is some sort of a

play19:33

discount calculator for some ferony in a

play19:36

insurance company calculating the policy

play19:38

the premium and the discount is quite

play19:40

complex there's a tons of data that you

play19:42

need to analyze in order to calculate

play19:44

those things and you might need to even

play19:47

access different systems so you might

play19:49

have a feature as your domain gets

play19:53

bigger those domain concepts

play19:56

end up growing and there might be a

play19:59

feature that will make this class evolve

play20:02

and one of these evolutions might be you

play20:07

should go to a database or chu use class

play20:11

F that will go to an external system

play20:17

somewhere in all of a sudden because

play20:21

everything is using the real class and

play20:23

you're not using marks anywhere as soon

play20:25

as I evolve this class feature one is

play20:29

broken future is broken

play20:31

the tests are broken and then the

play20:34

refactoring so what started very simple

play20:37

writing very simple tests as your domain

play20:40

evolves those tests become more and more

play20:42

difficult to maintain because your units

play20:44

are growing and you might have a need a

play20:47

dependence here across features in every

play20:50

now and again you have tones of tests

play20:52

broken that's what a lot of people

play20:54

complain I don't like to redo because

play20:55

every time that I make some small change

play20:57

many tests are broken this is one of the

play21:01

reasons so you would you have this

play21:06

problem with classicist as I said it

play21:09

depends of the features so if you're

play21:10

going to feature one that there will be

play21:14

a class in here and then if you talk to

play21:18

a few classes in here and then another

play21:20

class in here and then it talks to the

play21:22

database and feature to is a similar

play21:27

thing there is an entry point on API or

play21:29

something there is some domain logic in

play21:30

here some repository that goes to the

play21:32

database may be the same database you

play21:37

very rarely you'll have problems with

play21:38

your test because the features are very

play21:40

detached this is very common in a crud

play21:42

application right creating updates and a

play21:45

product creation updates on a client

play21:46

there's very little overlapping features

play21:48

so very rarely an evolution of these

play21:50

will impact on this but if you have a

play21:53

more complex than then it should be a

play21:54

nightmare to do this way another problem

play21:59

that you have when your units under test

play22:02

they become bigger is that as soon as

play22:05

you make a mistake or you make a change

play22:08

and our test is failing is very

play22:10

difficult now to figure out where so the

play22:14

diagnose of problems when they urinate

play22:15

is too big the unit under test is too

play22:17

big you should figure out where the

play22:19

problem is this is another problem that

play22:22

we have with these styles so refactoring

play22:28

that started very small we learned that

play22:31

we fast means a good thing but quite

play22:33

often as the system evolves we fasting

play22:35

becomes a big thing because the touching

play22:39

all those things are evolving because if

play22:40

I want to start mocking those tests from

play22:43

this one well before the behavior was

play22:46

expected here so we start detaching that

play22:49

is not just creating an interface I need

play22:51

to change all these tests as well

play22:53

because now some of those tests are

play22:55

relying on the the code to go through

play22:58

all the classes as soon as I did touch

play22:59

one there is an impact in my tests then

play23:01

I need to move the test somewhere else

play23:03

as well I need to inject things in

play23:04

constructors so refactor is not easy as

play23:07

you are evolving in this method so the

play23:12

setup of those tests if you make you

play23:14

keep making it into bigger become also

play23:16

more and more complex as you add more

play23:18

classes to these writing those tests

play23:20

becomes very difficult now because they

play23:22

need to take into account the whole

play23:23

execution so how so how do we know so

play23:34

this is class assistant I think that is

play23:37

great for things that I don't have a

play23:39

domain thing so inputs and outputs where

play23:42

I cannot see the internals or the

play23:44

internals are not about domain concepts

play23:46

persist for me is awesome

play23:48

but how do we define the signs of our

play23:51

unit I think this is a better discussion

play23:56

to have so how do I know the right size

play24:01

of a unit should be the unit under test

play24:03

one way to think about this is let's say

play24:06

that we have Class A that somehow talks

play24:10

to Class B and talks to cross see how

play24:14

you got both either you create this this

play24:16

way or it Class B and C a merchant from

play24:19

refactoring is less relevant for the

play24:22

for what I'm trying to say him so what

play24:26

we need to understand is like when I

play24:28

have my tests would I make the unit

play24:32

under test all three classes would I

play24:36

make just a and B and Moxie or would I

play24:41

mock B and C because those are the

play24:43

options that I have how do I decide that

play24:46

first voice you understand this is this

play24:49

is an association right association so a

play24:55

is associated to B and C but now we need

play24:59

to understand what kind of Association

play25:01

we have so there are two types of

play25:03

associations right one is called

play25:06

composition composition and the other

play25:11

one is called aggregation this is a very

play25:18

important thing to distinguish so in

play25:21

composition B and C are part of a the

play25:27

Association means a uses B&C the the

play25:32

specialization here is like it uses but

play25:35

our B and C part of a or they are

play25:38

independent thing that are just used by

play25:40

a so when it is a composition it's quite

play25:53

safe to make this a unit and test

play25:59

everything together not mop those things

play26:01

how do you know if this is a

play26:03

compositional aggregation one mental

play26:05

exercise that you can do is if you

play26:07

inline the behavior of B and C into a a

play26:12

will become more complex for sure but

play26:15

would it become less cohesive or would

play26:17

still remain cohesive an example would

play26:21

be if you have a discount calculator and

play26:24

during the discount has lots of

play26:26

different steps I might take into

play26:28

account the personal details if if the

play26:30

person is married is the age and family

play26:34

and stuff

play26:34

might take there might be a different

play26:36

part of the algorithm that will be the

play26:38

credit score or how often they claimed

play26:43

something under the insurance so there

play26:45

are different steps but if I inline the

play26:48

models your discount calculator a will

play26:50

still be cohesive it should just be

play26:52

messy so this is a composition so a

play26:58

different way of thinking is when it's

play27:01

an aggregation that relation is the

play27:03

opposite if I in line B and C into a a

play27:07

will not be cohesive or a very sound

play27:10

simpler way of saying that a will

play27:12

violate single responsibility principle

play27:15

if I have a checkout process and as part

play27:19

of my checkout as soon as I go to the

play27:20

website and say oh that's my payment

play27:23

details pay as part of the payment flow

play27:27

or the checkout flow I need to verify

play27:30

which payment method was chosen and then

play27:32

redirect to the right gateway but I also

play27:35

need to create orders I also need to

play27:37

notify the user I also need to trigger

play27:39

the delivery those things if I inline

play27:43

those things into a a will certainly

play27:45

violate single responsibility principle

play27:46

so then you know that your unit under

play27:52

test should just be a and those things

play27:55

should be marked so this is an exercise

play28:00

that is very important for us to do when

play28:06

when we are test writing code so this

play28:12

leads me to the question back to the

play28:15

original question of the talk is is this

play28:18

knowledge coming from TDD what is this

play28:22

knowledge coming from design knowledge

play28:24

that I already had previously right so

play28:28

if I was not test driving this code

play28:31

would I make the same design decisions

play28:36

so and if yes or similar design

play28:39

decisions the NTD D is a great workflow

play28:43

that I absolutely love to work but the

play28:46

design decisions the trigger for

play28:48

the trigger means that the flow is

play28:50

triggering so I okay it's work it's

play28:52

working now now's your time to design

play28:54

that's what that's why I say that is a

play28:55

workflow specify it make it work now

play28:59

design now let's fix it do it properly

play29:02

but what I do in this phase I need to

play29:07

build on top of a software design

play29:09

foundation before so so in order to know

play29:14

what you do so how many people like

play29:17

marks don't know if I raise my hand I

play29:21

don't know what he's gonna say next

play29:23

right so every time I give this talk

play29:32

like I talk about completely random

play29:34

things and and I never cover everything

play29:35

I want

play29:36

so I want you these mystify marks before

play29:40

I talk about the other example so how

play29:48

can a backhoe that let's say that I have

play29:49

a feature that is this check out thing

play29:52

that I talked about let's say that we

play29:54

have a web app and so there is a check

play29:57

out scenario and in this check out

play30:03

scenario so I want to buy my item so I

play30:05

press the submit button and stuff I

play30:07

don't want to go through the whole user

play30:08

story now what is important here is that

play30:10

there is a check out which say pay as

play30:13

part of my acceptance criteria I need to

play30:15

do the actual payment the payment is a

play30:20

complex thing I might need to identify

play30:23

which payment method was chosen which

play30:25

country I am if I need to choose a

play30:27

different gateways if it's paper if is

play30:30

credit card so there's a lot of things

play30:31

it's not just co-payment right so

play30:33

there's a lot of things related to

play30:35

payment in here so there's also like we

play30:37

need to create an order order management

play30:45

is also quite complicated sometimes you

play30:47

need to create a northern with a certain

play30:48

state and then wait for the result of

play30:50

the payment and then update it and then

play30:52

so there's a whole order life cycle into

play30:55

this right so there's the delivery part

play30:58

and there is a notification

play31:02

vacation so delivery is like depends on

play31:07

where you are in the world we need to

play31:09

know which delivery options are

play31:10

available to you some of them you can

play31:12

collect in the local store some of them

play31:14

will be delivered to your house some of

play31:15

the you some place you have Next Day

play31:17

Delivery some place you need to wait so

play31:19

delivery is also complicated things and

play31:21

some items can be delivered if you

play31:24

bought in the morning can be delivering

play31:25

the evening others will need to wait for

play31:27

two weeks so there's a lot of things

play31:29

going on in here

play31:29

and notifications just let the user know

play31:32

what happened after they click checkout

play31:35

so I want to talk about mocking as a

play31:40

design tool because like one of these

play31:43

debates that we have a mob I think that

play31:45

the debates that we are having about

play31:47

marks are the wrong ones because we are

play31:50

talking about marks as a testing tool

play31:52

and not as a design tool and if we

play31:56

understand that mocking can be used as a

play31:58

design tool a lot of these complex these

play32:00

discussions or many of those discussions

play32:02

they go away so let's say that we have

play32:07

these kind of scenario here let me just

play32:16

so we will have a browser right so

play32:19

someone is going to the browser and we

play32:22

say make a payment so there will be some

play32:26

front end up in here or some delivery

play32:33

Macanese that can be mobile can be web

play32:34

can be whatever and then there will be

play32:37

so I want to test drive this flow so I

play32:41

know that these thing in here will

play32:44

submit right so you send the payment

play32:47

send payment details or they want to

play32:54

process the payments right so that's the

play32:56

trigger the first design decision that I

play32:59

need to make here who is going to handle

play33:02

that so in that just for the sake of

play33:05

this example to keep things simple let's

play33:07

assume that I'm gonna say I'll have a

play33:10

payment API

play33:16

so these will receive the HTTP request

play33:22

let's say that's the web then what I

play33:27

need to decide now how do I test drive

play33:29

this do I put do I build the entire

play33:31

system inside one single test or how do

play33:35

I evolve now this flow one one thing

play33:39

that I need to ask myself if this is the

play33:40

class that is handling the output

play33:43

requests what is what is what is the

play33:48

responsibility of its of its class you

play33:50

can say wow it's you process the payment

play33:52

so then is to do the whole system say ok

play33:55

what does it involve in in processing

play33:58

the payment what are the different steps

play34:00

the different things that we need to do

play34:01

well business-wise that's kind of the

play34:04

flow that we want but we also have a

play34:06

delivery mechanism we need to handle

play34:08

these JSON that is coming in we have to

play34:10

get these out of the request and it

play34:12

should send a JSON back so there is a

play34:13

lot of delivery mechanism logic should I

play34:17

mix that delivery mechanism logic with

play34:19

my domain knowledge logic or not so now

play34:23

we are not talking about passing anymore

play34:24

we are purely talking about designing

play34:26

that's what I was thinking

play34:28

did it is giving me okay you need to

play34:31

write the test now but you write this

play34:34

test I can have the option to write as a

play34:38

black box as an acceptance test I'm

play34:40

gonna send some JSON in to this API and

play34:43

I expect this JSON as a result and I

play34:45

might expect something in the database

play34:47

somewhere or a message in a queue

play34:48

somewhere and really treat as a black

play34:51

box and that's one option for sure and

play34:53

we should do that anyway

play34:54

but it's too big for testing all those

play34:59

stuff or all this stuff through from

play35:02

outside so I might want you have smaller

play35:05

levels of testing and that's the ones

play35:07

that I'm talking about now so I only

play35:10

need to decide how much behavior I'm

play35:11

going to keep in here one type of

play35:13

behavior I need you have is to process

play35:15

to 200 call these to parse I'll just put

play35:18

random names right so so we just get the

play35:20

idea to parse the payload right so

play35:24

that's very generic because I'm dealing

play35:27

with

play35:27

zone HTTP request and like that

play35:30

right so I also know that these cars

play35:34

will need to respond something to my

play35:36

client so there will be at some point

play35:38

somewhere some J's and that's going to

play35:42

come back right with the response and

play35:45

stuff

play35:46

I will potentially we need to transform

play35:49

something in here so generate response

play35:52

or something like that the problem is

play36:05

like what I know that this class needs

play36:07

to do that

play36:09

how much of these should I put in this

play36:11

class how much should I delegate so what

play36:16

we could do also which layer does this

play36:18

class leave are this kind of behavior

play36:23

knowing about HTTP should they be in the

play36:26

same area of my code base or layer or

play36:30

whatever from these ones or they should

play36:33

be separate because if I understand that

play36:38

this might be some sort of a delivery

play36:41

mechanism right so this is a delivery

play36:47

mechanism then I probably should not

play36:52

have a lot of business in here but this

play36:54

design decision is coming from my hand

play36:56

it is saying like you need to design now

play36:58

because you need to write this test and

play37:00

this test needs to know what you haven't

play37:03

wear so it's a trigger for me to design

play37:07

but it doesn't tell me what you design

play37:09

so then I can say well what if I well

play37:15

what are we doing here I'm doing the

play37:17

checkout so what if I had a class in

play37:20

here that could call check out check out

play37:26

action right so in domain driven design

play37:30

how many of you use or art is familiar

play37:32

with domain driven design okay how many

play37:34

of you are you familiar with clean

play37:36

architecture from Uncle Bob ok a few

play37:39

hands so in domain driven design

play37:41

application service in clean

play37:43

architecture DC's a use case I'll just

play37:45

call it actions because why not to give

play37:47

another name for the same thing just to

play37:50

make it very confusing so they like I

play37:53

need to decide what's gonna go there so

play37:55

why don't I just say make a payment at

play38:04

this point this design decision what it

play38:07

allows me to do is understanding where

play38:11

that part of my behavior is here part of

play38:13

my behavior is here and this is when I

play38:15

look at the composition back to the

play38:17

composition aggregation although I have

play38:20

only one client for now should I check

play38:23

out action because you another way of

play38:25

some people say well if there is only if

play38:28

the payment API is the only concert use

play38:29

checkout is a composition because if I

play38:32

kill payment API this class dies because

play38:35

doesn't have any any client this is a

play38:37

fair thing to say but logically if I

play38:41

understand the kind of responsibilities

play38:43

of each class has and the force that

play38:45

they will have to evolve they are

play38:48

different and in this case although it

play38:50

has a single client I would still treat

play38:52

that as an aggregation and not a

play38:54

composition so I would be very

play38:56

comfortable to unit test this class

play38:59

mocking this class what is important in

play39:02

here is to understand that these

play39:04

exercise we are now using mocks

play39:06

because this client the class the needs

play39:09

of these classes to say look I will deal

play39:10

with the the JSON stuff but I want a

play39:14

class that can help me hey helper make

play39:19

this payment for me and give me a result

play39:21

and then I will do the transformation to

play39:23

the client so this need I can use a mock

play39:27

to define what this thing is and what

play39:30

this interface will be so for me mocking

play39:33

is a design tool and then I can go back

play39:36

to what I had in here

play39:38

check out payment so that the check out

play39:40

logic involves sub steps in the flow

play39:44

payment create order deliver

play39:45

notification so first off we can have

play39:47

like so check out

play39:51

what is the relationship between

play39:53

checkout and payment the payment logic

play39:57

the order logic the delivery logic and a

play40:08

notification logic I now need to

play40:13

understand because now I'm done so I

play40:15

will say butcher unit tests this one

play40:17

mock this one and I can test my entire

play40:19

navigation if I do that for all my AP

play40:21

eyes and stuff I can test all the

play40:23

navigation just mock in the backend now

play40:26

I need to continue so okay but this was

play40:28

not done yet so what is the role of this

play40:31

class so if I call them make a payment

play40:35

first and then as I'm mocking these I'll

play40:37

need to define which pair unto them that

play40:39

I have in what's going to come back so

play40:41

this is where the mock is a design - it

play40:43

allows us to say that the behavior is

play40:45

going to be here that's how I access the

play40:47

behavior that's the what I need to pass

play40:48

and that's what I will need to return so

play40:51

we can use mock to design that interface

play40:53

and then you are done with this then you

play40:56

can move inwards so you are coming from

play40:58

outside and moving inwards now I go to

play41:01

this class in here so I will this class

play41:03

now has a make a payment and this class

play41:05

was designed to satisfy the client class

play41:09

right so the reason that this cause

play41:12

exists with these is to satisfy a client

play41:14

so now I need to ask if I call this

play41:17

method what should happen oh we need to

play41:21

process the payment and there is a lot

play41:23

of complication here we need to create

play41:25

the order there's complication there is

play41:26

delivery there's notification okay so

play41:29

that is way to marching here

play41:30

how much behavior do I want to keep in

play41:33

the checkout action and how much we here

play41:34

do I want to delegate that's our again

play41:36

another design decision and then I need

play41:38

to understand in order to make these

play41:40

because I'm test driving right so I

play41:41

wrote the test for this class and now

play41:44

I'm writing test for this class at a

play41:46

unit level so I need to decide that the

play41:49

boundaries the unit so the unit under

play41:51

test for this one doesn't include this

play41:52

one now I need to say what is the size

play41:54

of this unit so would payment have

play42:00

different forces to change from pair to

play42:03

the checkout

play42:04

when you do some analysis they say well

play42:06

there are different business people in

play42:07

different areas let's say hey we would

play42:09

like to support PayPal or another credit

play42:13

card or in certain countries you are not

play42:15

allowed to use certain payment methods

play42:17

so there is a lot of business decisions

play42:20

that happen behind the scenes by

play42:22

different actors that impact the

play42:24

evolution of this area of the system and

play42:27

that is completely unrelated to the flow

play42:29

the flow would be the same you do the

play42:30

payment you create the order you do the

play42:32

delivery do the notification but the

play42:33

details of what happens in here is not

play42:36

only evolution of the code is evolution

play42:37

of the business as well

play42:38

right there are business decisions and

play42:41

agreements and contracts signed in order

play42:43

to provide certain payment methods in

play42:44

certain countries so when you analyze

play42:47

the domain and the business it's very

play42:49

safe to to make a decision that this

play42:53

sees an aggregation because these will

play42:57

evolve err has a chance to evolve

play42:58

completely independent from the rest

play43:01

order is the same order management is

play43:04

not only important when you when you try

play43:06

to buy something there is a department

play43:09

in the back office of the organization

play43:11

that is dealing with disorders customers

play43:13

will call in and said where the hell is

play43:15

my package I paid and I haven't received

play43:17

or what it was broken or it was not what

play43:20

I wanted

play43:21

so there is a whole set of group of

play43:26

people and systems that we need these so

play43:29

is pause so it's also quite safe

play43:31

she was filmed that the logic related to

play43:35

order should not be part of the checkout

play43:38

should be used by the checkout or should

play43:40

not be under the same unit because the

play43:42

force is to evolve those two I don't if

play43:45

they evolve as long as the interface

play43:47

remains the same I don't want this

play43:48

should be broken and then the livery is

play43:51

the same thing delivery is a very

play43:53

complicated thing if you when you have

play43:55

like these international companies

play43:56

delivering different countries they have

play43:58

deals with local people local companies

play44:01

to do the actual delivery so this also

play44:04

has a lot of business people behind and

play44:06

involving these certain delivery methods

play44:08

are not available in certain countries

play44:10

are not the notification I decided on

play44:14

you know once this is done and I get

play44:16

there is response

play44:17

in this case I'll probably will make the

play44:21

notification cuz the notification now is

play44:22

just to send an email out and stuff I

play44:23

might have some classes to do that

play44:27

separate from this but it's part of the

play44:29

thing if I inline this one into here

play44:31

this would still be reasonably cohesive

play44:33

I'm just making it up let's just to give

play44:35

an example

play44:36

those are design decisions and you need

play44:39

to make those design decisions before

play44:41

you write the test because otherwise how

play44:44

do you test it if you are trying to it

play44:46

you can make afterwards but that means

play44:49

that you're you need to start putting

play44:50

all this logic inside check out in the

play44:53

green so going to red to green very fast

play44:55

and populating the check out module with

play44:59

a lot of logic related to these two

play45:00

these two these two wait for the one of

play45:02

the refactoring cycles to start

play45:04

extracting then and then move the tests

play45:06

across and then decide where they're

play45:07

gonna put the boundaries is very

play45:08

wasteful to do this way I think that you

play45:11

can do a very quick analysis and make

play45:13

this decision up front so once we

play45:15

understand that when you do these design

play45:17

analysis how much times I have shaped I

play45:22

could go I could stay here forever as

play45:25

always just put this back so these

play45:34

design decisions in here it made just

play45:36

worse right so now it's very safe for us

play45:40

to start for example well let's put a

play45:44

payments clause in here that could be

play45:50

mocked and then I say like in order to

play45:53

test drive the check out action I

play45:54

already understanding my domain I made a

play45:59

decision that there will be some logic

play46:00

in here so this is my design decision in

play46:04

my test I said I'm gonna call this class

play46:06

but I'm gonna delegate part of the

play46:08

responsibility to this class so how

play46:11

would this flow work how do I access

play46:14

that behavior so then I can say well it

play46:17

could be I don't know hey could we have

play46:21

a method to come pay and I need to

play46:22

decide what parameters it would have

play46:24

what the return type so mocking now you

play46:27

allow me to go to the details what do I

play46:30

pass what

play46:31

my return and stuff like that I can also

play46:33

have an orders which I also need you

play46:39

decide I create or something like that

play46:45

what's going to go in what's going to go

play46:47

up again I can use a mock in there to

play46:50

refine the details the delivery as well

play46:58

right so sheep or whatever ships your

play47:00

client ships your client and then there

play47:07

is a notification side the notification

play47:08

I decided to keep inside check out so I

play47:10

can have a process in here that would be

play47:13

send notification so this could be a

play47:19

private method in here could be another

play47:21

class hanging off this one but it's part

play47:25

of the same unit so in my test I could

play47:26

mock those three but I don't need

play47:29

potentially mock these unless it is

play47:31

going to a email sender that I mock at

play47:33

that level that boundaries but what is

play47:35

either seen in here is that now I know

play47:37

that I will need to finish the contract

play47:41

in here what comes back right so what is

play47:43

the result of these these things so

play47:45

there will be some sort of a result in

play47:47

here or whatever there will be I need to

play47:49

define that in my marks and then I will

play47:52

populate and then return but these

play47:53

allows me what this is what we call

play47:57

outside in TDD that's the difference

play47:59

between the classicist we start from the

play48:01

outside of our system and you say like

play48:05

what is the first class that's going to

play48:07

handle the external world or that the

play48:09

request from the external world this one

play48:11

what this class should do and then you

play48:14

list a bunch of stuff and if you are a

play48:15

if you list more than one we need to

play48:19

decide how many of those things I want

play48:21

to keep inside and how many of these

play48:23

things I want to delegate and then you

play48:24

apply composition aggregation should

play48:27

decide that and then a few things we

play48:30

were merged so this class is injecting

play48:32

should this one this one into this one

play48:34

this one into this one this one to this

play48:35

one so now we have these to inject into

play48:37

here three classes injects into here

play48:39

these give us a hint of whoa

play48:44

do I have one class talking to too many

play48:46

because if we have one class talking to

play48:47

ten classes it to be mark hell

play48:50

we cannot mock we cannot blame marks for

play48:54

the design decisions that we are making

play48:55

but this is allowing us to explore if I

play48:59

see that one class is talking to too

play49:00

many classes of course it will be

play49:02

complicated to test that but I have what

play49:04

we call in couplings called fan-out is

play49:07

one class that talks to too many imagine

play49:09

the Russian those that normally go

play49:11

through big ones and to these more ones

play49:13

gracefully right so they are big level

play49:16

of abstraction or high level of

play49:17

abstraction to low level of abstraction

play49:19

this is the same if we start adding more

play49:21

mocks to this one or more collaborations

play49:23

you have a big Russian doll full of it's

play49:25

more Russian dolls inside and then what

play49:27

you what you need to do is just say hey

play49:29

maybe some of these collaborations here

play49:31

some of these calls I could group them

play49:33

into another class and then instead of

play49:35

having one class talking to ten I could

play49:38

have one class talking to three and then

play49:40

each one of those three who took channel

play49:41

who talked to another two or three and

play49:43

then it starts distributing the the

play49:46

degree of abstraction of your system

play49:48

gracefully and then mocks would not be a

play49:50

problem in outside in TDD

play49:58

this is the execution flow right

play50:01

execution flow it's completely focused

play50:08

on behavior

play50:09

the other one is focus on state this the

play50:13

design direction is alongside the

play50:17

execution flow the test directions are

play50:19

aligned as well so I normally prefer

play50:23

this kind of approach when unbelief

play50:26

flows but but this approach would not

play50:28

work for the discount calculator imagine

play50:31

that one of those things in here

play50:33

somewhere another class in here there

play50:36

was a discount calculator and there was

play50:38

a method calling calculate discount

play50:42

that's your data for that cause any

play50:45

specific as I how do I evolve these

play50:49

I know that these data comes in these

play50:51

data and this number comes out I would

play50:53

flip to cross assist I would work in

play50:55

very small increments write a test

play50:57

right a bit of code just to make it an

play50:59

enough to pass look at it and see if I

play51:02

find some duplication if I find some

play51:04

patterns if I find some different levels

play51:06

of abstraction and I keep doing and then

play51:08

I at some point something we were merged

play51:10

so is the degree of confidence so if

play51:13

something I cannot see if I cannot see

play51:15

the solution or the abstractions when I

play51:18

when I when I think about the inputs and

play51:20

outputs

play51:20

I go classicist and I let the design

play51:23

emerge as I guess I gain more insights

play51:26

but if I can clearly clearly understand

play51:29

these I won't do that the other way

play51:31

because it will be very wasteful I will

play51:34

go straight for the abstraction that I

play51:35

want so I could stay here forever so let

play51:42

me just go to one of the how much time

play51:44

do I have zero two hours descent there

play52:12

are there is a thing that I want to go

play52:14

very quickly

play52:15

I call it inflection point inflection

play52:26

point imagine that this is the most

play52:27

straightforward solution you can have

play52:31

straight forward and this is the future

play52:35

proof so normally when we design

play52:42

software we can go all the way what the

play52:45

future will look like and then we try to

play52:49

do this big design up front the opposite

play52:54

of it is the under engineering is like

play52:56

just let's do the simplest thing could

play52:58

possibly work both are bad in my view

play53:02

and I think that what is important here

play53:05

is

play53:07

let me just we need you when we are

play53:14

designing why don't we use just strings

play53:18

and ins why do we want to create a type

play53:20

why don't you do it in the procedural

play53:22

way why do we create a class or a method

play53:24

why do you create components why we use

play53:26

hexagonal architecture why do we divide

play53:28

our system in different modules why do

play53:30

we want to go micro services there's

play53:32

those are all design decisions just at

play53:33

different levels so but why do we make

play53:35

them if I'm discussing what if none of

play53:37

you I might say look I want to start

play53:40

small and grow and you might say no I

play53:42

want to start a little bit bigger so why

play53:45

do we so given the same requirement why

play53:48

would we design this differently at

play53:51

different levels because we are trying

play53:53

to optimize for something so why we are

play53:56

not doing the most straightforward

play53:57

solution not because we like to

play54:00

complicated things it's because in our

play54:02

head there is something either through

play54:03

our experience or because of our

play54:06

knowledge of what is coming or what

play54:09

you're going to be having problem with

play54:11

very soon that we start moving this is

play54:15

slide to look you know I want you

play54:18

optimizer a bit more I know that we

play54:20

could do a little bit simpler but maybe

play54:21

we could create this interface in here

play54:23

instead of having these JDBC codes or

play54:25

this database code in setup inside of

play54:27

our page let's create a few layers but

play54:31

that would be simpler well depends on

play54:33

how you define simple but if we want to

play54:36

push that down the the database code

play54:39

from the page to our repository going

play54:41

through a delivery mechanism and your

play54:43

hexagonal and stuff why are you doing

play54:45

that if you don't need it's because in

play54:47

your head you are optimizing that for

play54:49

changeability

play54:50

or to separation of concerns so those

play54:52

are optimizations and you need to

play54:54

understand how far do you go so how do

play54:56

we find these this point when we are

play54:58

designing one of the things is

play55:00

understand why what you are optimizing

play55:02

for and then we can come from different

play55:06

directions so I can go from left to

play55:08

right and say look how far can I go

play55:10

knowing that we need to have a Anessa

play55:14

layered expert transactions per second

play55:18

or we need to support a new credit

play55:20

are we are building a credit card

play55:21

feature now visa and our next feature

play55:23

these are max so why would I do

play55:25

something very specific for visa knowing

play55:28

that I will do Amex is straight away

play55:31

after that why would I we factor

play55:34

everything so so we can go from the

play55:36

simplest solution so how can I make it a

play55:38

little bit more future proof or prepare

play55:42

for the optimization that I want to do

play55:43

but without investing too much right now

play55:46

because if you pass that point then you

play55:49

were doing far too much the investment

play55:51

is too big for the degree of uncertainty

play55:53

that you have because you need to make

play55:56

sure that is a guess that you're going

play55:58

to do certain things so you need to

play56:00

decide how much you're gonna invest

play56:01

according to the certainty that you have

play56:03

of what's coming next or it can come the

play56:06

other way around it can come from right

play56:08

to left you can say look there are

play56:09

certain things that you need to have in

play56:12

order to go to production or in order to

play56:14

reach this milestone so but I'm Beauty

play56:18

but this milestone or the release date

play56:20

has all these features that you need to

play56:22

build so how can we keep our solutions

play56:24

simple as we go through each feature

play56:27

without compromising what we need to

play56:29

achieve so we can go the other way

play56:31

around so once you start rushing

play56:33

aligning that so the discussions between

play56:35

you and your peers is not about a

play56:38

solution anymore you can mark that now

play56:40

why does one person want a design and

play56:42

the other one wants another designer how

play56:44

complex are going to make right now so

play56:47

you can use that to find this inflection

play56:49

point that can be here can be here can

play56:51

be anywhere so I of course I'm away over

play56:55

time there's a ton of stuff that I won't

play56:57

cover

play56:59

what's with the message here the message

play57:02

is like test-driven development is a

play57:04

phenomenal tool is the thing that I

play57:06

started doing almost 14 years ago

play57:08

and I never never looked back I

play57:10

absolutely adore the rhythm that

play57:13

discipline specify what you want make it

play57:17

work make it better

play57:18

the design aspect of it i chair epeak

play57:21

sometimes i design a little bit more

play57:22

upfront sometimes I let it emerge

play57:24

according to the degree of confidence

play57:27

that I have in the solution that I'm

play57:30

building so I believe

play57:33

we believe that if you learn how to

play57:35

design well TDD will be much easier if

play57:39

you understand there are different

play57:40

styles and you have a good foundation of

play57:41

design synergy will be easy

play57:43

thank you very much

play57:45

[Applause]

play57:48

[Music]

Rate This
β˜…
β˜…
β˜…
β˜…
β˜…

5.0 / 5 (0 votes)

Related Tags
TDDSoftware DesignAgileDevelopment WorkflowEmergent DesignRefactoringDesign DecisionsClean ArchitectureDomain-Driven DesignTestingBest Practices