Port/Adapter/Simulator: read-only and write-only dependencies…

February 24, 2016 at 8:11 am

When dealing with many external dependencies, the Port/Adapter/Simulator pattern works great.

But what about dependencies that are read-only – such as consuming an information feed from another system – or write-only – such as sending a notification to a user? Can we use P/A/S in those scenarios?

The answer is a qualified "yes" – we can get many of the advantages of P/A/S, though we will probably have to give up something.

Stock prices

Let’s consider an application where we deal with stock prices. If we were in a read/write scenario, we would write something like this:

interface IStockPriceStore
{
    Decimal Load(StockSymbol stockSymbol);
    void Save(StockSymbol stockSymbol, Decimal price);
}

And the test that we would write would look something like this:

IStockPriceStore stockPriceStore = new StockPriceStoreMemory();
stockPriceStore.Save("MSFT", 55m);

StockProcessor stockProcessor = new StockProcessor(stockPriceStore);
stockProcessor.Process();
Assert(…);

Okay, that’s not perhaps as minimal as I would like for a test, but it’s not terrible.

But what if our stock feed is read-only? That changes our adapter to be something like:

interface IStockPriceSource
{
    Decimal Load(StockSymbol stockSymbol);
}

To make our tests run the same way, we need someplace to put a Save() method. My approach is to put it directly on the simulator (StockPriceSourceMemory) class. There are a few ways I’ve played around with expressing this:

  1. Put it directly on the class and name it Save()
  2. Put it directly on the class and name it SimulateSave()
  3. Define a separate interface (IStockPriceSink?), put it there, an have the simulator implement it.

 

I don’t really like the third option, as we have an interface that will only have one implementation. I haven’t decided between the first two; sometimes I like the division that option #2 gives, sometimes I think it’s too wordy.

This approach lets us write the product tests exactly the same way we would with a read/write store, but we lose a big advantage of P/A/S – the ability to test for similarity between our real and in-memory implementations of the adapter.

In many cases, I don’t think this matters a lot, as read-only stores tend to be fairly straightforward. In some cases, it does matter, and there’s another technique we can use. We write our adapter tests so that they pass against the real adapter, and then, when we run those same tests against the simulator, we pre-populate it by fetching specific data from the real adapter and storing it into the simulator. The data that we move across is enough to verify that the simulator works correctly.

This will result in two different sets of tests; there will be the pure-simulator unit tests, and then the contract verification tests that we run against the live data and the simulator.

It’s not a perfect solution, but it will be pretty close.

Email User

Emailing a user is a good example of a write-only operation. We’ll write the port like this:

interface IUserNotifier
{
    void Notify(User user, Message message);
}

I’m really hoping that you weren’t expecting a IEmailUser port.

In this case, our simulator needs to do a couple of things. It needs to verify that Notify was called with appropriate parameters, and it needs to be able to simulate any error situations that we want to raise with the calling application.

How about something like this:

class UserNotifierSimulator: IUserNotifier
{
    void Notify(User user, Message message) {}

    User User {get; private set;}
    Message Message {get; private set;}
}

To use the simulator, I pass it into a class that needs to perform a notification and then look and the User and Message properties to see whether it performed the notification.

As for the port tests, I suspect that I’m going to write a few around the port validation behavior to define what happens when either user or message is improperly formed.

There are other possible errors – the network could be unreachable, for example – but I’m not sure I’m going to write any of them into the port. I would prefer to hide them underneath, to make the real adapter responsible for recovery.

Message passing architectures…

And, so that’s how I’ve done it, and it’s worked pretty well.

But… remember my earlier comment about the test code I wrote for the stock store? The problem there is that I’m saving something into a store just so that the stock processor can fetch it right out. But there’s an alternative:

If I think of this as in message-passing/pipeline terms, I can express things differently. Something like:

class StockPriceSource
{
    public event EventHandler<StockPrice> StockPriceReady;

    public void FetchStockPrice(StockSymbol stockSymbol);
}

I can then hook this up to a modified version of the StockProcessor class by just hooking a method to an event. This approach means that I don’t really need my simulator any more; I have something that can produce one (or a set of) stock prices, and then things that know how to consume them.

I think this probably makes my world simpler. I can write a few quick contract tests for StockPriceSource to verify that it is working, and I can test all the processing just by passing in data.

You suck at TDD #3 – On Design sensitivity and improvement

February 11, 2016 at 8:31 am

Through an above-average display of ineptness, I managed to overwrite my first version of this post with a response I wrote to the comments. Since I’m too lazy to try to reconstruct it, I’m going to go a different direction. In a recent talk about design, I told the attendees that I was going to insult them during the talk, and it worked pretty well, so I’m going to try the same thing here:

You don’t know how to do design. You would not know a good design if it came up and bit you.

To explain this, I feel it necessary to talk a bit about ignorance. I will loop back to the topic at hand sometime in the future.

In a really cool article written back in 2000, Phillip Armour wrote about 5 orders of ignorance, which I’ll summarize here:

  • Oth Order Ignorance (0OI) – Lack of ignorance, or in other words, knowledge. I have 0OI about skiing.
  • 1st Order Ignorance (1OI) – Known lack of knowledge. I have 1OI about how to knit, but I can think of a number of ways to convert this to 0OI.
  • 2nd order Ignorance (2OI) – Lack of awareness. I have 2OI when I don’t know that I don’t know something. I cannot – and this is the point – give examples here.
  • 3rd order Ignorance (3OI) – Lack of process. I have 3OI when I don’t know a suitably efficient way to find out that I don’t know that I don’t know something.
  • 4th order ignorance (4OI) – Meta ignorance. I don’t know about the 5 orders of ignorance.

 

Like any model, this is a simplification of what is really going on, but it’s a useful model.

Back to the insult, but this time I’ll reword it using the orders of ignorance:

You have 20I about design; the code that you are writing has obvious problems with it but you do not see them because you are 2OI about these problems and therefore cannot see the problems yourself.

It’s a little less catchy, and that’s why this series is named "You suck at TDD", not "Systemic influences and limitations in human knowledge acquisition have limited your effectiveness at TDD in interesting ways".

You can probably think back when you learned something about coding – for example, there was probably a time when you learned it was good not to repeat code. Before you learned that, you had 2OI ignorance about it, and now you no longer do.

We *all* have at least some 2OI about design; it’s just a feature of how knowledge acquisition works. That is not the real problem.

The real problem is that most developers have both 3OI and 4OI when it comes to design. They don’t understand how 2OI works and therefore think that they have good design skills, and – probably more importantly – they don’t have an efficient way of identifying specific instances of 2OI and converting them to 1OI and ultimately 0OI.

Or, to put it more concisely, most developers think they are good at design because they can’t see the problems in their designs, they don’t really understand that this is the case, and they don’t have any plan to improve.

If you couple this with our industry’s typical focus on features, features, features, it is no longer surprising that there is so much bad code out there; it becomes surprising that there is code that works at all.

So, tying this whole thing back to TDD, the reason that TDD does not work for a lot of people is that they don’t have sufficient design skills to see the feedback that TDD is giving to them. They get to the refactor step, shrug, and say, "looks good to me; let’s write the next test". And these 2OI issues add up, and they make it harder to do TDD on the code, and it gets hard to do.

This is not surprising. TDD is about evolutionary design, and if you aren’t very good at design, it’s not going to work very well.

Improving your design skills

The remainder of this series is about improving your design skills. I will probably focus on specific patterns that I find especially useful in the TDD world, but I’d like to provide some general advice here. These are things that will help you move from 2OI to 1OI in specific areas of design. And please, if you have other ideas, add them in the comments:

  1. Pair with somebody who cares about design. They will be 1OI or 0OI in areas where you are 2OI, and by having discussions you will learn together.
  2. Read and study. There is a *ton* of useful information out there. If you like abstract, read – and then re-read Fowler’s book on Refactoring. If you like more specificity, go read information about a single code smells, and then find it – and fix it – in your code. If you want a bigger example, just search for refactoring, and you’ll find examples like this.
  3. Share and teach. You may think that you know something about a specific area of design, but when you go to teach it to others, that is when you really learn it.
  4. Practice refactoring skills. If you are lucky enough to work in a language with good refactoring tools, train yourself to use them instead of hand-editing. Not only will this speed you up and reduce the errors you make, it will train you to think differently about code.
  5. Practice TDD and experiment with different approaches. What does "tell, don’t ask" do to your code? Can a more functional programming approach have benefits?

Agile Open Northwest 2016 recap

February 9, 2016 at 8:13 pm

Last week, I spent three days at Agile Open Northwest 2016, a small (300-ish people) agile conference held at the Exhibition Hall at Seattle Center.

Well, perhaps ‘conference" is the wrong word; one of the first things that I read about the conference said the following:

Agile Open Northwest runs on Open Space Technology (OST).

I am generally both amused and annoyed by the non-ironic appending of the word "technology" to phrases, but in this case, I’m going to cut them some slack, because Open Space really is different.

I’ve done a lot of conferences in my time, and one of the problems with conferences is that they are never really about the things that you want them to be about. So, you pull out the conference program, try to figure out what the talks are really going to be like, and go from there.

Open space technology is basically a solution to that problem. It’s a self-organizing approach where a minimal bit of structure is put into place, and then the conference is put on by the attendees.

So, somebody like me could host a session on TDD and design principles and #NoMocks, and – in collaboration with a few others (including Arlo) – we could have very fun and constructive session.

And – far more cool in my book – somebody who knew just a little about value stream mapping to could host a session on applying value stream mapping to software projects and have the people who showed up teach me.

The other non-traditional thing with the conference is the law of personal mobility, which says that it’s okay – no, it’s required – that if you aren’t learning or contributing at a session you have chosen, you leave and find a better use of their time. Which means that people will circulate in and out of the sessions

With the exception of one session, I enjoyed and learned something at all of the sessions that I went to.

The one downside of this format is that you need engaged people to make it work; if you take a bunch of disinterested people and ask them to come up with sessions, nobody is going to step up.

I also got to do a couple of Lean Coffee sessions at breakfast Thursday and Friday. These are a great way to get ideas quickly and cover a lot of topics in a short amount of time.

Overall, I had a great time. If you have passion around this area, I highly recommend this conference.

You suck at TDD #4 – External dependencies

January 26, 2016 at 1:48 pm

