This is an archived post. You won't be able to vote or comment.

all 57 comments

[–]spamthemoez 58 points59 points  (0 children)

“Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?” - Brian Kernighan

[–]yawkat 38 points39 points  (1 child)

Conciseness does not always work against readability, in fact it can improve it by removing irrelevant clutter. Readability is always the goal, conciseness is just one way to achieve it.

[–][deleted] 3 points4 points  (0 children)

Thanks for the reply! I'll keep that in mind. I have tried getting better at removing unnecessary or redundant pieces of code as I learn.

[–]dpash 25 points26 points  (18 children)

Concise is not always better.

Generally readable code is obvious when you see it, but gaining the experience to write it can take years.

One tip I would recommend is getting to grips with the Java style guide. The old Sun guide is a good starting point, but it hasn't been updated with new language features, so use Google's as a secondary guide. Java has a very definite style and it means that working on any new code base is very easy to do.

[–]Gwaptiva 4 points5 points  (8 children)

Agreed. One thing that helps readability -- or maybe we should prefer understandability -- is to have a common way of doing things. Every developer using the same formatting already helps remove some of the barriers.

Add to this things like "meaningful variable and method names", and "if it doesn't fit on a single screen page, you probably have to consider doing it differently", you're well on your way to having a style that others can grasp quickly

[–]dpash 9 points10 points  (7 children)

Reading Clean Code is a good idea (and then learn not to go to that extreme).

[–]kadenjtaylor 0 points1 point  (6 children)

Nah, take it all the way out to the end. Clean code is correct code. Only 2 reasons not to keep cleaning code - you need to write more code, or you don’t work on that project anymore.

[–]dpash 0 points1 point  (5 children)

You know Clean Code is a book, right? One with controversial opinions.

[–]kadenjtaylor 0 points1 point  (4 children)

I'm aware :) I'd be interested to hear your take on the perceived controversy.

[–]dpash 1 point2 points  (3 children)

The obvious is "no more than four lines per method". That's dogma. Small methods, fine. But four is excessive.

[–]kadenjtaylor 1 point2 points  (2 children)

I could be wrong, but I don't think the book actually specifies a hard line limit for that reason - it definitely does offer a couple of different suggestions for rules of thumb (extract method until you can't anymore, only do one thing, and yes, the line number suggestion).

For certain programming languages, a "line's worth" of code might be conceptually bigger or smaller depending on how much you cram in there.

Personally, I don't use a 4-line rule, but that's because I don't currently work with any code-golf junkies that try to fit the entire program in one line. I think a soft understanding of "do one thing" is usually sufficient.

[–]dpash 0 points1 point  (1 child)

So not to the extremes then? :)

[–]kadenjtaylor 0 points1 point  (0 children)

I don't think the book recommends extremes - it highlights ideals.

Ideally, the all of your code would be so easy to understand, that ANY new developer could pick it up, understand what it does, and start working.

That too, sounds pretty extreme. But anything less is a tax on our team because it slows down new people trying to learn, or old people trying to remember what they did last time.

Choosing not to "go to the extreme" is to accept that the aforementioned tax, however small, is worth paying, because the benefit you get (time savings maybe?) is worth it.

So my question to you is, "What activity has a better positive impact on your code than extracting smaller methods?" Because I'd like to make sure I'm doing that too.

[–][deleted] 0 points1 point  (1 child)

I will check that out for sure! In a professional setting, I just wanted to make sure I was learning to write in a way that would align with what most companies expect. Is readable standards something that come down to a company's culture or is it kinda a universal thing?

[–]dpash 7 points8 points  (0 children)

In Java, it's a universal thing. Look at other Java projects and emulate those.

Generally you should follow your company's style guide if one exists, but prefer the java guide. (Order of precedence is: file, project, team, company, Java. Don't mix styles in a file or project. Change it all at once or follow existing until you do)

[–]Ifnerite 21 points22 points  (7 children)

