4 ms·
Interestingly, enough, my OO code, when I refactor it well, mostly consists of tiny little (one-public-methods) classes, 99% of them are stateless, and, usually
by waterlink 10y ago
Interestingly, enough, my OO code, when I refactor it well, mostly consists of tiny little (one-public-methods) classes, 99% of them are stateless, and, usually, 3-5 are composed to accomplish any sort of task at any level of the detail. I started writing OO code this way only after learning Haskell and having production experience with Clojure. Basically, immutable objects are very similar to pure functions and easier to reason about.
Even in pure functional environments I do use TDD, because it gives me enough confidence to know, that I know what I am doing. Maybe it is just a mindset, or my brain is wired this way. For any change to the production code I require a proof, that system needs to be changed in a form of failing test.
- keithnz 10y agoI think this is an important point, your design literacy is key in creating good software. To me software design hinges a lot on finding good ways of composing things together simply. Functional programming is really good at encouraging this by its very nature. TDD I think works best when, mentally, it is design centric rather than test centric. The tests are used to prod a design around till you are happy with the design and act as validation of the intent of the design. The goal is to keep the tests at the minimal level to test that intent. If, testing sum of two numbers, from the article def sum(a, b) if b == 2 4 else 5 end end If this is what you do,I think you've gone wrong. The name of your function is either wrong and should be renamed, or your design of sum is wrong. Attempting to test that functionality into place is the wrong approach. I know its tricky with examples, but every extra sum(2,3) sum(4,5) sum(9,1) etc that doesn't reveal more design intent from the implementation of returning a+b is a wasted test that must be maintained. You don't want your test to try and prove every possible implementation of sum. It really doesn't help in practical terms. I know when I used to use the Bowling game as an interview coding question, I was amazed how many tests I needed to try and test every possible implementation. People would do crazy things with their design, such as the equivalent implementation for sum... return a == 392984589? 0 : a+b it was a conditional to handle an edge case that introduced a bizarre bug for 392984589. It would mean, to test any possible implementation of bowling ( or sum) you need to test every combo. But that's not really the purpose of TDD. TDD is about design and incrementally putting a design in place.
- waterlink 10y agoI would never write such an if statement. In the article it was an example of the Specific/Generic Rule violation. Implementation evolution is as following (backed up by respective test): Sum(a,b): 4 Sum(a,b): a+2 Sum(a,b): a+b 1 example test for the requirement and 2 iteration of triangulation with transformation priority premise. I hope that makes sense. Sorry for not being clear enough in the article about the example being a violation of the rule, that you shouldn't do.
- mdpopescu 10y agoSame thing here: small classes, a lot of them with a single method. Some state but usually immutable (besides other services, stuff like "password" and "base path"). A huge amount of composition. I've had people object to this design: I simplify the classes too much so as a result, I have too many of them. I disagree with that idea - I don't find English too complicated because "there are too many words". (Or the .NET framework because there are too many classes, to keep it in scope.) As long as abstractions are built correctly, with good names (a hard problem :D), I can handle the result much better than if I have only a few "God classes".