When I started doing TDD, I thought it was pretty clear what to do with external dependencies. If your code writes to a file system – for example – you just write a file system layer (what would typically be called a façade, though I didn’t know the name of the pattern back then), and then you can mock at that layer, and write your tests.

This is a very common approach, and it mostly works in some scenarios, and because of that I see a lot of groups stick at that level. But it has a significant problem, and that problem is that it is lacking an important abstraction. This lack of abstraction usually shows up in two very specific ways:

  • The leakage of complexity from the dependency into the application code
  • The leakage of implementation-specific details into the application code

Teams usually don’t notice the downside of these, unless a very specific thing happens: they get asked to change the underlying technology. Their system was storing documents in the file system, and it now needs to store them in the cloud. They look at their code, and they realize that the whole structure of their application is coupled to the specific implementation. The team hems and haws, and then comes up with a 3 month estimate to do the conversion. This generally isn’t a big problem for the team because it is accepted pretty widely that changing an underlying technology is going to be a big deal and expensive. You will even find people who say that you can’t avoid it – that it is always expensive to make such a change.

If the team never ends up with this requirement, they typically won’t see the coupling nor will the see the downside of the leakage. In my earlier posts I talked about not being sensitive to certain problems, and this is a great example of that. Their lives will be much harder, but they won’t really notice.

Enter the hexagon

A long time ago in internet time, Alistair Cockburn came up with a different approach that avoids these problems, which he called the Hexagonal Architecture. The basic idea is that you segment your application into two different kinds of code – there is the application code, and then there is the code that deals with the external dependencies.

About this time, some of you are thinking, “this is obvious – everybody knows that you write a database layer when you need to talk to a database”. I’ll ask you to bear with me for a bit and keep in mind the part where if you are not sensitive to a specific problem, you don’t even know the problem exists.

What is different about this approach – what Cockburn’s big insight is – is that the interface between the application and the dependency (what he calls a “port”) should be defined by the application using application-level abstractions. This is sometimes expressed as “write the interface that you wish you had”. If you think of this in the abstract, the ideal would be to write all of the application code using the abstraction, and then go off an implement the concrete implementation that actually talks to the dependency.

What does this give us? Well, it gives us a couple of things. First of all, it typically gives us a significant simplification of the interface between the application and the dependency; if you are storing documents, you typically end up with operations like “store document, load document, and get the list of documents”, and they have very simple parameter lists. That is quite a bit simpler than a file system, and an order of magnitude simpler than most databases. This makes writing the application-level code simpler, with all of the benefits that come with simpler code.

Second, it decouples the application code from the implementation; because we defined the interface at the application level, if we did it right there are no implementation-specific details at the app layer (okay, there is probably a factory somewhere with some details – root directory, connection string, that sort of thing). That gives us the things we like from a componentization perspective, and incidentally makes it straightforward to write a different implementation of the interface in some other technology.

At this point there is somebody holding up their hand and saying, “but how are you going to test the implementation of port to make sure it works?” BTW, Cockburn calls the implementation of a port an “adapter” because it adapts the application view to the underlying dependency view, and the overall pattern is therefore known as “port/adapter”.

This is a real concern. Cockburn came up with the pattern before TDD was really big so we didn’t think about testing in the same way, and he was happy with the tradeoff of a well-defined adapter that didn’t change very often and therefore didn’t need a lot of ongoing testing because the benefits of putting the “yucky dependency code” (my term, not his) in a separate place was so significant. But it is fair to point to that adapter code and say, “how do you know that the adapter code works?”

In the TDD world, we would like to do better. My first attempt did what I thought was the logical thing to do. I had an adapter that sat on top of the file system, so I put a façade on the file system, and wrote a bunch of adapter tests with a mocked-out file system, and verified that the adapter behaved as I expected it to. Which worked because the file system was practical to mock, but would not have worked with a database system because of the problem with mocking.

Then I read something that Arlo wrote about simulators, and it all made sense.

After I have created a port abstraction, I need some way of testing code that uses a specific port, which means some sort of test double. Instead of using a mocking library – which you already know that I don’t like – I can write a special kind of test double known as a simulator. A simulator is simply an in-memory implementation of the port, and it’s generally fairly quick to create because it doesn’t do a ton of things. Since I’m using TDD to write it, I will end up with both the simulator and a set of tests that verify that the simulator behaves properly. But these tests aren’t really simulator tests, they are port contract tests.

So, I can point them at other implementations of the port (ie the ones that use the real file system or the real database), and verify that the other adapters behave exactly the way the simulator does. And that removes the requirement to test the other adapters in the traditional unit-tested way; all I care about is that all the adapters behave the same way. And it actually gives me a stronger sense of correctness, because when I used the façade I had no assurance that the file system façade behaved the same way the real file system did.

In other words, the combination of the simulator + tests has given me a easy & quick way to write application tests, and it has given me a way to test the yucky adapter code. And it’s all unicorns and rainbows from then on. Because the simulator is a real adapter, it supports other uses; you can build a headless test version of the application that doesn’t need the real dependency to work. Or you can make some small changes to the simulator and use it as an in-memory cache that sits on to of the real adapter.

Using Port/Adapter/Simulator

If you want to use this pattern – and I highly recommend it – I have a few thoughts on how to make it work well.

The most common problem people run into is in the port definition; they end up with a port that is more complex than it needs to be or they expose implementation-specific details through the port.

