David's Blog

The Mock Objects Trap

In a previous post, I wrote about integrated tests and how they actually decrease your chance to catch regressions, decrease testability of the system and can lead to a test suite where nobody really trusts the results. That post captures some of my thoughts after hearing a talk and reading an article by J.B. Rainsberger about the topic.

So, what is the solution?

Mock Objects vs. Integrated Tests

J.B. Rainsberger presented a simple solution (and this is also the solution that I prefer, most of the time, so I am a bit biased ;) ):

Say you want to develop a class (or module or function) A that uses B and C.

  • First develop A without having B or C at all in a test-driven way. As you write tests for A, you define the interfaces of B and C, but as of now, you just stub them, preferably with a mocking framework (because you can then use the mock objects in your tests to verify that A behaves correctly).
  • Then, develop B and C in a test-driven way. Look at your mock objects from the first step to see how A uses B and C and create unit tests with that knowledge. Then implement B and C. Create more interfaces and mock objects for the collaborators of B and C if necessary.
  • You now have tests for A that show you A uses B and C in a way that you deem correct. And you have tests for B and C that show you that B and C behave correctly if used in a way like A uses them. Now you wire the classes up, and they will "just work".

This process is often called "Outside-In TDD" or "Controller-First TDD" or "London School TDD" or "Mockist TDD Style".

The caveat here is that this only "just works" when the mock objects used in the A tests (which document how A uses B and C) and the tests for B and C are always in sync. So, when you change a mock object that A uses, you also have to change a test for either B or C. Unfortunately, I know of no automated tool that could help you with that.

Why Not Work Like That?

After J.B.'s talk, I heard someone in the audience say:

That's nice in theory, but this will never work on a real project. We had mock objects. It was a mess.

And I hear that sentiment quite often. There is a huge resentment against mock objects in a large part of the programming community, while the other part loves them. Why is that?

"Our project is a special snowflake". I have seen this attitude at some of my past clients, and in many different programmers. "We cannot use Mock objects because...". "We cannot do TDD here because...". "Agile will not work in this company because...". "This solution will never work on a real/big/complex/hardware/... project, because..."

