Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> why I try to keep functions/modules as simple as possible and ideally not longer in length than I can see on my screen at once (when possible)

This is the paradox of "readable" code. Each person has a different definition of it. I also prefer to write as dumb code as possible (well, these days I do, I of course tried to be extra clever in my earlier days). But for me it's the jumping around that makes me lose focus. My limit is about 3-4 jumps. This is not to say I write long meandering functions, but I personally couldn't imagine a codebase I'd be happy working in that is made up of modules that fit on a screen. Maybe it's possible! But the projects I've worked on that have a linter rule of "100 lines per file" or whatever end up being these rabbit holes. It's so hard to come up with code design guidelines everyone can agree on.

As a side note, I despise things like imports and aliases. I'd prefer that when I do jump to a function, I can read it without having to check if anything is imported or not. I always opt for fully qualified function calls, regardless of how many characters it is.



I cannot stand programs that are excessively split up and have too many files. There is nothing worse, especially combined with tiny functions.

Not to mention the performance impact caused depending on the language. At this point I do not even care if it's true or not that the impact isnt negligible, if you are submitting something like that for me to review I'm probably going to demand you inline (not with the keyword, with copy paste) the majority of your functions and merge the files.

I think they are teaching this tiny function and tiny file method of programming in schools now or something. I get tons of submissions where there isn't a single function longer than 4 or 5 lines. I'm going to blame it on Java and OOP because thats when I started seeing it, probably due to people writing classes like that with trivial getters and setters rather than public fields.


When I was working in Ruby, I think the default function length was 5 lines. I used to be on board with this until I helped write a whole system adhering to this.

Small functions aren't bad per se, especially if they are re-used a lot, but I no longer believe that they are inherently good. Especially awful are having a lot of tiny single-use private functions.

I think that developers often want an easy way to say "we must do this" and have a tool tell them to do so. Tools can get us pretty far but at some point writing good code is going to come down to taste. This is of course very hard in many large project situations where its every team for themselves, and often every developer for themselves within a team.


IntelliJ recommends inlining single use functions.


> As a side note, I despise things like imports and aliases. I'd prefer that when I do jump to a function, I can read it without having to check if anything is imported or not.

One idea might be to use an LSP (Language Server Protocol) interface. It could describe the fully qualified symbol for you when you, say, select the abbreviated symbol or press a keyboard shortcut. I've been working on a moderately large C program with Emacs and clangd[1] recently and have been amazed at how 'immersive' it feels, and that's from someone who's used to the comfort of a Lisp REPL!

[1]: https://clangd.llvm.org/


I work in Elixir and there are LSPs available. I'd still rather be able to just read and take as little action as possible to have to figure out where something is coming from. But as a sibling commenter says, they hate long names, so it's impossible to please everyone and comes down to teams making agreements.


For me it's not just the jumps but also overly long names. My ability to quickly scan the code is hindered by names that all jumble together because they aren't visually distinct enough. And when they read like a book, I'm going to have the same problems I have when reading books where I'm somehow reading all these words across the page but at the same time not actually processing any of it.


I have a colleague that loves to call functions things like ‘convert_object_type_from_mm_to_m’ and ‘convert_object_type_from_m_to_mm’ . It’s unscannable. They’re the same to me.

He does not like my ‘meter_to_mm’ and ‘mm_to_meter’ because the abbreviations are inconsistent, no verb is used and he needs to go all the way to the typehint to know the input. We both have a point, but there is not really a clear middle ground without writing a novel in function names.


Ya, that is ridiculous, honestly. While it's still all subjective, you gotta draw the line somewhere! I'm a stickler for consistency myself and would be ok with `meter_to_millimeter` but the `convert_object_type_from_` is pure nonsense. Like, assuming you're talking about a language with objects, what the heck else would you be converting?? EDIT: requiring verbs in function names is also overrated. It's one of those things that's usually a good idea, but if comes down to employing some taste to decide when it might not be. EDIT 2: I'm now upset for you for having to put up with that, lol.


