6 ms·
I am amused by this: > Worse, the early exposure to static methods will turn out to be a bad habit that must be later unlearned. I have been using Java since
by mcculley 4y ago
I am amused by this:
> Worse, the early exposure to static methods will turn out to be a bad habit that must be later unlearned.
I have been using Java since 1.0 and it is my default language. I am writing Java code today.
I write functions using ‘static’ all the time. I prefer that a function be static. It shows that it does not depend on state of the enclosing object. Using ‘static’ on methods is not a bad habit. Having static fields and state is to be avoided.
- sz4kerto 4y agoYou can't really mock static methods though, so it makes testing harder.
- i386 4y agoStatic 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.
- 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.
- deleted 4y ago[deleted]
- Noe2097 4y agoCouldn't agree more. Recently I tried another take on the same idea: using default methods in Interfaces. It has nice properties, as it enables ~mixins in a way not dissimilar to what Scala provides, and enables overriding (e.g. for tests). Give it a try, it's ... refreshing :)
- mcculley 4y agoI am also getting a lot of value from default methods in interfaces. Java really could benefit from a new syntax on top of the modern VM that favors immutability.
- grodriguez100 4y agoLike… kotlin?
- mcculley 4y agoLike Kotlin, but Kotlin also makes a lot of compromises to accommodate Java’s warts.
- StevePerkins 4y agoMost IDE's and static analysis tools will actually provide a warning when an instance method could have been declared static.
- okennedy 4y agoIt's worth keeping in mind that the primary audience that the article discusses is not folks at your skill level. By far one of the most common errors I see as a CS instructor is aggressive over-reliance on global state. Not global methods, but state. However, usually what causes the student to reach for global state is the fact that it can be accessed from a static method like main; In lieu of figuring out how to structure a class, they reach for the easier "just make the variable static" approach. Allowing the initialization sequence to call main on an instance via the class's zero-arg constructor seems like it would address the point.
- mcculley 4y agoI agree that this is a good way to simplify Java. I just don’t want newbie Java programmers told that static methods are bad because that is our only way to express pure functions and we need them to learn to default to immutable data and minimizing stateful objects.
- okennedy 4y agoThat's a fair long term view, and a sense for this type of nuanced choice is one of the marks of a good programmer. Not all students have the experience to judge the tradeoff, and so my goal as an educator is to default them to the safer of the two options. In this example, it's usually trivial to just add the static keyword to an already pure method. In my experience it's considerably harder to refactor a series of stateful methods that were incorrectly declared static, since you usually also have to plumb the state object through all of the callers, and their callers, and their callers, etc...
- monster_group 4y agoStatic methods are a pain for unit testing though. I have started avoiding them for that reason alone. For stateless objects, you can always have a singleton and invoke all the methods on that object giving effectively static behavior without the baggage.
- Sankozi 4y agoThey are hard to test only if they are not functions and access some global mutable state. In vast majority of cases static methods are functions and are easier to test than normal methods, because you do not need to initialize object.
- hibikir 4y agoI suspect that the issue that the GP is discussing is not that they are hard to unit test, but that they are hard to mock: If you don't want to call the static method, either some relatively unfortunate thing has to be done to your mocking classes, or you have to inject it, which is uncommon in this kind of situation in your typical Spring application. Now, what I'd say to that kind of argument is that a good static method, which could really live on its own as a function out there in the world, is something simple enough you'd never want to mock, or is something that is so specific that you'd always want to inject. This is easier to understand if you are used to functional programming styles, and therefore also realize that automated dependency injection was a misstep. It's also easier to get if, like in Scala, there is no such thing as a static method, just classes that have only static methods, and classes that have none. But until one has 'seen the light' of FP, static methods that are complicated and are not injected will be annoying when someone is trying to not call them in a unit test. Therefore, in some places, static methods are always avoided.
- shagie 4y agoIf they're not modifying or accessing some state, then the occasions that one would need to mock them is drastically cut down.
- patrickthebold 4y ago
- pron 4y ago> It shows that it does not depend on state of the enclosing object. Fine, but that's not relevant to the subject of this document, the "first program", as it would make all fields static, too, and so methods would still be dependent on state. It will just make moving to the next step harder; as the article says: this is probably not the direction we want to go when we scale up from a handful of statements and declarations to a simple class — we probably want to start using classes as classes, not just as containers for static members.
- salil999 4y ago> Having static fields and state is to be avoided. This is totally false. It will always depend on the use case.
- mcculley 4y agoState, while necessary, is the enemy of sanity. It should be kept to a minimum and be well marked as dangerous. The change I would most like to see in a new Java syntax would be to make final and immutable the default. Force the programmer to make clear where state lives.
- exabrial 4y agoThey’re fine if they are self contained, which is your point, and which is the author’s point (and generally everyone else). He didn’t go into detail of the why, but that is east is usually meant. A good clean programming have it is to wrap all of your stream()/lambdas chains in a static method that describes what they do. This make sure they don’t have access to the local scope and can mutate data.
- RockingGoodNite 4y agostatic should be removed from Java. static is bad, not always but because it can be misused and because it makes debugging more difficult and most important of all, it makes testing impossible and PowerMock is to be avoided at all costs.
- ahtihn 4y agoRight, methods that call Math.min() are literally untestable without PowerMock.
- thedracle 4y agoSo many creational design patterns rely on static factory methods too. I'm not really sure what they're on about.