The project or company is often not that special. In most of those situation, I got the impression that they tried the thing, failed (because they didn't really try it, made some basic mistakes, didn't change their attitude/behavior or didn't seek out for outside help), and now blame their their failure on the thing they tried.

This is what I call "The Mock Objects Trap" when talking about TDD with mock objects.

The Mock Objects Trap

The mock objects trap happens when you use mock objects in a certain way. (If you are not sure what mock objects are or want to refresh your knowlege about test doubles, stubs, fakes, mocks, etc. , read Mocks Aren't Stubs by Martin Fowler before reading on...)

Mocks to Make the Untestable Testable

Mocks can help you to make untestable code testable.

Say you have a class that cannot be instantiated or tested on it's own because it has so many collaborators. And you cannot test the correct behavior of the class because there is no accessible state - The class just calls some methods of it's collaborators.

With a mocking framework, you can still test this class: You stub out all the collaborators, and add expectations or verification for the expected interactions (Note that this is a different use of mocking frameworks than I described in "Outside-In TDD" above). You can now test this class. But, as we will see later, if you are not careful, this can be the first step into the mock objects trap.

Mocks to Cover Up for Bad Practice

Recently I have read an article called "All Your Mocks Are Evil!!". It's a long rant about how mocks are bad, because people use them to cover up all kinds of bad practice.

Say you have some business logic in your data access layer. Without mock objects, this would be hard to test. But with mock objects, you just stub / verify some database calls, and now you can test the business logic. The problem is: This business logic does not belong here! But the tests are there and they are green, so this will probably go unnoticed.

Mock objects can be used to hide architecture and design problems. This is step two into the mock objects trap.

Mocks that Lock Down an Implementation

Some tests use mocks in a way that the test creates a lock on how the code is implemented.

Now you cannot change the code anymore without breaking the tests. Even if you did not change the functionality! This means that every time you refactor some code, you will break some tests.

Your tests should be a safety net for refactoring, where the tests stay green when you got the refactoring right (i.e. when you changed some code without changing the behavior of the system). But now your tests have become an impediment to refactoring! This is the final step into the mock objects trap.

Why is it a Trap?

This is a trap because it happens to many programmers when they first try out mock objects. Because they are just starting out with mock objects, they don't notice the problems until it is too late. And then they hate mock objects and never touch them again. Some write angry blog posts. The story goes like this:

The programmer is working on a legacy system and they want to write automated tests for a specific aspect of that system. The problem is: All involved classes are really hard to test. They have dependencies everywhere and you cannot instantiate them on their own.

So the programmer downloads Mockito and stubs out all the dependencies. She also downloads PowerMock because she wants to stub some static or final methods.

Because the system under test is still very hard to understand and to test, the programmer writes coarse-grained, unfocused tests. And because it is not clear which details are important (it's legacy code, after all!), she verifies all the interactions the code has with the mocks.

Now we have a system that actually got worse by adding tests with mocks: The tests are unfocused (and thus hard to read and debug). And they lock down the bad practice that exists within the system: When you try to refactor anything, multiple tests will break, even though you didn't change any functionality.

And this is the first and only experience many programmers have with mocks. This is the "Mock Objects Trap".

To Recap...

Tests should put a positive pressure on our design. They should help us refactor our code by providing a safety net. We can achieve this with or without mock objects.

But when we are not careful, the mock objects we use might actually hide some design problems or lock down the actual implementation of a class, not it's visible, desired behavior. Then we have created an evil unit test (N.B.: You can create accidentally create evil unit tests without mock objects too).

The "mock objects trap" is a trap because many programmers unintentionally create such evil unit tests when they first use mock objects. But they only find out about the problems with those tests later - When they have many of them and when the tests have become an impediment to refactoring.

And many of those programmers then blame mock objects and won't use them again - not even in situations where they would make sense and provide huge benefits.

Have you experienced the problems with mock objects I have described above? How can I help you to overcome them? Please tell me!

Posting Type: 

A New Testing Framework for Swift

Last week, Rene Pirringer and I sat together and collected some ideas for a new test framework for the Swift programming language. Everything we did (and want to do) was heavily inspired by JUnit 5.

This is a very quick overview of what we are trying to do. I guess I will write more about this topic in the future ;)

Why a New Testing Framework?

There are at least two good testing frameworks for Swift: XCTest, which originally comes from the Objecive C world, and Quick, which has some very interesting features. So why write a new one?

Some time ago, Rene and I hosted a "Test Driven Development for iOS with Swift" workshop, and after that we discussed some differences between JUnit 4 and XCTest, like a few JUnit features we were missing in XCTest. A few days later we saw a great talk about JUnit 5 by Jens Schauder.

We decided that we want to try and bring some JUnit features to Swift. Like dynamic tests, assumptions, test extensions, ... To be able to do this, we need a flexible test framework architecture.

Basic Architecture

We want to support running tests written with different testing technologies (our framework, XCTest, Quick, ...). And we want to be able to run them with different runners (XCTest compatible, console, ...).

A TestEngine is responsible for knowing all the tests in the project written with a given technology and for knowing how to execute a test. For example, there might be a XCTestEngine, a QuickTestEngine and a SwiftTestEngine. When an engine executes a single test, it reports the result in a technology-agnostic way (Pass/Fail/Inconclusive + Message).

A Runner is responsible for actually running the tests and displaying the results. For example, a XCTestRunner would ask all engines for their tests and create a list of tests that can be understood by XCTest from that. Then, when XCTest tries to execute a test, the runner will actually execute it with the test's engine, and then translate the result to "XCTFail" if the test failed.

We would probably write our own ConsoleTestRunner and an XCTestRunner which would run the tests in a way that is compatible with the new XCTest API (i.e. passes them to XCTMain). We assume that, with the second runner, we will be compatible with existing IDEs. But the better integration would be when IDEs would implement their own runner. Then they would be immediately compatible with all testing frameworks that provide a TestEngine.

On top of that, we can implement our own test engine, where we can experiment with stuff. Like having more nuanced test results, not only "pass/fail", which we would need for ignored tests and assumptions.

Next Steps

We want to implement a prototype, of course. But we also want to gather some feedback early, so we will talk to some people who are interested in Testing and/or Swift.

Do you have some feedback for us? What features / capabilities would you like to see in a new testing framework? Please write a short email: Feedback SwiftTest.

P.S.: Do you want to learn and/or practice Test Driven Development in Swift (or any other language)? Have a look at my TDD Basics Training!

Posting Type: 

Getting The Details Right is as Important as Your Architecture

This post has been translated to Chinese by Zhang Wei: Getting the Details Right (Chinese)

On the internet, you can find more definitions for "Software Architecture" than I want to list here. But I hope you agree with me that software architecture is more about the high level structure of a system, and "software design" is more about the details, the low-level stuff.

The more I think about it, the more I realize: If you don't get those little details right, you cannot have a great high-level structure. If you don't have a good software design, your software architecture also cannot be that great.

Which Details?

I am talking about the little design decisions we take every day, every hour. Almost every minute.

How do I name this variable, function or class? When should I split a function or class? Can I make this function pure or does it make more sense right here to reference some state? How should other modules access / use this module? Am I missing an abstraction here? Is there another place in the code where a developer has to know the same concepts this code deals with? How do I design the interface of this module to its test? What should my next test do? Is this test small, focused, independent and clear? ...

We design all the time when we are writing code. You cannot not design when you program. You cannot not answer the questions from above. But when you do not think about them, your answer will not be the best solution - Maybe even not a good one.

Care

When some members of your team do not care enough to keep the design clean and good, they will also not care enough to keep the architecture in a good shape.

Code does not really "rot". As long as we do not touch it, it stays exactly like it is. But as soon as we make changes, it seems to get worse. That's because with every careless design decision you will cause damage. Sometimes just a little damage, sometimes a lot.

It takes a lot of effort and care to keep code clean. But you have to do it, otherwise you will become slower and slower over time. And everybody on the team has to take part - Everybody has to care.

Good Names and other Design Principles

When you cannot find good names for the "little things", you will have a hard time figuring out where to change code when you have to. No matter how well-documented your architecture is.

If you do not stick to the dependency inversion principle, you'll have technical details littered over your business code. Your clean, layered architecture alone will not protect you.

If your classes, modules and methods have multiple responsibilities and direct dependencies, changes will ripple through your system. And you won't see this in your architecture diagrams, with their clear-cut components.

I could go on with other design principles that mostly effect your low-level design and still can undermine your architecture. Well, you might say, "If it can undermine my architecture, then it's really and architectural decision". But I think this is a slippery slope - Soon, every design decision will be an architectural one.

Tests and Documentation

Good design is also about good tests - And a well designed interface between your tests and your production code.

Tests - especially "micro tests" - can be a great technical documentation of your software design. But only when you write good, independent tests and give them good names. You need to design the interface of your tests to the production code, and the interface of your tests to the programmer who has to interpret a negative test result!

But when you get this right, the test are better than any other documentation you could write: They cannot be outdated - Either they are still relevant or they will fail. Beware: Even if you have great tests as documentation, you might still need some other forms of technical documentation!

Can you also use tests as architecture documentation? You might be able to document some aspects of your architecture using automated tests. But a good architecture documentation does not only document the high-level structure of your system. It also documents all the decisions you took and why you took them.

So, to really document your architecture, you will also need additional documentation. The Arc42 Template is a good start. But do not overdo it: Keep the document short - Just add what is absolutely necessary!

When you do not get the documentation of your design details - The production modules/functions and their micro tests - right, you will again undermine your architecture: Your architecture documentation will tell you in which general area to look for something. But when you arrive there, you need clean code, documentation and tests to navigate to the exact place.

Why is this Important?

I have worked with many code bases that are hard to maintain (because helping customers to improve their hard-to-maintain codebase is one of the services I provide). And in my experience, it's not a few, huge architectural problems that cause the majority of the pain. Sure, those are often there, and they cause big problems.

But most of the pain comes from the thousands of small design problems that are there. A method with a bad name. Calling a method from a collaborator that should really be somewhere else. Huge modules and functions. Tests that are not independent. Tests with bad names. Test suites where one little change in the production code can break 10, 20 or more of your tests.

Sure, sometime you just have to get something out on time, and fix it later. But when you neglect your your design for too long, those little problems will slow you down considerably. And this slowdown happens much earlier than most developers would expect. It can happen a few weeks or even days or hours after you took a "short cut".

Micro Services to the Rescue?

Do we still need a good internal design when we do micro services? We are writing them for replacement, not for reuse, right? We are planning to throw some of them away on a regular basis...

Well, it depends. Mostly on the size of your micro services. And as far as I can tell, the internet did not come to a conclusion about the "right" size for micro services yet...

So, if your micro services are "big" (on a relative scale) and vertically integrated, you should keep their internal design clean. Because the code of each "self contained system" will be big enough that a mess will slow down your future development considerably!

But if your micro services are really small (just a hand full of functions or classes), then you still have to take care about the little things - but some of those little design decisions now affect how your micro services work together, and not the modules within a micro service.

Good Design != Good Architecture

You need to get the details right to have a good architecture. But just because you have a good low-level design does not automatically mean that you have a good architecture.

You have to care about both. But if you want to get started, start with the design: You can easily practice it in a small part of your code or even in a training. You can refactor more and more of your code to have a nice internal design. When you are getting good at this, start thinking about the bigger scheme of things - Start designing your architecture.

Start Improving!

If you want, you can start now. Try TDD, and get help if it does not work for you. Learn about good design - for example, the SOLID principles, the four rules of simple design, coupling and cohesion, ...

But at some point, you need to get your whole team on the same page. You have to sell them on better design. Otherwise, somebody else will always undermine the design improvements you are trying to make.

Posting Type: 

Boilerplate vs. Magic

Just about a month ago, Phil Webb tweeted:

What would you like to complain about?

[ ] Too much magic
[ ] Too much boilerplate

Phil Webb - @phillip_webb

and just a little bit later, Josh Long tweeted:

“too much magic” = you haven’t read the docs on @SpringBoot ’s auto-configuration

http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference...

Josh Long - @starbuxman

Here's my take...

Magic

Magic means that things happen at runtime that I cannot immediately explain just by reading the code. At least to me. I know, this definition is quite fuzzy. There is always something that happens at runtime that cannot be expected by reading the code, even if you program assembler (processors are weird). The difference between "not magic" and "magic" here is just "How big is the surprise?".

But I would definitely consider a method that violates the "Single Responsibility Principle" or "Command / Query Separation" to be magic (from the caller's point of view):

public User getUser(final long userId) {
    transactionManager.newTransaction();

    User user = userRepository.get(userId);
    user.setLastAccessed(System.currentTimeMillis());
    userRepository.save(user);

    transactionManager.commitTransaction();
    return user;
}

When you just read code that calls this method, you will never expect that this method changes the user in the database. But you can just open the code of the method and find out. So the magic here is not quite strong (i.e. on a very low level).

Here's another one:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void persistLastAccessTime(User user) {
    user.setLastAccessed(System.currentTimeMillis());
    userRepository.save(user);
}

Now the method is reasonably named. It sets the access time and persists the user. It still does two things (violating the SRP), but they are somewhat related. And it always runs in its own transaction.

The magic that happens here cannot be found in the code itself anymore. The magical thing here is how Spring implements the Transaction - Especially the "REQUIRES_NEW": It suspends the current database connection and opens a new connection for the new transaction. It's the only way REQUIRES_NEW semantics can be implemented with most (if not all) relational databases.

Your code will work fine in your unit tests, it will work fine in your integration tests, it will even work fine when you test it on your staging server. But then you start a load test, and everything breaks down. What has happened? You didn't carefully configure your database connection pool size to be much bigger than your thread pool size, and you ran out of database connections.

This doesn't have to happen. If you read the documentation really carefully, you can find out that you will need much more parallel DB connections with REQUIRES_NEW than without. But the point is: To find out what's really happening, you have to read the documentation and know what that means for your application, or you have to load test. This is a stronger kind of magic.

One last example, again with Spring, but this time it's Spring Boot:

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

This is the complete source code of a demo application. When running this class, Spring Boot will start an in-process web server. If we go with my definition from above, this is definitely magic.

Boilerplate

Boilerplate code is code that you have to write again and again. You'll write it in every application you work on. Sometimes you even have to write it multiple times in the same application. It's the boring code, that nobody really likes to write.

Boilerplate, Magic

Magic and boilerplate are both subjective. Look again at the transaction annotation example from above... Some developers I know would immediately say "Well, of course this requires a new DB connection" while others would be quite surprised that the defect I described can really happen under high load.

And with the Spring Boot demo application, the whole point of writing the application like this is to have Spring Boot do a lot of work for you in the background. So I, personally, hope that people who write code like this know what they are doing (i.e. that they know Spring Boot well enough).

Magic and boilerplate are not necessarily bad. Consider the Spring transaction magic from above: Yes, writing begin and commit is not really hard. And if you would have done it yourself, you definitely would have spotted the too-many-sessions-but: You would have realized that you cannot implement the "REQUIRES_NEW" on the current session. On the other hand, if you always write "begin" at the beginning of a method and "commit" at the end, this is quite redundant.

Or let's look at Spring Boot: Yes, configuring and starting an in-process web server is not hard - it's just a couple of lines of code. But if you have to configure multiple things (a web server, JPA, REST endpoints, ...), it will become quite a bit of boilerplate and Spring Boot can really help you focus on what is important in your application.

Boilerplate is not the opposite of magic! You can have both in the same code base, even in the same class. You can have a single class where there is a lot of boilerplate and where you cannot explain everything that happens just by reading the code.

And you can also have neither: If you find the right abstractions, you can have really expressive, self-documenting code. Code where everything you need to know about what it does can be found within the code itself. And this code will contain no boilerplate, because you found the right abstractions. This is easier with some languages than with others, but I don't think there is any language which make reducing boilerplate impossible (at least for most boilerplate).

Too Much Magic

Boilerplate is mostly a problem when writing code. Magic when reading & debugging. We read & debug more than we write.

David Tanzer - @dtanzer

Libraries and tools that do magic for us help us to develop software faster. They make the boring tasks go away and help us focus on our business code. That's the theory, at least.

On the other hand, they sometimes make reading and debugging our code harder. You want to step into a method, but can't, since the method was created with a byte code manipulation library. Or you read the code of some method you want to call, but don't see all its behavior, since some aspect oriented programming tool adds behavior at run time.

Libraries and frameworks where I constantly have to read documentation or debug code I didn't write are in this category for me: They make it harder for me to understand my own code. Don't get me wrong: I know that I have to learn and understand the tools I am using. But with some tools, I have to come back to the documentation or open the debugger more often and for longer than with others.

Since we spend much more time reading and debugging code than writing new code, I really don't want too much magic like this - i.e. magic that makes reading and debugging code harder - in my code.

Too Much Boilerplate

Too much boilerplate is worse for me.

I would mostly prefer annotation generation magic over writing stuff myself. If I understand the tools it is less code to read.

Janusz Leidgens - @Killerdackel

Boilerplate is mostly a problem when writing code for the first time. You have to write it, and you have to get it right. But after that, you won't touch that code anymore.

Boilerplate is not so much a problem when reading code. It is often easy to understand and easy to recognize. So you can just skip it.

Since we spend much more time reading and debugging code than writing new code, I usually don't mind a little bit of boilerplate code. But Janusz has a point here: If you have a lot of boilerplate code, you have more code to read and more code to maintain.

What Now?

Check boxes, not radio buttons. *takes hat off*

What would you like to complain about?

[ ] Too much magic
[ ] Too much boilerplate

Samir Talwar - @SamirTalwar

Of course, too much boilerplate and too much magic both are problems. As I said above, boilerplate is not the opposite of magic. You can have both, and you can have none of them.

You can write expressive code that gives you a lot of information about what is happening just by using good names and following some general design principles. And when you find the right abstractions for your program, you will still have very little boilerplate.

If you have a statically typed language, you can write your code in a way that your type checker or compiler tells you if you got something wrong. This will make your code even more expressive and safer. For example, when you use Spring, use the Java configuration whenever possible. The compiler will prevent you from making a big number of mistakes you could make with the XML configuration.

And always try to eliminate both: Boilerplate and magic.

Posting Type: 

6 Reasons Why You Should Avoid Singletons

A little more than a decade ago, I used singletons a lot. I had a shortcut in eclipse where I only had to write "singleton" and press "CTRL+Space", and boom: Eclipse would generate all the necessary code to make the currently open class be a singleton. Since then, I learned a lot. And the tools we have to avoid Singletons (i.e. the Singleton Pattern) have matured. Now I try to avoid the singleton pattern like the plague. Here is why...

Yes, I am really writing a blog about why the "Singleton Pattern" is bad. In 2016. But it comes up in discussions time and again, so here is a list of reasons why you should avoid singletons.

Actually, there's nothing wrong with having only one instance of an object. But using the "Singleton Pattern" to achieve this is never the best solution. Towards the end of this post, I will show you why and how you can do it better.

Some of the reasons why using the "Singleton Pattern" is bad are closely related to others. Like, "Inversion of Control Violation" has mostly the same consequences as "Coupling to Concrete Implementation". But I will list them separately anyway because they give you different motivations to avoid the Singleton Pattern.

The Singleton Pattern

The singleton pattern is a design pattern that you can use when you need exactly one instance of an object. An implementation looks like this:

public class InterestingThingsDoer {
    private static InterestingThingsDoer instance = new InterestingThingsDoer();

    //possible some instance state

    private InterestingThingsDoer() {}

    public static InterestingThingsDoer getInstance() {
        return instance;
    }

    public ResultType doSomethingInteresting() {
        //something interesting
    }
}

Callers can now get the single instance of the Singleton and make it perform some work for them:

public void evenMoreInteresting() {
    InterestingThingsDoer doer = InterestingThingsDoer.getInstance();
    ResultType result = doer.doSomethingInteresting();
    //do something even more interesting...
}

Great - Now you can implement your abstract factories, services, facades, ... in a way that guarantees that every caller operates on the same, shared instance. What could possibly go wrong?

Coupling to Concrete Implementation

Singletons couple all callers to the concrete implementation of the singleton, because the callee asks for the singleton object. Your classes become harder to test: You cannot test them in isolation, without also running code from the Singleton.

In the example from above, you cannot test the method "evenMoreInteresting" without also running some code from "InterestingThingsDoer". You cannot test this method in isolation.

Why is this a problem?

Suppose the method from above looked like this:

public void evenMoreInteresting() {
    InterestingThingsDoer doer = InterestingThingsDoer.getInstance();
    ResultType result = doer.doSomethingInteresting();
    ResultTypeDao dao = ResultTypeDao.getInstance();
    dao.save(result);
}

Now you need a database to test "evenMoreInteresting()". And if "evenMoreInteresting()" is again defined in a singleton (e.g. because it's part of a stateless service, and everyone knows that you only need one instance of a stateless service), you'll need a database to test every method that calls "evenMoreInteresting()". And so on. A large percentage of your tests will be integrated tests, and those are evil.

Inversion of Control Violation

When you use a singleton in one of your classes, you violate "Inversion of Control": Your class does not get the collaborator (the singleton object) injected, it usually asks for the singleton object.

Why is this a problem?

In the code above, evenMoreInteresting() has complete control over the control flow, because it gets a concrete implementation of all required collaborators and decides what to do with them.

To achieve inversion of control, you have to make sure that classes are not responsible for finding / creating their collaborators (among other things). You do this with a technique called "dependency injection" - Preferably "constructor injection".

But my constructor signatures are getting too big!

If you change some existing code to dependency injection, especially constructor injection, you will notice that some of your constructors have lots and lots of parameters. Take that a chance for refactoring: This class is clearly doing too much!

Open / Closed Principle Violation

Singletons themselves violate the "Open / Closed Principle": If you want to extend or change the behavior of the singleton, you have to change the class. In other words, you cannot change the behavior of "InterestingThingsDoer" from above without opening the file and editing the code.

Why is this a problem?

Changing code is much riskier than adding new code. When you change existing code, there is always the possibility that you'll introduce undesired side effects (a.k.a "defects" or "bugs") in totally different areas of the code that depend on the changed code.

When you can extend the functionality of existing code by just adding new code, the probability that you'll introduce side effects in "unrelated" areas of the code goes way down (but might still be greater than zero, depending on your architecture and design).

So, classes / modules / functions that violate the open / closed principle increase the probability that you'll introduce defects later, when you need to change them.

Single Responsibility Principle Violation

Singletons themselves violate the "Single Responsibility Principle": In addition to their main responsibility, they are also responsible for implementing their own lifecycle.

Classes that use a singleton also violate the "Single Responsibility Principle": In addition to their main responsibility, they are also responsible for deciding the concrete class of (at least one of) their collaborators.

Why is this a problem?

Every responsibility of a class is also a reason to change. You'll have to change "InterestingThingsDoer" whenever you need to change what it does and whenever it's lifecycle changes. And you have to change all callers of "InterestingThingsDoer" when its lifecycle changes, since they have multiple responsibilities too.

And, as already stated above, changing code is inherently risky: If you change code because some responsibility of a class has changed, there is some risk that you'll also break code that deals with other responsibilities of the same class.

Also, if your class has multiple responsibilities, you have to test all of them. And you probably cannot test them in isolation. This means you'll have to write more complicated / hard to understand tests.

Dependency Inversion Principle Violation

The "Dependency Inversion Principle states that the high-level policy of your system should not depend on low-level details. Also, abstractions should never depend on details.

Singletons often implement some low-level detail. When you use them from your business logic (the high-level policy of your system), you violate the "Dependency Inversion Principle".

Why is this a problem?

The dependency inversion principle ensures that you can change the low-level details of a system without having to change the high-level "business logic".

Imagine a vending machine: You select a product, pay the price, get the product. When the implementation of this high-level workflow has any dependencies to low-level details, like how the payment works, you might have to change code dealing with this high-level workflow when you add some new payment method (like NFC payment). You don't want this, because changing code is dangerous.

Increased Coupling / Decreased Cohesion

Often, multiple classes depend on the concrete implementation of a singleton. This increases coupling in your system: When you want to change the behavior of the singleton, you probably have to check and change all the callers. You always have common coupling between all classes that use the singleton: They share a global variable - the singleton!

Sometimes, moving code to singletons (to minimize code duplication, for example) can also decrease cohesion: You move stuff to different classes / packages that conceptually should be a part of the original class / package.

Why is this a problem?

In a tightly coupled system, changes ripple through the system: You want to change one tiny bit of functionality, but to do that, you'll have to modify 20 classes and 50 tests.

In a system with low cohesion, it is hard to even find out where to make a change: It can be any one of 10 different modules. Or it could be all of them. Sometimes it's even hard to know if you have found all the places you have to change to fix one tiny defect.

One and Only One Object

If you really want only one instance of a certain class, implement inversion of control for your dependencies. If you are already using a dependency injection container (like Guice or Spring), just make sure all your singleton objects are managed by that container. All those containers have a way to declare objects as singleton.

If you don't want to use one of those containers, just create all instances of objects you'll need to be singleton in one place, and inject them to other objects via their constructor. You may only need one instance throughout the lifetime of your application, but you don't need the Singleton pattern for that. Just construct one, and inject it into your classes as desired.

And if you don't have inversion of control for your dependencies right now, start using it. It will pay off.

Stateful vs. Stateless Singletons

Do you remember the "//possible some instance state" in "InterestingThingsDoer" from above? There are basically two types of singletons:

  • Stateless singletons: You don't need more than one instance of this class, because it has no state. But you could have many of them: It just does not matter. Because they have no state :)
  • Stateful singletons: You must have exactly one instance of this class, because it represents some globally shared state.

The first category is not a problem. Just use one of the "sane" approaches for creating singletons from above, don't use the "Singleton Pattern". And even if you construct more than one, it's probably not a problem: The class is stateless anyway, you'll just end up consuming more resources. This overhead is probably negligible for most applications (but not all!).

The second category is probably even a problem when you use one of the "sane" approaches to make sure there is only one object: Shared, mutable state makes it easy to introduce defects when changing stuff and makes it hard to scale applications.

Thanks to Samir Talwar who convinced me to write this blog post. He also helped me review the very first draft of this post.
Want to read more like this? Never miss one of my articles: Readers of my newsletter get my articles before anyone else. Subscribe here!

Posting Type: 

Agile Software Development Workshop

Last week, I hosted a training/workshop about "Agile Software Development" for a customer. They had already started introducing Scrum in their teams. And actually they had already gotten quite far: They had all of the basic things in place (the meetings, task board, user stories, ...).

I did agile training in the past, but this time I did some things differently: I basically had next to no slides, and I let the audience do most of the work. We tried to learn everything together, discussing and drawing on flip charts. Also, this was the first agile training I did where all the participants were from the same company.

Well Prepared...
Well Prepared...
Live Drawing
Live Drawing

Break almost over...
Break almost over...
Classroom
Classroom

Here's what went well, and things that positively surprised me:

  • I thought we would do the training in a meeting room at the customer's office. But no: They rented a really nice villa for two days!
  • They brought in almost everyone from three different teams, plus managers, project managers, ... Basically everybody who has to do with software development.
  • They already tried to implement Scrum on their own (quite successfully). So everyone had at least a basic understanding of "Agile" and we were able to spend a lot of time discussing (and trying to solve) their concrete problems/challenges. Because of that, the workshop was very hands-on.
  • Everybody participated in all the exercises.
  • In some of the exercises, I was really just a facilitator. The participants researched, discussed, drew the flipchart pages, ...
  • The weather was really nice (especially for February), and we were allowed to also use the garden of the villa, so we did some of the sessions outdoor.
  • I had to shorten some topics on my agenda, but I actually expected that. And I did that after a discussion with the participants, so they got to decide what they wanted to do in-depth and what we could shorten.

I took pictures of all the flip chart pages and sent them everything I drew on the whiteboard. I also sent them lots of links and books for further reading, grouped by topic. So, even though I didn't really have any "course material", I hope the participants have enough information to remember what we discussed/learned anyway.

Outdoor Sessions
Outdoor Sessions
Group Discussion
Group Discussion

Preparing to discuss
Preparing to discuss
Writing good user stories
Writing good user stories

Again, the best thing about this particular workshop was, that they had already tried some things, and had a lot of concrete questions that we could answer together. We also tried to solve some of their problems together, and worked out a list of things for them to try next.

There were also some things that didn't go so well, and things I need to consider for future workshops/trainings:

  • The time was almost too short - For that group size and what they wanted to learn, three days would probably have been better than too.
  • The days were almost too long - But we took a lot of breaks, so I guess it was OK. At least, nobody fell asleep.
  • Some people told me afterwards that they really would have wanted more slides and a hand-out. I guess I will prepare some for future workshops, but also inform the participants in advance that this is mostly a workshop, not a talk or training with ex-cathedra teaching.
  • The group size was rather large, and during my planning, I didn't really consider that some activities are quite slow with larger groups. Had the group been even bigger, we probably would have needed a third workshop day or cut even more topics from the agenda. I have to consider this when planning future trainings / workshops.

For me, it was a great experience. And the first results from the anonymous survey I sent to the participants are also very positive. In future trainings or workshops, I will definitely use a similar teaching style, but change a thing or two to address participant concerns from this workshop and earlier trainings I gave.

Facilitated discourse
Facilitated discourse
Concentrated
Concentrated

Preparing for a retrospective
Preparing for a retrospective:
"What did we learn?"
Results Gallery
Results Gallery

And I will have another chance to teach soon: Next month, I'll co-host a workshop about "Test Driven Development for iOS Apps" together with Rene Pirringer. Interested? You can find out more Information here (German): Mathema Workshops, and you can also register at that page. I heard that there are still some places left...

Never miss one of my articles: Readers of my newsletter get my articles before anyone else. Subscribe here!

Posting Type: 

jObjectFormatter - A toString Generator for Java

Over Christmas, I realeased a new open source project: jObjectFormatter, a simple toString() generator for java. Using it is really easy: Just override your toString methods with:

@Override
public void toString() {
    return ObjectFormatter.format(this);
}

Ok, there is a little bit more to it: jObjectFormatter is fully configurable. You can define how your objects should be formatted and which properties should be part of the output. You can find more information in the official documentation on GitHub:

I hope you have fun with it, and I would really appreciate your feedback.

Posting Type: 

Well Crafted Code Will Ship Faster

well-crafted code is expensive. good developers spending hours on fixing bad code is very, very, very, very expensive.

Christoph Neuroth

Christoph wrote this some days ago on Twitter. And it sparked quite some discussion. So, a few days later, Chris tweeted:

Sigh so many reactions to that tweet that read "but we need to ship". People still don't get it.

Well crafted code *will* ship faster. Today, tomorrow and in five years. Crap you ship today will kill you in the future.

Christoph Neuroth

Now, you know, the thing is:

Well Crafted Code Will Ship Faster

Actually, this has been demonstrated a couple of times in the past. As a starting point, read the chapters about quality in Code Complete:

The general principle of software quality is: Improving quality reduces development cost.
You don’t have to choose between quality, cost and time-they all go hand in hand.

Steve McConnell, Code Complete 2

Yes, writing code well takes time. But fixing defects takes a lot of time too. Defects are rediculously expensive! And most of the customers I worked with did not even think about the true cost of their defects (in terms of lost developer productivity, lost user productivity, lost credability, ops team cost, lost business, lost market opportunities by schedule slips, budget uncertainty because of bad predictability, ...). Mose companies I worked with so far simply didn't know how much money each defect cost them!

Techniques to improve quality are not always cheap. But, overall, they are free, because:

Projects with low defect potentials and high defect removal efficiency also have the shortest schedules, lowest costs and best customer satisfaction levels.

Steve McConnell, Code Complete 2

So, in software development, you cannot trade quality for speed or cost. Teams that produce higher quality also work faster and cheaper. A study about test driven development by Microsoft research also agrees: Here the teams using TDD took a little longer than teams not using TDD (estimated by Management), but:

From an efficacy perspective this increase in development time is offset by the by the reduced maintenance costs due to the improvement in quality (Erdogmus and Williams 2003), an observation that was backed up the product teams at Microsoft and IBM.

Again, Steve McConnell agrees too:

Writing test cases before the code takes the same amount of time as writing test cases after the code, but it shortens defect-detection-debug-correction cycles.

Steve McConnell, Code Complete 2

What To No Next?

So, you need to improve quality to go faster. The "obvious" idea for most would then be: "Let's invest in quality, then we will become faster over time". But I think this is an extremely difficult route to go. Where do you start? Where do you stop? I think, if you start with "let's improve quality", there is a real danger that this effort will lead you to gold plating and no real improvements.

I think the better way to achieve this is: Just try to move faster, and fix all the problems you face. If you ship your code to customers once a year now, try to ship every three months. When this works, ship every month. And so on. Then you know what "good enough" is at every step of improvement - You know when to stop. And this is extremely valuable knowledge.

I have seen this approach working, but I cannot fully explain why (yet). I think it has some similar reasons like First do things right, then do the right things.

Get Help

Your company and your teams can probably fix most of their problems by themselves. But sometimes it's just cheaper and more efficient to get an external expert. And sometimes you cannot solve your problems all by yourself, because of company politics. Or because you don't even see some of the problems or solutions - you developed blind spots over the years.

Maybe, right now, you think: "Yeah, he only wants to sell his services. Why should I believe him?". But so many teams would benefit from coaching by someone external to the team, especially when it comes to shipping faster. Just consider it, please.

Still not sure? Start with a question: Go to davidtanzer.net/contact and ask me anything - I'll do my best to answer it, and it's free!

Update: After a very interesting discussion on Twitter, I wrote a follow-up where I explain all concepts and terms I used in this article and provide more reasoning why I think "better is faster": Well Crafted Code, Quality, Speed and Budget.

Never miss one of my articles: Readers of my newsletter get my articles before anyone else. Subscribe here!

You might be also interested in:

Posting Type: 

Test-driven development in Ruby

Last week I created a new contact form for this page where you can ask me anything, and I'll do my best to answer your question. From now on, I will post the most interesting questions and my answers here on my blog (and, of course, on my newsletter).

So, here is the very first question somebody asked me, and my answer. After reading it, try it yourself: Just press the big blue button at the top of this page, and ask a question...

I'd like to know more about TDD in Ruby, but most of the tutorials that I have seen have been focused on Java. Where do I start learning TDD in Ruby?

LJ Nissen

Dear LJ,

thank you for your question. It was actually the first question that was submitted through my new contact form ;) And it's already a tough one... At least for me. But I like that.

Alright. Before we start, let me say that I am by no means a Ruby expert. So take everything I say about Ruby with a grain of salt. But I don't think the choice of Language is really that important here. Let me explain...

I know that quite a lot of TDD literature is written for Java. But there are people who do TDD in Ruby - after all, the whole "Is TDD Dead?" [1] discussion got started after David Heinemeier Hansson wrote an angry blog post [2]. So, can you use Java tutorials or a book like "Growing Object-Oriented Software, Guided by Tests" [3] even though you are using Ruby? I think so. But more on that later.

Before you start with those tutorials, you need to learn your test framework reasonably well, so you're able to translate the examples from Java to your test framework. It probably also helps when you can read at least *some* Java code, but many tutorials describe the reasoning behind the code well enough so you should be able to implement it in Ruby.

There seem to be *many* different testing frameworks for Ruby [4], and I can't really help you with choosing one. But the testing frameworks seem to have some good documentation (for example, here [5]).

Now you can start to learn the TDD flow. Don't try anything fancy yet. Take a really simple example (like the "Prime Numbers Kata" [6] - The solution has less than 10 lines of code!) and write your first test. Get it to green. Refactor. Write the next test. Get it to green. Refactor.

Then you can try a fancier example. I like "Hangman" as an exercise: Write a hangman game and/or a bot that can play hangman. You can start either with the game or with the bot. The bot can be very simple (just guesses random letters), and you can evolve it to use more elaborate strategies (dictionary based, ...).

Hangman is also great because you can do it "Inside-Out" or "Outside-In" [7], and now it is probably time to learn about the differences between those strategies. Also, try to find out how you can use Mocks [8] in Ruby, because you'll probably need them for "Outside-In".

When you have a good feeling for your testing framework, mocking framework and how you can refactor code in Ruby, you can start to do more tutorials or start reading "Growing Object-Oriented Software, Guided by Tests" [3]. Even though most of the examples you'll find will be in Java or C#, by now you should be able to translate the *learnings* and *reasonging* behind the examples to Ruby.

You should pay special attention to the "refactoring" step in TDD. This is really important - If you don't do it, your software design will suffer. Also make sure that you proceed in small, safe steps. "Taking Baby Steps" [9] and "Brutal Refactoring Game" [10] are two exercises that can help you here. You normally do those exercises in a group, at a conference or during a workshop. But you can practice them alone too.

Also, after the first few exercises and Katas, try to use TDD in a "real" (i.e. longer) project - Either a side project or at work. A Kata is nice to get started, but they are quite short lived. You do them, and when you are finished, you throw away the code. You will learn different things when you have to live with your code and your decisions for a longer time, like in a "real" project.

What questions do you still have? What will you try next?

Kind Regards,
David

[1] http://martinfowler.com/articles/is-tdd-dead/
[2] http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html
[3] http://www.amazon.de/gp/product/0321503627
[4] https://www.ruby-toolbox.com/categories/testing_frameworks
[5] https://en.wikibooks.org/wiki/Ruby_Programming/Unit_testing
[6] http://butunclebob.com/files/downloads/Prime%20Factors%20Kata.ppt
[7] http://programmers.stackexchange.com/questions/166409/tdd-outside-in-vs-inside-out
[8] http://martinfowler.com/articles/mocksArentStubs.html
[9] http://blog.adrianbolboaca.ro/2013/01/the-history-of-taking-baby-steps/
[10] http://blog.adrianbolboaca.ro/2013/07/brutal-refactoring-game/

Posting Type: 

Integrated Tests - The Other Side Of The Scam

At GeeCon Prague 2015, I saw a great talk by J.B. Rainsberger about integrated tests. It was basically a live version of his essay Integrated Tests Are a Scam, that I had read earlier. But It was great to hear his reasoning live, in a narrated way.

I use the term integrated test to mean any test whose result (pass or fail) depends on the correctness of the implementation of more than one piece of non-trivial behavior.

J.B. Rainsberger

The Scam: Original Version

The gist of his talk (and his essay, which you should read), is: If you start to depend on integrated tests, you need to write more and more of them over time. Since they don't put as much positive pressure on your design as unit tests would do, your code quality will suffer, more defects will escape your net of tests, and you'll need more integrated tests to reproduce them.

The driving force here is: Positive design pressure caused by unit tests. We are missing this positive pressure with integrated tests, and this brings us into a tail spin.

The Problem with that Version

Now, some people seem to have a hard time to understand this narrative. After the talk, I have heard from several people things like:

"Integrated tests might not be the best possible solution, but they are not so bad. Better have some tests than none."

"This sounds nice in theory, but I don't think his solution (unit tests with mocks) will work in the real world. It is not any better than having the integrated tests."

"But we have to test if all components are working together, don't we?"

Some Don't Feel the Pressure

I almost dismissed what they said as "some people always complain". But then I started thinking. For me, the reasoning in the talk was absolutely plausible and the conclusion to use unit tests and mocks seemed just right. Why was this not the case for other people?

And I think I found a possible explanation...

Some people don't feel the positive design pressure from their tests. They write tests, but don't take too much care to write good unit tests. Often, they don't refactor enough. Then, after a very small change, 20 tests break, and they complain that testing is waste. I have seen this scenario, and I did those things myself.

In other words: TDD is hard. You have to learn it and train it and take the time to do it right. But when you do it right, you can get great benefits from it.

Alternative Version of the Scam

Even if you do TDD like that, integrated tests are still a scam: They still lead you down this vicious circle where you need more of them the more you have.

  1. We already have some integrated tests
  2. They don't catch many errors (because you never have enough integrated tests)
  3. When an error occurs, we try to write a test
  4. Since we already have some integrated tests, and we do not refactor enough, some parts of our system are really hard to test
  5. So, let's just add some code to an existing test or write another integrated test, and then fix the bug
  6. We have less time to write unit tests or improve our design
  7. Go to 1

I know that one can explain this cycle with "the positive design pressure is missing". But it feels differently for the people in the cycle, who are not "listening to their tests" anyway. Because if they would, they would not be in this cycle.

Second Vicious Circle

There is a second vicious circle that often seems to happen at the same time:

  1. We already have some integrated tests
  2. We don't want to cover a line of code with different tests, because we think this would be waste
  3. So we don't write unit tests, since we already covered the code with integrated tests ("There is already a test for this class, why do you write another one?")
  4. Oh shit, writing those integrated tests is hard
  5. Also, they never catch regressions (see above)
  6. So we write less of them, and make them bigger
  7. Bigger tests cover more lines -> Go to 1

Trust in Automated Testing Suffers

So, writing integrated tests is hard. And those tests seldom catch real regressions. I mean, they do, but they'll also often fail when we make a perfectly legitimate change. So, over time, people will start to consider automated testing a waste.

Also, integrated tests often become flaky. There are a simply too many reasons why they might fail, so they'll fail "for no reason" from time to time. You'll hear your team members say: "Yeah, the nightly build is red, but whatever. This test simply fails once or twice a month."

Over time, the team trusts the test suite less and less. You can easily get into a situation where a large percentage of the builds fail because of flaky tests, and nobody fixes them, because fixing those tests is hard, and they never catch any regressions anyway.

Manual Testing

When trust in automated testing decreases, teams often rely more and more on manual testing. "Red-Green-Refactor" becomes (if we ever had it) "Change-Test-Debug". They'll have testers (on the team or in an external testing department) who will "validate" the results once the programmers are "finished". At best, they will automate some test cases "through the GUI", but often they will just click through the program.

This manual testing and automating through the UI slows down all feedback cycles considerably. Later feedback means that fixing the problems we find becomes more expensive, because someone has to go back and change something that was supposed to be "finished".

Conclusion

You cannot write all the integrated tests you need to verify that your software works correctly under all circumstances. Even covering all the code paths is incredibly hard. So, if you rely too much on them, you will increase the likelihood that some defects will slip all your safety nets and "escape" to production.

Integrated tests are self-replicating: When you have more, you'll need them even more. Then they often become flaky and trust in your test suite starts to suffer. But when you rely too much on manual testing as a result, you slow down your feedback cycles, making your development unresponsive and expensive.

So: Be wary of integrated tests!

Now subscribe to my newsletter so you don't miss Part 2: "The Mock Objects Trap"!

You might be also interested in:

Posting Type: 

Pages

My name is David Tanzer and I have been working as an independent software consultant since 2006. I help my clients to develop software right and to develop the right software by providing training, coaching and consultanting for teams and individuals.

Learn more...

Subscribe to RSS - David's Blog