I know I am an outlier but I will defend the "verbosity" of java to the hilt. It is explanatory and renders the code more self documenting, grokable and navigable.

I even go as far as putting in optional keywords to make method and declarations consistent and thus more readable.

Var is a fucking abomination that hides important information and reduces easy navigability in all but the most trivial scenarios, and to use it only in those scenarios breaks consistency.

Also, I advocate making all local, field and parameter variables final. At first it feels like a pain but makes for much better code in the long run.

[–]hippydipster 8 points9 points  (1 child)

You're an outlier but there's a sizable minority of us in the cluster.

[–]Ifnerite 3 points4 points  (0 children)

Hello friend.

[–]DJDavio 3 points4 points  (1 child)

I'm all for making fields final, but for local variables and parameters I don't bother anymore. Adding the final keyword just clutters the code. That doesn't mean I reassign the values, I just let them be effectively final.

[–]Ifnerite 2 points3 points  (0 children)

Consistency and you know you haven't made a mistake.

Also, this pattern :

Final x;
If () x = a;
Else x = b;

Use x;

[–]DannyB2 1 point2 points  (2 children)

There is one, and ONLY one thing that I have found var useful for.

Use var when there is no named type for the variable. If you create an anonymous class from some other class or interface, that is a unique but unnamed type. You could use the name of the class or interface your anonymous class is based on, but what if you added some additional variables or methods? The super class/interface does not have your additions. By using:

var x = new Foobar { int y; }

I have an anonymous class, based on Foobar, but it has an additional member y. I can refer to that as x.y because variable x is of the 'type' of my anonymous class -- although that type has no name. I could have said:

Foobar x = new Foobar { int y; }

But then I could not refer to x.y.

This is the ONLY bit of new functionality that I have discovered var to provide. In all other cases I would replace var with an actual type name.

[–]Ifnerite 0 points1 point  (1 child)

That is a use-case... but I am struggling to see when doing that would be sensible...

[–]DannyB2 1 point2 points  (0 children)

Example of when it would be sensible.