The simplest way to get around this is to write from the inside out. Write the application code and the simulator & tests first, and then only go and write the other adapters when that is done. This makes it much easier to define an implementation-free port, and that will make your life easier far easier.

If you are refactoring into P/A/S, then the best approach gets a little more complex. You probably have application code that has implementation-specific details. I recommend that you approach it in small chunks, with a flow like this:

  1. Create an empty IDocumentStore port, an empty DocumentStoreSimulator class, and an empty DocumentStoreFileSystem class.
  2. Find an abstraction that would be useful to the application – something like “load a document”.
  3. Refactor the application code so that there is a static method that knows how to drive the current dependency to load a document.
  4. Move the static method into the file system adapter.
  5. Refactor it to an instance method.
  6. Add the method to IDocumentStore.
  7. Refactor the method so that the implementation-dependent details are hidden in the adapter.
  8. Write a simulator test for the method.
  9. Implement the method in the simulator.
  10. Repeat steps 2-9.

Practice

I wrote a few blog posts that talk about port/adapter/simulator and a practice kata. I highly recommend doing the kata to practice the pattern before you try it with live code; it is far easier to wrap your head around it in a constrained situation than in your actual product code.

Lean, Toyota, and how it relates to agile.

January 4, 2016 at 5:22 pm

I like to read non-software-development books from time to time, and during my holiday vacation, I read “The Toyota Way to Continuous Improvement: Linking Strategy and Operational Excellence to Achieve Superior Performance”.

What? Doesn’t everybody relax by reading books about different organizational approaches and business transformation during their holidays?

I highly recommend the book if you are interested in agile processes in the abstract; there’s an interesting perspective that I haven’t been seeing in the part of the agile world I’ve been paying attention to. 

I will note that there are a number of people who have explored and written about the overlap between lean and agile, so I don’t think I’m breaking ground here, but there are a few things that I think are worth sharing.

Value stream mapping

Part of my definition of “being agile” involves change; if you aren’t evolving your process on an ongoing basis, you aren’t agile. I’ve spent a lot of time looking at processes and can now look at a team’s process and have a pretty good idea where they are wasting time and what a better world might look like.

Unfortunately, that isn’t especially useful, because “Do what Eric says you should do” is not a particularly good approach. I don’t scale well, and I have been wrong on occasion.

Shocking, I know.

It also removes the tuning to a specific team’s needs, which is pretty important.

I do know how to teach the “determine an experiment to try during retrospective” approach, and have had decent luck with that, but teams tend to go for low-hanging fruit and tend to ignore big opportunities. Just to pick an example, you can experiment your way into a better process for a lot of things, but the project build that takes 20 minutes and the code review process that takes 8 hours is now dominating your inner loop, and those are the things that you should think about.

I don’t currently have a great way to make these things obvious to the team, a way to teach them how to see the things that I’m seeing. I’m also missing a good way to think about the process holistically, so that the big issues will at least be obvious.

Enter value stream mapping, which is a process diagram for whatever the team is doing. It includes the inputs to the team, the outputs from the team, and all of the individual steps that are taken to produce the output. It also typically includes the amount of time each operation takes, how long items sit in a queue between steps, whether there are rework steps, etc. Here’s a simple diagram from Net Objectives:

The times in the boxes are the average times for each step, and I think the times underneath the boxes are the worst cases. The times between are the average queue times. We also show some of the rework that we are spending time (wasting time) on.

Given all of this data, we can walk all the boxes, and figure out that our average time to implement (ignoring rework) is about 266 hours, or over 6 weeks. Worse, our queue time is just killing us; the average queue time is 1280 hours, or a full 8 *months*. So, on average, we can expect that a new request takes over 9 months to be deployed. We can then look at what the world would be like if we combined steps, reduced queue sizes, or reduced rework. It gives us a framework in which we can discuss process.

This is a simple example; I’m sure that the real-world flow also has a “bugfix” path, and there is likely a “high-priority request” section that is also at work.

I’m also interested in the details inside the boxes. We could decompose the Code box into separate steps:

  1. Get current source and build
  2. Write code
  3. Test code
  4. Submit code for code review
  5. Handle code review comments
  6. Submit code to gated checkin system

Each of these steps has queue times between them, there are likely rework loops for some of them, and the “test” step likely varies significantly based on what you are testing.

Coming up with a value stream mapping is typically the first thing you do with the Toyota approach. I like the fact that it’s a holistic process; you cover all the inputs and the outputs rather than focusing on the things you know about.

I have not tried doing this for a software team yet, but I find the approach very promising and hope to try it soon. I’m especially hoping that it will highlight the impact that big organizational systems have on team agility.

Implementing an improvement

The continuous improvement approach used by Toyota is know as PDCA (either plan-do-check-act or plan-do-check-adjust). Here’s a more detailed explanation of “plan”:

  1. Define the problem or objective
  2. Establish targets
  3. Understand the physics (use 5 whys to figure out what is really going on).
  4. Brainstorm alternatives
  5. Analyze and rank alternatives
  6. Evaluate impact on all areas (this is a “what could go wrong?” step)
  7. Create a visual, detailed, double-ended schedule

I like that it’s organized into steps and overall focuses on the “let’s think about this a bit”. That is good, and I especially like #3 and #6.

