5 ms·
Some like to say that you should never write clever code. But clever to who? Some people lambdas, map, reduce, and even polymorphism are clever. So in a vacu
by sbov 10y ago
Some like to say that you should never write clever code. But clever to who? Some people lambdas, map, reduce, and even polymorphism are clever. So in a vacuum the statement is meaningless.
Whenever you're writing code you need to know your audience. Is the Haskell solution really that clever to someone who uses Haskell on a daily basis?
That said, I always liked the saying: it's easier to write code than read it. Which means, that if you're writing code at "maximum cleverness" you're writing code you won't be able to read.
- Consultant32452 10y agoMy rule of thumb is that I attempt to write code that a junior programmer whose experience is limited to a little more than having taken a course in the language and has done a couple tutorials on the framework(s) can maintain. I see so many developers try to squeeze every new language feature or loads of esoteric library use cases into their code because they learned something and feel like it MUST belong in the production code. Sometimes you have to write complicated code, but 99% of the time it should be possible to write very simple code using only the most commonly used language features.
- jdmichal 10y agoFor all of Java's pitfalls, this is one of the things it really has going for it. The language itself is extremely simple. I think adding properties instead of the weirdness of getters and setters would take it to peak simplicity and straight-forwardness. (Also, maybe eliminate inheritance and force interfaces and composition instead.)
- iamcreasy 10y ago> eliminate inheritance Why would you want that? Wouldn't eliminating inheritance add a lot of boilerplate code?
- jdmichal 10y agoI think default methods take care of most of the places where boilerplate would be required. The abstract collections are a great example of this; most of the methods required of a `Collection` can be implemented from a small subset. Sometimes you'll re-implement other operations anyway for efficiency gains, but that's supported with default methods also. However, I may just be weird. My Java coding style is probably closer to Rust or Haskell. Lots of interfaces defining my type requirements, and static methods to implement compound operations on those interfaces. I like this because it's easily testable and traceable.
- maxdeviant 10y agoYou can use composition to reduce boilerplate as well. Composition > inheritance is something that is emphasized greatly in the React community.
- tigershark 10y agoComposition increases boilerplate code. With simple inheritance hierarchies there is an inherent advantage in this regard. If you use inheritance you don't need to encapsulate the "base" object and implement all the methods of the interfaces doing most of the time just a routing to the base object, you can just extend from the abstract base object and implement only the methods that you need. Obviously if your hierarchy is complex then it is much better to use composition to have a better decoupling, but it has nothing to do with decreasing the boilerplate code. Composition and inheritance are just two tools for different jobs. If someone says Composition > Inheritance it is like saying Screwdriver > Hammer, a complete non-sense. There is no tool that is inherently good or bad, it all depends how the craftsman uses it (or don't) in a good or bad way for the job.
- jdmichal 10y ago> If someone says Composition > Inheritance it is like saying Screwdriver > Hammer, a complete non-sense. You're stretching a bit too far. Inheritance is nothing but composition with some default implicit virtual method routing. You admit as much in your comment. If you want tools, it's more like a hammer vs a mallet and a prybar. Same tools, same purpose, just one is bundled.
- mohaine 10y agoAdding properties would just make the language MORE complex. Then you would have fields, getters/setters AND properties. That said, a "property" keyword that auto-generated default getters/setters would be nice. This was one of things that always bothered me about C#, What is the point of properties. What do the offer that public fields don't?
- tigershark 10y agoYou don't need getters and setters in c#. If you don't have any side effect in a read-write property you can just use an automatic property. The same for read only properties that don't need to be recalculated on the fly. And I hope that I don't need to explain why using a write only property is almost always a code smell. In the other cases you can use a normal property with a backing field. If your code is well written and you use the appropriate tools, only rarely you need normal properties (that are as annoying as getters/setters). What do getters and setters offer that public fields don't? Properties offer exactly the same advantage as getters and setters, fields encapsulation https://en.m.wikipedia.org/wiki/Field_encapsulation https://en.m.wikipedia.org/wiki/Field_encapsulation No wonder that you don't understand properties if you don't know why getters and setters are useful.
- krzat 10y agoI prefer Swift's solution, where fields and properties are unified. Makes so much more sense.
- tigershark 10y agoJava is a quite awful language honestly. And I use it everyday at work. Generics implementation with type erasure is a pain and complicates things a lot. There is no automatic static type inference and before Java 7 you had to specify twice the generic types in the same statement. This adds a lot of "complexity" or noise when reading some code. Checked exceptions..do we want to speak about all the complexity that they add? Before Java 8 there was absolutely no first class support to closures, and if you wanted to have something equivalent you had to use an anonymous inner class... Very simple, eh? All the streams (as in input/output streams) are heavily used and while sometime they are useful, they complicate needlessly the code. The streams implementation (as in the Linq-like feature) is more complex than Linq. Honestly I can't say that Java is a simple language. It may be true if you just use loops and basic statements, but you can say the same for pretty much every other high level language. Finally I'm quite perplexed for the reasons why you want to kill inheritance. While it is true that when it is abused is bad, ditching it completely is wrong because used in the right way can make you code simpler.
- jdmichal 10y agoI think there's two definitions of simple being used between you and I. Let's use different words instead: obviousness and terseness. Obviousness is how clear the goal of the code is; terseness is how much typing it takes to get there. I'm using simple to mean obviousness; this seems to be in line with the article, as being "clever" typically means exchanging obviousness for terseness. You seem to be taking terseness as your definition of simple. Now Java is the king of obviousness; it's very clear exactly what is being done on every line of code. It pays for it in being very wordy. I don't like inheritance because it breaks obviousness; it's no longer obvious where a virtual call is actually going to be served. With composition, the immediate object has to serve the call, even if it's just to delegate it. The only virtual calls would be dispatching calls to interface methods. And this style isn't expensive after JIT; inlining these kinds of delegations is its primary optimization. (Think getter-method chains that return a field value, a common pattern in Java.) Lambdas were a step towards terseness, but they sacrifice obviousness to get there. It hides things... What SAM type is a lambda implementing? You have to check to call site; the lambda itself won't tell you. The anonymous class syntax tells you exactly what is being implemented, but that means you have to type more to get there. Now, I like properties because IMO they optimize both obviousness and terseness. You are obviously making a single property with a getter and a setter, as opposed to defining each separately. And you are more terse by removing the need to define each separately.
- munchbunny 10y agoMy measuring stick for "cleverness" has two axes. The first axis is how far away you are from the naive solution(s). The further away you are, the longer it takes someone else to understand what you're doing. In some cases you have to take a non-obvious approach, usually for performance reasons in my experience. Fortunately, commenting is a good way to explain when you are using a non-obvious solution to a problem. The other axis is how many edge cases your solution has relative to the general case. The negative connotation of "clever" is that the clever approach works but is over-specialized for the specific set of cases where it's used. It might not solve the general problem, but it solves enough specific cases of the general problem for your current needs. Then when for some reason the larger program changes (new feature?) and the solution is expected to handle a new case, it fails, and now you've got a clever non-working solution. To me, code that is clever in the sense of "non-obvious algorithm" is fine when it is needed. Just comment and explain it well. The problem is when your clever code comes with a side effect of brittleness. Either document the edge cases thoroughly, or use an approach with fewer edge cases.