5 ms·
Static methods should be treated like functions. Same input same output. Keep them small. If you find yourself needing to mock them they are doing too much.
by i386 4y ago
Static methods should be treated like functions. Same input same output. Keep them small. If you find yourself needing to mock them they are doing too much.
- hardware2win 4y ago>like pure functions Small nitpick :p
- bheadmaster 4y agoI think they meant "functions" in the mathematical sense. Although due to the ambiguity of the word "function", your nitpick still has its place.
- mcculley 4y agoYes, I definitely meant in the mathematical sense. I would really like a way to express pure functions in Java. There would need to some way to mark objects as immutable at the language level.
- kaashif 4y agoI switched from being a C++ developer to Java a while back and the lack of const (i.e. immutability) annoys me. It annoys me even more than no-one seems to care about it much, and most think final is good enough - you can still mutate final objects. In C++ all references are final (in a Java sense) since they can't be reseated, but const actually gets you immutability (modulo const_cast). I just want everything to be immutable unless mutability is really truly needed!
- barbarbar 4y agoWhat about Records and immutable Collections, Sets, Maps? Isn't it possible to achieve what you want with that?
- kaashif 4y agoNot really. In Java you can do all kinds of things with immutable wrappers, but the language doesn't help you and it doesn't come for free for your own types. In C++ you can write a class with some methods that mutate, and some const methods that can't mutate anything, and you can pass around const references through which mutation is guaranteed to be impossible. This all comes for free.
- barbarbar 4y agoThis was added a couple of years ago https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Record.html https://docs.oracle.com/en/java/javase/17/docs/api/java.base.... I was thinking that would make it possible to create unmodifiable data objects using that (and not Object as base class).
- kaba0 4y agoClojure may be what you want then, if you can stomach the lisp-y syntax. Otherwise Scala is pretty pragmatic about it (val vs var). In both cases you still get only shallow immutability, but if nigh every object itself is immutable, shallow immutability may not be so shallow.
- cobbzilla 4y ago> I just want everything to be immutable unless mutability is really truly needed Have you tried Rust? It’s nice in this regard; variables are immutable unless explicitly declared mutable.
- kaashif 4y agoYeah, and I really like Rust. Rust has its mistakes but having RAII and immutability by default goes a very long way. But it's not terribly easy or even a good idea to switch from Java to Rust at a real company that has no time to rewrite libraries, has to hire developers, and so on.
- misja111 4y agoThat will only work when your functions don't have side effects. So no database access, no network calls etc. You could work around that by passing in your database client as parameter but when you have a DAO class with lots of functions this quickly becomes tedious.
- patates 4y agoOP said: > I write functions using ‘static’ all the time. I prefer that a function be static. This, however, does not mean that all the functions should be static. IMHO, the more static stuff you can extract from your instance methods while keeping parameters count to max 3 (magic number that works for me), the better.
- foobarian 4y ago> You could work around that by passing in your database client as parameter Yes this is the way. [1] [1] https://en.wikipedia.org/wiki/Hexagonal_architecture_(software) https://en.wikipedia.org/wiki/Hexagonal_architecture_(softwa...
- 0x445442 4y agoBut even here you’re testing the same code twice. One directly with the tests for the class the static methods live in and once accidentally when you test the class that includes the util class as a dependency. This situation can be fixed by replacing the static methods with Functions.
- ahtihn 4y ago> But even here you’re testing the same code twice So what? How is that a problem?
- 0x445442 4y agoBecause you have to address the separate permutations and concerns of multiple stack levels versus just declaring what you want the result to be from those additional stack levels. In essence, your "unit" test is a lie because your testing other units accidentally. I see a similar problems a lot with classes that have a small number of public methods which delegate to a larger stack of internal private calls. Unit tests are about testing the unit explicitly and forcing/contriving results of dependencies which you shouldn't be concerned with because those dependencies have been explicitly tested elsewhere. When these situations arise what you have are in memory integration tests, not unit tests. As an example, suppose I have a static method that takes in an object and returns a result based on the state of that object. Now I have conditional logic in the unit under test that has a dependency on the result of that static method. In my unit test, I don't want to go to the trouble of creating the state of the object to force the delegate call to return a certain result that determines the execution flow, I want to just force that call to return the result I need.
- aszen 4y agoThis is an extremely bad habit, people over use it to make testing easier by mocking all over the place. They end up writing tests that are coupled to the implementation, and any small change breaks them. Please go through the trouble to create the state of your object that you want to test, don't just mock other dependencies, which dependencies your method uses or how it does it's job is no concern of the test at all.