On the other hand, agile teams who aren’t used to making changes can easily get stuck in analysis paralysis and can’t actually agree on something to try, and a detailed set of steps could easily make that worse. I’m more concerned that they try *something* at the beginning rather than it be the absolute best thing to try.

So, I’m not sure about this one yet, but it is interesting.

Organic vs Mechanistic

In the book, the talk about two ways of implementing lean. The organic approach is close to the Toyota approach; you send a very experienced coach (sensei) into the group, and they teach the group how to do continuous improvement and stick around for a while. This gives great results, but requires a lot of work to teach the team members and reinforcement to make sure the whole team understands that continuous improvement is their job. It is also sensitive to the environment the group is embedded inside; some groups had made the transition but it didn’t take because management didn’t understand the environment it took to foster the improvement in the first place.

I’m sure that seems familiar to many of you trying to do agile.

The mechanistic approach comes from the Six Sigma folks. It focuses more on top-down implementation; you train up a centralized group of people and they go out across the company to hold Kaizen (improvement) events. That gives you breadth and consistency across the organization – which are good things – but the results aren’t as significant and – more importantly – teams do not keep improving on their own.

As you might have figured out, I’m a big fan of the organic approach, as I see it as the only way to get the ongoing continuous improvement that will take you someplace really great – the only way that you will get a radically more productive team. And I’ve seen a lot of “scrum from above” implementations, and – at best – the have not been significant successes. So, I’m biased.

Interestingly, the book has a case study of a company that owned two shipyards. One took an organic approach and the other took the mechanistic approach. The organic approach worked great where it was tried, but it was difficult to spread across that shipyard without support and it was very easy for the group to lose the environment that they needed to do continuous improvement.

The mechanistic shipyard had not seen the sort of improvements that the organic one saw, but because they had an establish program with executive sponsorship, the improvements were spread more broadly in the enterprise and stuck around a bit better.

The consultants said that after 5 years is was not clear which shipyard had benefitted more. Which I find to be very interesting in how you can do something organic but it’s really dependent on the individuals, and to make something lasting you need the support of the larger organization.

The role of employees

In the Toyota world, everybody works on continuous improvement, and there is an expectation that every employee should be able to provide an answer around what the current issues are in their group and how that employee is helping make things better.

That is something that is really missing in the software world, and I’m curious what sort of improvements you would see if everybody knew it was their job to make things better on an ongoing basis.

The role of management

One of the interesting questions about agile transitions is how the role of management evolves, and there are a lot of different approaches taken. We see everything from “business as usual” to people managers with lots of reports (say, 20-50) to approaches that don’t have management in the traditional sense.

I’m a big believer in collaborative self-organizing approaches, and the best that I’m usually hoping for is what I’d label was “benign neglect”. Since that is rare, I hadn’t spent much time thinking about what optimal management might be.

I think I may now have a partial answer to this. Toyota lives and breathes continuous improvement, and one of the most important skills in management is the ability to teach their system at that level. They have employees whose only role is to help groups with continuous improvement. I think the agile analog is roughly, “what would it be like if your management was made up of skilled agile coaches who mostly focused on helping you be better?”

Sounds like a very interesting world to be in – though I’m not sure it’s practical for most software companies.  I do think that having management focusing on the continuous improvement part – if done well – could be a significant value-add for a team.

Response to comments : You suck at TDD #3–Design sensitivity and improvement

December 18, 2015 at 8:58 am

I got some great comments on the post, and I answered a few in comments but one started to get very long-winded so I decided to convert my response into a post.

Integration tests before refactoring

The first question is around whether it would be a good idea to write an integration test around code before refactoring.

I hate integration tests. It may be the kinds of teams that I’ve been on, but in the majority of cases, they:

  1. Were very expensive to write and maintain
  2. Took a long time to run
  3. Broke often for hard-to-determine reasons (sometimes randomly)
  4. Didn’t provide useful coverage for the underlying features.

 

Typically, the number of issues they found was not worth the amount of time we spent waiting for them to run, much less the cost of creating and maintaining them.

There are a few cases where I think integration tests are justified:

  1. If you are doing something like ATDD or BDD, you are probably writing integration tests. I generally like those, though it’s possible they could get out of hand as well.
  2. You have a need to maintain conformance to a specification or to previous behavior. You probably need integration tests for this, and you’re just going to have to pay the tax to create and maintain them.
  3. You are working in code that is scary.

 

"Scary" means something very specific to me. It’s not about the risk of breaking something during modification, it’s about the risk of breaking something in a way that isn’t immediately obvious.

There are times when the risk is significant and I do write some sort of pinning tests, but in most cases the risk does not justify the investment. I am willing to put up with a few hiccups along the way if it avoids a whole lot of time spent writing tests.

I’ll also note that to get the benefit out of these tests, I have to cover all the test cases that are important. The kinds of things that I might break during refactoring are the same kind of things I might forget to test. Doing well at this makes a test even more expensive.

In the case in the post, the code is pretty simple and it seemed unlikely that we could break it in non-obvious way, so I didn’t invest the time in an integration test, which in this case would have been really expensive to write.  And the majority of the changes were done automatically using Resharper refactorings that I trust to be correct.

Preserving the interface while making it testable