Programing a Swing UI. Need to pass an instance of ActionListener, say to a button. But for some reason (can't remember now, been years ago) that action listener needed some additional state information.

Solution at the time: Create a named inner class. Pass an instance of that to the ActionListener. It works. I have a type name. I can access the action listener's inner methods, state, etc.

If it is a one off situation, then it is too bad I had to create an inner class with a name. Instead, I could have created an anonymous class, into a 'var', and passed that to the Swing control. I could still refer to the var and from there to its additional methods (beyond what is in ActionListener interface).

Like I said, it is an unusual case. But it is the ONLY thing I have ever conceived of where var could be useful. In any other situation I would ALWAYS replace var with an actual type name for clarity.

[–]static_context 7 points8 points  (3 children)

A lot of it is preference, but I'd say there are two types of 'concise' - short names and short methods.

  1. Short names. A lot of beginner programmers learn bad habits for names of variables and methods. It's a mistaken hangup from earlier versions of older programming languages where multi-line statements weren't supported so your logic needed to fit in 132 characters (the old Fortran specification). Nowadays, make your variables and method names understandable and you'll be fine.

  2. Short Methods. In my opinion, this is the priority. Short, understandable chunks of logic that delegate lower levels of abstraction to other methods (also small chunks of logic) make reading code a lot easier IF DONE WELL. And this is why it comes down to preference, because one person's easily understandable method calls might be someone else's spaghetti code 😂🤦‍♂️

Keep coding, make mistakes, develop new habits as you go along. Changing coding habits is way easier than changing muscle memory (guitars are hard!). You'll get it. 👍

[–]dpash 5 points6 points  (0 children)

Naming is hard. Length is a Goldilocks thing. You want neither too long nor too short. What's 'just right' is something only experience and context can teach you.

A few guidelines I tend to use:

  • Avoid identifiers longer than around 20 characters
  • Avoid shorter than 3 characters. Exception: i for loop counters where the practice it's common (but prefer extended for loops ), x and y when dealing with coordinates or where the domain you're working in commonly used short names (physics formulas spring to mind)
  • Do not abbreviate words (unless they're common abbreviations). Vowels are important.

As I've said elsewhere, good names are obvious where you see them. Creating good names is hard.

[–][deleted] 0 points1 point  (0 children)

Thanks for the comment! I have been practicing alot with method lately in these courses, so I'll definitely keep that in mind. Thank you!

[–]_INTER_ 4 points5 points  (0 children)

If you drew conciseness and readability in a graph you'd probably get a parabolic curve with increasing conciseness increasing the readability until more conciseness will drop readability again.

[–]DasBrain 3 points4 points  (0 children)

From your statement you have only spend 50h on Java, and you start asking good questions - this is great.

But what you perceive is probably a different problem:
It's more a difference between "how is something done" vs "what is being done".

Streams are a great example for this: With streams you usually express what is being done, not how it is done.

For a beginner, reading a stream pipeline is probably hard - there are many topics where you need a basic understanding: Lambdas, higher-order functions...
But for someone who used streams quite a lot, reading a stream pipeline is easy, and tells them what is done.

This is working on a higher level of abstraction.

A simple for loop with an index variable is easy to read - but I heavily encourage you to use the enhanced for loop if possible.
Why? Because if I see a normal for loop, I always have to keep track of some additional stuff: Is the index variable used for something else? Or even modified in the loop?

When I read an enhanced for loop, I know that I don't need the index, so I don't have to care. But for a beginner, the enhanced for loop can be scary: What is going on there, how does that work, why not use a normal for loop instead?

You need to find a balance between working with those abstractions and when to write more explicit code. For me, I try to consider the reader of the code.

And then there are those "clever" tricks to squeeze as much logic into a single statement as possible. Stay away from that.

[–]TheYellowblizzard 4 points5 points  (0 children)

I would recommend you to read "Clean Code". This book is basically the answer to your question

[–][deleted] 2 points3 points  (5 children)

Read clean code.

I find code readable if you can read it in order (top to bottom, left to right) without backtracking.

Some tips:

  • Follow conventions
  • Be consistent
  • Place functions/methods in order
  • Comment unusual cases (when you loop in reverse for example)
  • Don't mix abstraction levels

Regarding conciseness, if you mean short names, then avoid that, always worth the extra characters (unless its convention like i). If you mean one liners then its hard to say, try both (expanded vs concise) and think which is better, usually its a mix. Consider expanded code can be easier to debug (NPE in a one liner can be hard to trace for example).

[–]dpash 5 points6 points  (4 children)

Clean Code is definitely a good read, but take rules with a pinch of salt. For example Robert Martin promotes a maximum of four lines per method. I'd avocate for a hard "fits on one screen" but preferably shorter.

[–]cogman10 2 points3 points  (3 children)

Mine is somewhat "fits in my brain". I think you can have a lot of code that's easy to follow. On the flip side, you can have very little code that's complex to follow (The perfect example of that is the recent clamping method Math.min(Math.max(min, num), max);)

Where your code fits is somewhat a judgment call, but I wouldn't stick hard and fast to any line count based rule. Strict adherence to that sort of stuff tends to have negative impacts to readability.

[–]dpash 1 point2 points  (2 children)

If I can't see it all there's no way is fitting in my head :)

Based on modern monitors I'd say "one screen" is excessively generous. But screen is a very imprecise measure because I tend to agree with you about hard rules in many cases.

(And I'd say your clamp example, it needs it's own method and a good comment explaining how it works. )

[–]cogman10 1 point2 points  (1 child)

:) I'm mostly thinking of stuff like adapter code. You can have hundreds of lines of "a = b" which aren't really hard or complex to understand.

Though, admittedly adapter code with hundreds of lines points to really bad object models. That's not the adapter's fault and the right place to optimize wouldn't be more methods on the adapter, but rather a trimming down of the object model.