I’d personally go with a single function like “convert_object_type” and pattern match into different clauses such as “convert_object_type(obj, from: m, to: mm)” and so on.


I believe a good variable name should be a token. To me this means that it should be visually distinct at a glance without reading it. This runs counter to my job where 20+ character variables are common.

Token length names are really useful when working on a contained codebase. Exposed endpoints result in longer names and a messy spelling errors


What constitutes an overly long name for you? Are you talking Java-y things likes `UserAccountBuilderFactoryFactory` or even just something like `operation` instead of `op`?


For the `operation` vs `op` example, it's highly contextual. If it's used in a narrow scope or if it's repeated many times (like I've seen in functions that copy fields of one structure to another), `op` is preferable. Otherwise I'm fine with `operation`.

The Java naming is one cause of what I really have a problem with. Like that name on it's own isn't the worst because the key info is right at the start and I'm probably not going to see the type name in function bodies I'm trying to follow. It's when that naming is combined with other overly verbose naming that it gets really gets bad: `CreateUserFromUserAccountBuilderFactoryFactoryOnBackgroundThread()` By the time I've read "BackgroundThread" I'm glancing backwards to see what is happening on the background thread.

Other places where longer names make reading harder are when the names are very similar. With `textBoxXPosition` and `textBoxYPosition` the X and Y get lost too easily. You could rearrange the letters to the front to help with that, but it can still make computations harder to read: `sqrt(xTextBoxPosition * xTextBoxPosition + yTextBoxPosition * yTextBoxPosition)` vs `sqrt(x * x + y * y)` or `sqrt(tbx * tbx + tby * tby)`


I think we're mostly in agreement here, thanks for sharing!

I actually always write full variable names, even in narrow scopes. This is mostly because I'm used to programming in dynamic languages and it makes renaming much easier. I've also become so accustom to it that it makes scanning incredibly fast. For example:

    Enum.map(operations, fn operation ->
      execute(operation)
    end)
I can pretty much just read the left-hand side of that if I'm scanning really quickly, ie, ignore everything after `fn`. I'm talking micro-optimizations here, but I have been tripped up before when someone did something like `optn`.

Elixir allows for a shorthand notation for anonymous functions like so:

    Enum.map(operations, &execute(&1))
Some people hate that but again I like it due to the refactoring advantages (it becomes very simple to read once you get used to it).

I hear you on the x/y thing. You example is actually why I really prefer snake case, though I don't want to start a flame war there, haha. But ideally when you're dealing with points and dimensions you wrap them in a type or object that you can pass around and the receivers can extract simple `x` and `y` variables from them.


not OP but I think even just `operation` vs `op` should be self explanatory for the majority of devs. And documentation can dispel any doubt regarding the interpretation of the name.

Terse naming is just fine as long as the names are visually distinct from those in the same scope/namespace and as long as engineers/developers are religious about proper documentation.

i.e. members/classes/types/fn/etc getting a doxy/doc description and local variables getting a `//` comment if their meaning and use isn't easily derivable from the immediate context.

If that isn't happening however, you probably need to be pushing for more descriptive names or better docs during code review.


It's self-explanatory for sure, but I would prefer the actual domain term be Op as well. IE, I really dislike `op = Operation.new()` or whathaveyou. This breaks stuff like editor highlighting and whatnot. It's also harder to keep consistency through a codebase. Like maybe some people do `o = Operation.new()`. I find very high cohesion here helps my code-scanning a ton.

I'm not saying that would be true for anyone, just furthering my premise that it's different for everyone.


At my firm we’ve standardized on import being used only for a short list of well known first/third party modules (e.g. Ecto.Query and Plug.Conn).

Application modules can be aliased, but not library modules. This is so that we don’t need to keep repeating the name of the application throughout the codebase while preserving clarity as much as possible.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: