5 ms·
I'd say that it's true that the closer you get to pure functional programming (no state or side effects), the more unit testable your code becomes. I'd have to
by akeefer 18y ago
I'd say that it's true that the closer you get to pure functional programming (no state or side effects), the more unit testable your code becomes.
I'd have to take issue, however, with the author's implication that Java programmers who unit tests are idiots who don't realize they're reinventing the wheel. Good developers in any language recognize the importance of avoiding side effects, isolating parts of the system from each other (including minimizing state), etc. It shouldn't come as a surprise to anyone that testable code has some common characteristics across all programming languages. There are differences unique to the language as well, though, and unit testing in Java also tends to involve use of things like interfaces and polymorphism that are distinctly OO concepts as well.
And of course, unit testing isn't just for those "overly complicated" Java applications; it's for any type of system in any language. The author seems to me to imply that somehow unit testing is uniquely a requirement of Java systems that Erlang systems somehow don't need.
- sayrer 18y agoThe main point the guy makes is that "testable code" resembles functional programming. And testable code is code that doesn't suck. Maybe code that doesn't suck is code that resembles functional programming. I guess you could argue that all the moronic OO voodoo theory books are trying to say this. I don't think so. I think he's a got a point.
- akeefer 18y agoI agree that he's got a point, I just get annoyed when people feel the need to make their point in a way that questions the intelligence of other people. It's unnecessary and counter-productive. There are ways to say "one big advantage of functional programming is that it leads to more testable code" without also saying "and anyone that programs in any other sort of language is clearly an idiot."
- jim-greer 18y agoI also agree that he's got a point. I'd encourage him to build something so awesome with a functional language that the rest of us can't help but be blown away. Ejabberd is a good start, how about some more? It's not easy to develop things so useful & elegant that you win people over... but it's easier than arguing the Internet into submission from a mailing list.
- vlisivka 18y ago> I'd encourage him to build something so awesome with a functional language that the rest of us can't help but be blown away. Functional language helps a lot in building of side effect free code. But such code can be written even in pure assembler. I writing in such style in any language, including Bash. Sometimes I need to refactor somebody else code. Code functionality remains exact same after refactoring. Things that changed are: better code clarity, better reusability, and better testability as part of reusability. Unit tests creates additional contexts, in which main code can be used, thus they force to improve reusability of the code, thus code forced to make less or none side effects, thus programmer forced to rewrite code in functional style.
- kragen 18y agoHow do you write such code in x86 assembler? All the instructions I'm familiar with have side effects except for nop, hlt, and, arguably, push and call.
- vlisivka 18y agoIt is not a problem. Execution of any code in any language can have side effects, like garbage in memory or stack overflow or OutOfMemoryException. Usually, you just ignore these side effects. Use code convention to define which flags, registers, and memory areas, IO registers, etc. must be preserved by the called function. Just ignore any other changes.
- jlouis 18y agoActually, there are two views of functional programming: 1) Default to functional ideas: Variables are immutable, recursion is encouraged, etc; but you can get access to imperative code when needed (Call this the Algoritmically functional languages) 2) Functional is the norm: You can't write non-pure functions with side-effects at all. These are the Pure Functional languages. I am leaning towards 1 more than 2 personally, but many people would disagree with me on that one. The question is: Do you want a usable program written in class 1 or 2? Because there is a hell of a difference between them and how you build software for the two classes. Interesting class 1 projects, where you can get the source code, are: ejabberd, mldonkey, unison, harmony/boomerang, coq, twelf, isabelle, coccinelle, and mlton. Interesting class 2 projects could be xmonad, darcs, and GHC. Of these projects, some would be easily implementible in imperative languages, some would be hard but doable and some would be insanely impossible to do. Please note that all things on the list are useful and elegant. But they might not have a user-base as big as other projects.
- jlouis 18y agoIt does not question other peoples intelligence, but rather their knowledge of programming language paradigms. You can program functionally in any language by eschewing side-effects whenever you can. Only that in some languages it is way easier to program functionally than others (ML, Scheme, Common Lisp, Erlang) and in some it is even forced (Haskell). The "idiot" here is the one that can't see or understand that it is easier to program functionally in functional languages and that it leads to better programs by doing so. To see this, you need knowledge of functional programming. And sadly, many people do not understand its finer points because they have not spent time writing non-trivial programs in functional languages. If you know nothing about FP on the other hand, you could be lead into the concept of Dependency Injection, Design Patterns and whatnot, because your world is shaped around a statical subtyping system (In the case of Java). These concepts are not bad at all: they help Java programmers write better code (for most part) with fewer errors.
- 10ren 18y agoI agree that avoiding side effects and global state is a well-known practice (and OO languages have access modifiers, like private, to support it). It's not unique to functional programming. Interesting to me was that the reasoning of the article was strikingly close to Dijkstra's "Goto considered harmful", and it makes me wonder if there is some small step that OO languages could take to automatically enforce testable code, in the way that structured programming made gotos safer. The problem is that side-effects and global state are very useful for making some problems simpler - which is why Erlang has its transactional database mnesia, and Lisp is not purely functional. Is there a way to structure side-effect/global state to make it entirely testable, without destroying the benefits?
- eru 18y agoMonads are one attempt at solving this problem.
- joe_the_user 18y agoI can't see an argument that Erlang is automatically tested in the body of the link. Perhaps I missed something. All I read was the usual arguments for functional programming - which has some merits but ... whatever. Where is the unit testing connection?
- 10ren 18y agoStarting from the 5th last paragraph: The funny thing is that the OOP world have found one way to manage the complexity and the code-bases that grow ugly: They are using unit tests, and practice the art of writing testable code. ("Testable code" is something that is simple to write unit tests for. )
- akeefer 18y agoThat's also generally the reasoning behind mocks, dependency injection, etc. used by OO unit testing. If something is supposed to, say, update something in the database, you abstract out an interface to the database and mock it out in your tests, and then use interaction tests to verify that your code is calling the right methods on your database abstraction. Of course, it's kind of turtles all the way down, and you then have to test that your production implementation of that database abstraction does, in fact, call through to the database. And of course, there are the ever-raging holy wars in the tdd community around interaction testing versus state testing, and that level of abstraction and mockage can sometimes (in my opinion) make the code harder to follow, so it's always about tradeoffs. But whatever the language you're in, encapsulating side effects and state as much as possible is going to be the way forward, using whatever tools are at your disposal. Some languages tend to make it easier to do that (or harder to avoid doing that) than others.