This is a very interesting question. Is it important to preserve the class interface when making a class testable, or should you feel free to change it? In this case, the question is whether I should pull the creation of the LegacyService instance out of the method and pass it in through the constructor, or instead use another technique that would allow me to create either a production or test instance as necessary.

Let me relate a story…

A few years ago, I led a team that was responsible for taking an authoring tool and extending it. The initial part had been done fairly quickly and wasn’t very well designed, and it had only a handful of tests.

One day, I was looking at a class, trying to figure out how it worked, because the constructor parameters didn’t seem sufficient to do what it needed to do. So, I started digging and exploring, and I found that it was using a global reference to an uber-singleton that give it access to 5 other global singletons, and it was using these singletons to get its work done. Think of it as hand-coded DI.

I felt betrayed and outraged. The constructor had *lied* to me, it wasn’t honest about its dependencies.

And that started a time-consuming refactoring where I pulled out all the references to the singletons and converted them to parameters. Once I got there, I could now see how the classes really worked and figure out how to simplify them.

I prefer my code to be honest. In fact, I *need* it to be honest. Remember that my premise is that in TDD, the difficulty of writing tests exerts design pressure and that in response to that design pressure, I will refactor the code to be easier to test and that aligns well with "better overall". So I am hugely in preference of code that makes dependencies explicit, both because it is more honest (and therefore easier to reason about), and because it’s messy and ugly and that means I’m more likely to convert it to something that is less messy and ugly.

Or, to put it another way, preserving interfaces is a non-goal for me. I prefer honest messiness over fake tidiness.

You suck at TDD #2–Mocking libraries

December 10, 2015 at 8:20 am

Note: I am focusing only on the design impact of TDD. To better understand the overall impact, see this series of posts by Jay Bazuzi.

My first experience with TDD was back in 2002 or so, and it was in C++, so there weren’t any mocking libraries available. That meant that I had to use hand-written mocking classes.

When hand-mocking, you need to create separate classes, write each of the methods that you need, etc. If the scenario is complex, you may have to write several classes that coordinate with each other to accomplish the mock. It’s more than a little pain at times, and creating a new class always seems like a bit of an interrupt in my train of thought.

That is as it should be. One of my foundational principles of running development teams is that pain – which, in this context, means, "tedious things I have to do instead of writing new code" – is a great incentive. That which is tedious is an automatic target for reduction and elimination. So, you have developers fix their own bugs because it will cause them pain to do so.

(This is, of course, not a panacea; there are plenty of organizations where this will not result in better quality because the incentive towards writing bugs is so strong, but I digress…)

Then mocking libraries showed up the scene. No need to write new classes, just write some mocking code and you’re done. That reduced the pain and reduced the design pressure that ‘the test is hard to write" was exerting, which reduces the improvement.

Then a few mocking libraries showed up that let you mock statics, which allows you to test things that were totally untestable before, and that further reduced the design pressure. You can do some pretty ugly things with those libraries…

Refactoring gets harder

Many of the mocking libraries have another problem – they use a string-based approach for defining their mocks. This means that they are not refactoring-friendly; after you refactor your code, you find out that your tests won’t even run; you have to go and hand-modify them so that they now match your new refactoring. This makes refactoring more painful, and makes it more likely that you will just skip the refactoring

Discussion

As you have probably gathered, I am not a fan of mocking libraries. They make it too easy to do things that I think you shouldn’t, and they short circuit the feedback that you would otherwise be feeling. Embrace the pain of writing your own mocks, and use that to motivate you towards better solutions. I’ll be talking more about better solutions in future posts.

There is one situation where mocking libraries are great; if I need to bring an existing codebase under test so that I won’t break it as I work on it. In that case, I need their power, and I will plan to get rid of them in the longer term.

You suck at TDD #1: Rewrite the steps

December 4, 2015 at 8:05 am

I’ve been paying attention to TDD for the past few years – doing it myself, watching others doing it, reading about it, etc. – and I’ve been seeing a lot of variation in the level of success people are having with it. As is my usual approach, I wrote a long and tedious post about it, which I have mercifully decided not to inflict on you.

Instead, I’m going to do a series of posts about the things I’ve seen getting in the way of TDD success. And, in case it isn’t obvious, I’ve engaged in the majority of the things that I’m going to be writing about, so, in the past, I sucked at TDD, and I’m sure I haven’t totally fixed things, so I still suck at it now.

Welcome to "You suck at TDD"…

Rewrite the steps

The whole point of TDD is that following the process exerts design pressure on your code so that you will refactor to make it better (1). More specifically, it uses the difficulty in writing simple test code as a proxy for the design quality of the code that is being tested.

Let’s walk through the TDD steps:

  1. Write a test that fails

  2. Make the test pass

  3. Refactor

How does this usually play out? Typically, we dive directly into writing the test, partly because we want to skip the silly test part and get onto the real work of writing the product code, and partly because TDD tells us to do the simplest thing that could possible work. Writing the test is a formality, and we don’t put a lot of thought into it.

The only time this is not true is when it’s not apparent how we can actually write the test. If, for example, a dependency is created inside a class, we need to do something to be able to inject that dependency, and that usually means some refactoring in the product code.

Now that we have the test written, we make the test pass, and then it’s time to refactor, so we look at the code, make some improvements, and then repeat the process.

