Hacker News new | past | comments | ask | show | jobs | submit login




That was a nod to that article actually.

No one does that now. Someone does some thinking, writes a strong interface, then builds the code behind it. There's usually only one implementation. The advantage comes at the testing phase when you have strong interfaces to mock.

I can count on one hand the amount of things we do with multiple inplementations and that's mainly switching cache and file store implementations out depending on who paid for what.


Testing using mocks usually (a) over-specifies the code under test (e.g. mandating method call order and call count), and (b) under-tests the integration across the boundary - i.e. there's no guarantee that the mock acts the same way as the concrete implementation.

I prefer composition through more general abstractions like iterators, consumers, functors etc. where possible. With more general abstractions, there's both less need to mock (there are concrete implementations that are simple enough to use in tests) and the contract is trivial enough to be implemented consistently.

Converting control flow (where modules interact through a rich protocol of method calls) into data flow (where modules interact by consuming data and producing data) promotes both a more functional style, and naturally leads to more testable code with fewer of the downsides of mocks. It also reduces the number of interface-implementation redundantly paired types throughout the system.


Call order and count assertions are important in non-idempotent calls (message delivery for example) and complex integration tests.

While I respect your opinion, it misses three realities. Firstly you can't generalise most complex systems enough for this to be a viable solution universally. Secondly, skill level just isn't on the market to implement this for every case even if you could specify it. Thirdly, to solve the first two problems it costs more.

Data flow moves all the test responsibilities into integration testing, which is much harder!

It's a careful thing to balance but I'm currently on the side of mocks and control flow based systems. They are cost effective and scale well in practice (I think we're on about 4 million or so lines of code and tens of thousands of class levels now)


I think "realities" are subjective here :)

Complex systems only become tractable when modularized, and simple module boundaries are preferable to chatty APIs; the nature of the system may make it more or less worthwhile, I'll agree.

Building crappier software because that's all you can build with the people you can find seems to me to be putting the cart before the horse. And I think you easily end up with crappier, less flexible software if you blindly follow Java norms. The tendency to over-specified tests both increases the cost of writing test code, increases the cost of refactoring (the tests usually need to change in some proportion to the implementation, even if the behaviour is no different), but even worse: your modules are, by default, not recomposable. When things are built out of data flow instead of control flow, you get a bunch of power almost for free.

Parallel and distributed processing, logging and system introspection, up to and including new product development using known good components. The business agility is especially important.

I've seen codebases calcified by "long land borders" between modules, with value locked in by the architecture, requiring risky and costly refactoring, rewrites or monotonically increasing complexity to try and repurpose that value. A system that looks more like Lego than a series of custom crafted blocks is more valuable, even if it's harder to build.

The opportunity cost obviously depends heavily on the domain. For an internal corporate IT project, I can certainly see that the upside isn't as clear.


"mandating method call order and call count)" - Very few people use mocks like that.

Most people use them glorified stubs for returning data. Personally these days I just in memory datastores.


We do use mocks like that. How else do you test that a complex piece of logic doesn't try and perform the same operation twice, such as a trivial case of sending only one message to a queue?

Without the assertion, you are left with an assumption, which from experience isn't reliable and keeps you up at night.


Some alternatives:

- Make it possible to introspect the state and effects of the code on your dependency in the real implementation, and use that instead of a mock. Can then put the assertion into the code (a post-condition, design-by-contracts style) so it always runs, not just for the few explicitly written unit-tests. Those unit tests can be deleted in favor of something that tests something useful, like running the logic on

- Return the effect (messages to be sent) instead of doing it internally as a side-effect. Then introspect and verify this data in the test. The dependency on the message queue can now be elimitated, both in test and by the complex piece of logic


Because it makes refactoring very difficult. One of the original intentions of TDD and Unit testing was to make refactoring much easier.

If you start testing the internals of function, it makes it very difficult to refactor without breaking tons and tons tests.

We only test on publicly exposed functions, and check the changes on the data or external services.

It means we can do major refactoring's of internals, keep public functions the same but tests will still pass.

One of the biggest mistakes that happened was that kent beck was misinterpreted and Unit was considered a code unit, when really it means a unit of behaviour.


I don't disagree with your explanation. But the core point of objects is to bind a state and some method implementations.

Mocking the state sounds mandatory to test the method implementations in such a paradigm.

What you propose seems more like functional programming oriented testing.


I have seldom seen a jMock Expectations clause without oneOf etc.


Bet on a software engineering blog to try to make a point using bad paralels with, uh, murdering women.


I do believe that's actually a personality cult disguised as a software engineering blog




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: