News for hackers. Stuff that matters.
Re:TDD did not live up to expectations by lliamander on Thursday June 29, 2017 @03:06PM (#14666014)
Sounds like you're doing the right thing. Note that not every one would agree that you are doing "true TDD" (due to your lack of "unit" tests) but that doesn't matter. What matters is that:

a) you are disciplined in your commitment to quality

b) you offload as much of the tedious, repetitive work to the computer as possible.

Regarding unit tests and mocking, I have a similar opinion. I tend to test at the larger component/package level rather than the smaller class/module level. Furthermore, I avoid mocking as much as possible. Object-Oriented decoupling through dependency injection makes mocking a lot easier (and removes the need for mocking frameworks) and Functional decoupling[0] makes mocking largely unnecessary.

[0]http://prog21.dadgum.com/131.html

Re:TDD did not live up to expectations by unclebucknasty on Friday June 30, 2017 @09:54AM (#14670699)
Mocking is an aspect of testing that grew out of control and the cost can easily outweigh the benefits.

In addition to mocking frameworks, I've also encountered home-grown solutions that were complete time-sinks to use. At some point, you're investing huge chunks of time, not just testing, but mocking in particular.

It can literally layer an entirely different problem domain onto your dev effort, apart from the actual "business problem" the code is intended to solve.

At a certain point, it's like, "wait, what are we doing here again? There has to be another way." Always wondered how people became so dogmatic and determined that they fail to see that they are veering from their original purpose. There is a balance to everything and something about the dev community causes us to lurch in different directions, well beyond that balance.

BTW, there is a post [0] that reminds me of this on the blog you shared. Good blog, BTW, even if it is no longer active.

[0] http://prog21.dadgum.com/56.html

Re:TDD did not live up to expectations by charlieflowers on Thursday June 29, 2017 @06:45PM (#14667467)
Along the same lines, checkout "Functional Core, Imperative Shell".
Re:TDD did not live up to expectations by BeetleB on Friday June 30, 2017 @10:52AM (#14671094)
>Object-Oriented decoupling through dependency injection makes mocking a lot easier (and removes the need for mocking frameworks)

I'm confused by this. In C++, I found that one of the only ways to effectively use mocking was via dependency injection. For us, dependency injection was introduced to enable TDD. That it had other good qualities was a bonus.

Re:TDD did not live up to expectations by lliamander on Friday June 30, 2017 @01:06PM (#14672071)
A fair question. Let me put it this way: in order to properly do unit tests, you need to decouple business logic from "integration code" (code that manipulates external systems). Dependency injection is one approach. However, with this approach the business logic still depends (now indirectly) on the integration code.

Another approach is to model business logic using pure functions. Instead of business logic calling the integration logic (directly or indirectly) you have the integration logic calling the business logic.

The consequence of this is that when you are unit testing your business logic you do not need to mock anything. It's simply a matter of checking input/output mappings.

See this series of articles for a deeper explanation: http://blog.ploeh.dk/2017/01/27/from-dependency-injection-to...

Re:TDD did not live up to expectations by BeetleB on Friday June 30, 2017 @03:02PM (#14672965)
>Another approach is to model business logic using pure functions. Instead of business logic calling the integration logic (directly or indirectly) you have the integration logic calling the business logic.

Yes, this is similar to what I did. I ensured business logic dealt only with data structures and algorithms, and knew nothing about the rest of the world. If it needed to report an error, it would call an interface class's "ReportError" function, and pass a string. It did not need to know if the error went to the console, a file, an email, text message, etc.

However, in our case, the communication is still two way - just separated via interfaces. The integration logic does call the business logic, but the business logic may need to do things like report the results, log interesting information, etc. So we still had to mock the interface class (i.e. mock the ReportError function).

But in the bigger picture - yes. Not allowing your business logic to know anything about the details of the integration was really helpful. In principle, our customers could have written the business logic for us.

Sadly, my team did not accept it so we never adopted it.

Re:TDD did not live up to expectations by crdoconnor on Friday June 30, 2017 @06:08AM (#14669667)
>Note that not every one would agree that you are doing "true TDD" (due to your lack of "unit" tests)

I think he's doing it right in spite of what other religious zealots may say. In my experience, unit test driven development causes three massive problems:

* Unit tests are intrinsically tight coupling.

* Unit tests require you to build a model for most things that you are testing against (e.g. your database). Building these elaborate models (i.e. using mocks) is prohibitively expensive when you have tightly coupled code but they're often still expensive to build (in terms of developer time) even when you have loosely coupled code.

* Unit tests are intrinsically unrealistic because they are built against models rather than the real thing.

In my experience unit tests work adequately for domains that are heavy on complex logic and light on integration (e.g. writing a parser). In domains which are light on complex logic and heavy on integration they fail badly (e.g. most business apps).

Optimizing for the overall speed of your test suite by using a more unrealistic test that catches fewer bugs is a massive false economy. CPU time is dirt cheap. QA and dev time is very expensive.

Re:TDD did not live up to expectations by lliamander on Friday June 30, 2017 @01:31PM (#14672267)
> In my experience unit tests work adequately for domains that are heavy on complex logic and light on integration (e.g. writing a parser). In domains which are light on complex logic and heavy on integration they fail badly (e.g. most business apps).

There's a testing methodology we used at my last company called "Change Risk Analysis" or something. Essentially, the point was that you separate business logic and integration code, and you write unit tests for the business logic. There was a metric that combined the the cyclomatic complexity with the test coverage to produce a "risk" score for methods and classes, and all code (or at least all new code) had to be under a certain risk threshold.

I would also add that domains that are heavy on complex logic and light on integration are also highly amenable to more sophisticated verification methods, such as generative testing and model checking.