And we’re doing TDD, right?

Well…. Not really. As I said, you suck at TDD…

Let’s go back to what I wrote at the beginning of the section. I said that the point of TDD was that the state of our test code (difficult to write/ugly/etc) forced us to improve our product code. To succeed in that, that means that our test code has to either be drop-dead-simple (setup/test/assert in three lines) or it needs to be evolving to be simpler as we go. With the exception of the cases where we can’t write a test, our tests typically are static. I see this all the time. 

Let’s try a thought experiment. I want you to channel your mindset when you are doing TDD. You have just finished making the test pass, and you are starting the refactor set. What are you thinking about? What are you looking at?

Well, for me, I am focused on the product code that I just wrote, and I have the source staring me in the face. So, when I think of refactoring, I think about things that I might do to the product code. But that doesn’t help my goal, which is to focus on what the test code is telling me, because it is the proxy for whether my product code is any good.

This is where the three-step process of TDD falls down; it’s really easy to miss the fact that you should be focusing on the test code and looking for refactorings *there*. I’m not going to say that you should ignore product code refactorings, but I am saying that the test ones are much more important.

How can we change things? Well, I tried a couple of rewrites of the steps. The first is:

  1. Write a test that fails

  2. Make the test pass

  3. Refactor code

  4. Refactor test

Making the code/test split explicit is a good thing as it can remind us to focus on the tests. You can also rotate this around so that "refactor tests" is step #1 if you like. This was an improvement for me, but I was still in "product mindset" for step 4 and it didn’t work that great. So, I tried something different:

  1. Write a test that fails

  2. Refactor tests

  3. Make the test pass

  4. Refactor code

Now, we’re writing the test that fails, and then immediately stopping to evaluate what that test is telling us. We are looking at the test code and explicitly thinking about whether it needs to improve. That is a "good thing".

But… There’s a problem with this flow. The problem is that we’re going to be doing our test refactoring while we have a failing test in our test suite, which makes the refactoring a bit harder as the endpoint isn’t "all green", it’s "all green except for the new test".

How about this:

  1. Write a test that fails

  2. Disable the newly failed assertion

  3. Refactor tests

  4. Re-enable the previously failing assertion

  5. Make the test pass

  6. Refactor code

That is better, as we now know when we finish our test refactoring that we didn’t break any existing tests.

My experience is that if you think of TDD in terms of these steps, it will help put the focus where it belongs – on the tests. Though I will admit that for simple refactorings, I often skip disabling the failing test, since it’s a bit quicker and it’s a tiny bit easier to remember where I was after the refactoring.

Agile Transitions Aren’t

October 31, 2015 at 9:37 pm

A while back I was talking with a team about agile. Rather than give them a typical introduction, I decided to talk about techniques that differentiated more successful agile teams from less successful ones. Near the end of the talk, I got a very interesting question:

"What is the set of techniques where, if you took one away, you would no longer call it ‘agile’?"

This is a pretty good question. I thought for a little bit, and came up with the following:

  • First, the team takes an incremental approach; they make process changes in small, incremental steps
  • Second, the team is experimental; they approach process changes from a "let’s try this and see if it works for us" perspective.
  • Third, the team is a team; they have a shared set of work items that they own and work on as a group, and they drive their own process.

All of these are necessary for the team to be moving their process forward. The first two allow process to be changed in low risk and reversible way, and the third provides the group ownership that makes it possible to have discussions about process changes in the first place. We get process plasticity, and that is the key to a successful agile team – the ability to take the current process and evolve it into something better.

Fast forward a few weeks later, and I was involved in a discussion about a team that had tried Scrum but hadn’t had a lot of luck with it, and I started thinking about how agile transitions are usually done:

  • They are implemented as a big change; one week the team is doing their old process, then next they (if they are lucky) get a little training, and then they toss out pretty much all of their old process and adopt a totally different process.
  • The adoption is usually a "this is what we are doing" thing.
  • The team is rarely the instigator of the change.

That’s when I realized what had been bothering me for a while…

The agile transition is not agile.

That seems more than a little weird. We are advocating a quick incremental way of developing software, and we start by making a big change that neither management or the team really understand on the belief that, in a few months, things will shake out and the team will be in a better place. Worse, because the team is very busy trying to learn a lot of new things, it’s unlikely that they will pick up on the incremental and experimental nature of agile, so they are likely going to go from their old static methodology to a new static methodology.

This makes the "you should hire an agile coach" advice much more clear; of course you need a coach because otherwise you don’t have much chance of understanding how everything is supposed to work. Unfortunately, most teams don’t hire an agile coach, so it’s not surprising that they don’t have much success.

Is there a better way? Can a team work their way into agile through a set of small steps? Well, the answer there is obviously "Yes", since that’s how the agile methods were originally developed.

I think we should be able to come up with a way to stage the changes so that the team can focus on the single thing they are working on rather than trying to deal with a ton of change. For example, there’s no reason that you can’t establish a good backlog process before you start doing anything else, and that would make it much easier for the agile teams when they start executing.

Resharper tip #1: Push code into a method / Pull code out of a method

October 12, 2015 at 2:59 pm

Resharper is a great tool, but many times that operation that I want to perform isn’t possible with a single refactoring; you need multiple refactorings to get the result that you want. I did a search and could find these anywhere, so I thought I’d share them with you.

If you know where more of these things are described and/or you know a better way of doing what I describe, please let me know.

Push code into a method

Consider the following code:

   1: static void Main(string[] args)

   2: {

   3:     DateTime start = DateTime.Now;

   4:  

   5:  

   6:     DateTime oneDayEarlier = start - TimeSpan.FromDays(1);

   7:     string startString = start.ToShortDateString();

   8:  

   9:     Process(oneDayEarlier, startString);

  10:  

  11: }

  12:  

  13: private static void Process(DateTime oneDayEarlier, string startString)

  14: {

  15:     Console.WriteLine(oneDayEarlier);

  16:     Console.WriteLine(startString);

  17: }

Looking at the code in Main(), there are a couple of variables that are passed into the Process() method. A little examination shows that things would be cleaner they were in the Process method, but there’s no “move code into method” refactoring, so I’ll have to synthesize it out of the refactorings that I have. I start by renaming the Process() method to Process2(). Use whatever name you want here:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         DateTime start = DateTime.Now;

   6:  

   7:  

   8:         DateTime oneDayEarlier = start - TimeSpan.FromDays(1);

   9:         string startString = start.ToShortDateString();

  10:  

  11:         Process2(oneDayEarlier, startString);

  12:  

  13:     }

  14:  

  15:     private static void Process2(DateTime oneDayEarlier, string startString)

  16:     {

  17:         Console.WriteLine(oneDayEarlier);

  18:         Console.WriteLine(startString);

  19:     }

  20: }

Next, select the lines that I want to include into the method plus the method call itself, and do an Extract Method refactoring to create a new Process() method:

   1: static void Main(string[] args)

   2: {

   3:     DateTime start = DateTime.Now;

   4:  

   5:  

   6:     Process(start);

   7: }

   8:  

   9: private static void Process(DateTime start)

  10: {

  11:     DateTime oneDayEarlier = start - TimeSpan.FromDays(1);

  12:     string startString = start.ToShortDateString();

  13:  

  14:     Process2(oneDayEarlier, startString);

  15: }

  16:  

  17: private static void Process2(DateTime oneDayEarlier, string startString)

  18: {

  19:     Console.WriteLine(oneDayEarlier);

  20:     Console.WriteLine(startString);

  21: }

Finally, inline the Process2() method:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         DateTime start = DateTime.Now;

   6:  

   7:  

   8:         Process(start);

   9:     }

  10:  

  11:     private static void Process(DateTime start)

  12:     {

  13:         DateTime oneDayEarlier = start - TimeSpan.FromDays(1);

  14:         string startString = start.ToShortDateString();

  15:  

  16:         Console.WriteLine(oneDayEarlier);

  17:         Console.WriteLine(startString);

  18:     }

  19: }

Three quick refactorings got me to where I wanted, and it’s about 15 seconds of work if you use the predefined keys.

Pull Code Out of a Method

Sometimes, I have some code that I want to pull out of a method. Consider the following:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         int n = 15;

   6:  

   7:         WriteInformation("Information: ", n);

   8:     }

   9:  

  10:     private static void WriteInformation(string information, int n)

  11:     {

  12:         File.WriteAllText("information.txt", information + n);

  13:     }

  14: }

I have a few options here. We can pull “information.txt” out easily by selecting it and using Introduce Parameter:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         int n = 15;

   6:  

   7:         WriteInformation("Information: ", n, "information.txt");

   8:     }

   9:  

  10:     private static void WriteInformation(string information, int n, string filename)

  11:     {

  12:         File.WriteAllText(filename, information + n);

  13:     }

  14: }

I could use that same approach to pull out “information + n”, but I’m going to do it an alternate way that works well if I have a chunk of code. First, I introduce a variable:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         int n = 15;

   6:  

   7:         WriteInformation("Information: ", n, "information.txt");

   8:     }

   9:  

  10:     private static void WriteInformation(string information, int n, string filename)

  11:     {

  12:         string contents = information + n;

  13:         File.WriteAllText(filename, contents);

  14:     }

  15: }

I rename the method:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         int n = 15;

   6:  

   7:         WriteInformation2("Information: ", n, "information.txt");

   8:     }

   9:  

  10:     private static void WriteInformation2(string information, int n, string filename)

  11:     {

  12:         string contents = information + n;

  13:         File.WriteAllText(filename, contents);

  14:     }

  15: }

And I now extract the code that I want to remain in the method to a new method:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         int n = 15;

   6:  

   7:         WriteInformation2("Information: ", n, "information.txt");

   8:     }

   9:  

  10:     private static void WriteInformation2(string information, int n, string filename)

  11:     {

  12:         string contents = information + n;

  13:         WriteInformation(filename, contents);

  14:     }

  15:  

  16:     private static void WriteInformation(string filename, string contents)

  17:     {

  18:         File.WriteAllText(filename, contents);

  19:     }

  20: }

And, finally, I inline the original method:

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         int n = 15;

   6:  

   7:         string contents = "Information: " + n;

   8:         WriteInformation("information.txt", contents);

   9:     }

  10:  

  11:     private static void WriteInformation(string filename, string contents)

  12:     {

  13:         File.WriteAllText(filename, contents);

  14:     }

  15: }