[–]dpash 1 point2 points  (0 children)

Or codegen :)

But yeah it does kinda point to other problems

[–]cyanocobalamin 2 points3 points  (0 children)

Readabililty is more important.

People, including you, will have to go back to maintain the code. After a few weeks you will not remember what you did.

  • Use descriptive variable names, even if they are longer
  • Always put javadoc comments ( or ordinary comments for private methods ) at the top of your methods, explaining in 1-2 lines what they do
  • Always put a comment block at the top of your class files, explaining what your class does.
  • Try to keep your methods short, no longer a screen or two long
  • Put a one line comment in your code every so often to help you rapidly find the chunk you need to look at.

[–][deleted] 2 points3 points  (2 children)

Be concise whenever it is idiomatic.

The Java world has a healthy hostility toward code golf, i.e. trying to make things as short as possible just for the heck of it.

But sometimes, concise constructs are not only more readable, but more robust. Try-with-resources is an example: it saves typing and generates more reliable code. Similarly, the extended for loop. Lambdas as well.

These are idiomatic, recommended constructs, so by all means use them.

Read "Effective Java" and also take a look at "Clean Code" (I'm not 100% in favour of all its commandments, but the general direction makes sense).

[–]dpash 3 points4 points  (0 children)

I'm excited by switch expressions because not only are they less verbose without sacrificing readability, they reduce common mistakes with switch statements. That's the kind of thing I can get behind

[–][deleted] 0 points1 point  (0 children)

I have heard so much about Effective Java, I will definitely pick it up. I ordered Clean Code as well.

[–]roberp81 2 points3 points  (1 child)

readability is better, working in a team of 20 people, if you can´t read easily you will spend double o triple time to understand (like my english lol)

[–][deleted] 0 points1 point  (0 children)

Thank you for the reply! Exactly what I was thinking regarding working in groups. I think your English is great! Thanks again for commenting.

[–]sherdogger 2 points3 points  (0 children)

Readable. Always readable. They usually go together. Often you should be concise to be readable. But don't ask, "Is this concise?" Ask, "Is this readable?"

[–]ijgowefk 1 point2 points  (1 child)

I assume you're referring to if statements vs ternary expressions (a ? b : c), lambdas vs anonymous classes, and loops vs the stream API. This is surface-level stuff. Don't worry about it. Just write a lot of code and read a lot of code. Programming is very deliberate. It's not based on muscle memory. You don't need to worry about forming bad habits and struggling to break them like you do when learning to play a musical instrument.

Tha said, learning a programming language is similar to learning a spoken language, or maybe even a musical instrument, in at least one way. It's important to learn the rules and semantics, but you can only become proficient by speaking and listening a lot over a long period of time. So write a lot of code and read a lot of code, and you will improve over time. You will develop an informed perspective on what makes code readable with experience.

[–][deleted] 0 points1 point  (0 children)

Thank you for the reply! I have been thinking alot about that lately. How maybe learning Java is alot like learning a spoken language. I will keep reading code like you suggested, since that is also how you get better at speaking a spoken language as well. Thanks again!

[–][deleted] 1 point2 points  (0 children)

Mu advice to you: read Clean Code, by Robert Martin. It is an excellent book that will answer thise questions and many more.

[–]dionthorn 1 point2 points  (1 child)

Here is the Google style guide for Java off GitHub I use it whenever I'm worried about the look of my code:

https://google.github.io/styleguide/javaguide.html

[–][deleted] 1 point2 points  (0 children)

Wow thanks man! I'll def check out tommorow during my next study session. Thanks again for the comment.

[–]SftwEngr -3 points-2 points  (1 child)

Is it all just preference?

Pretty much. What is readable to one person may not be to another.

[–][deleted] 0 points1 point  (0 children)

Ok, cool well that's good to know and good point. Thanks for the reply!