Live data from Hacker News

Code doesn’t have to be a mess

danielsieger.com

181–190 of 190 posts

Re: Code doesn’t have to be a mess

#181
post #145

Earlier quoted context omitted.

The thing is that if you just need to understand a specific part of something you will need to jump as well even if everything you needed for that one thing is written sequentially in one file. You will want to skip over implentation details of certain things to get the general picture first on a more abstract level. Let's say you have a simple endpoint that takes a list of comma separated inputs, parses them as numb…

You can easily understand what it does because you picked an example that is easy to understand :) This discussion often ends up in the extremes: inline everything versus abstract everything. I don't think anybody reasonable would opt for either of those extremes, we should focus on the very large middle ground where there's a lot of subjectivity. Trust me on this, I've been raised on the DRY dogma and all related ar…

It may not have been evident from my simple example but I do agree with your "middle" approach. That's where I try to end up in our code base. Endless interfaces, methods that are only one line long and such are counter productive. But nobody can tell me that inlining quicksort will ever be useful outside of a place where your compiler can't do it for you and you need to favour execution speed over everything else. I don't believe such places really exist much if at all any longer.

What I do have to have to question is the strict non-use of constants. It can be very very useful to use constants for such things, e.g. if you are calling libraries that do not make it apparent what is what. Say you have something that takes a timeout value.

    send(data, 10)
What is this? I have to know what send is, what parameters it takes etc. I might have to look that up. I can easily work around that with a constant.

    const timeoutInMillis = 10
    send(data, timeoutInMillis)
The same principle can easily apply for other similar situations. I really like it for things like

    doSomethingThatCouldTakeLongButAlsoShouldHaveATimeout(data, 64800000)
What is that and what does that value even mean in human readable? Of course some of these values you will recognize if used enough but so far my domains have been sparse enough that I don't recognize all of them and have to compute. Much better (with shorter, real names anyway but ya know, we're dealing in simple examples here :) ):

    REALLY_LONG_RUNNING_PROCESS_TIMEOUT_IN_MILLIS = 1000 * 60 * 60 * 18
    doSomethingThatCouldTakeLongButAlsoShouldHaveATimeout(data, REALLY_LONG_RUNNING_PROCESS_TIMEOUT_IN_MILLIS)
So far most people I've talked to find that it's much easier to recognize that this has a timeout of 18 hours but the method happens to want milliseconds.

Oh and don't get me started on people that use the constants from the real code in their tests, completely defeating the testing. Especially if they then do math with the constants and simply copy the math - or worse, put the math into a method and call it from the tests too - to their tests. Test expectations have to be computed once, when writing the test and just hardcoded into them, otherwise they serve no purpose as changing the code itself will always result in green tests even if you've just made a major mistake by changing the values without thinking.

Re: Code doesn’t have to be a mess

#182
post #177

Earlier quoted context omitted.

The thing is that if you just need to understand a specific part of something you will need to jump as well even if everything you needed for that one thing is written sequentially in one file. You will want to skip over implentation details of certain things to get the general picture first on a more abstract level. Let's say you have a simple endpoint that takes a list of comma separated inputs, parses them as numb…

This would be the “simple” code. The “abstract” code would be more like this: public class EndpointManager { private EndpointInputManager eim; private StringSplitter splitter; private NumberParser parser; private Sorter sorter; public EndpointManager(EndpointInput input) { eim = new EndpointInputManagerFactory().setInput(input).build(); splitter = new StringSplitterFactory().setDelimiter(new Delimiter(",")).build();…

My guess is this is Java or something close? We can make that much more readable. We may have to do away with bad libraries. A lot more could actually be magicked away, which can also be a problem sometimes. In a "real" application this resource's interface would probably not just take a comma separated string in a body but accept a proper JSON object or somesuch and not just be a "sort endpoint" but it's not going to be much different from this if written properly. I happen to like the few annotations you'll see me use here. I also think that something as simple as a line break can unclog things. Also the choice of having each of the stream operations in a separate line is deliberate for readability. There are linter/auto formatting rules to enforce this (we do this at my current place for example).

    @Path("/sort")
    public class SortResource {

        @GET
        public List sort(@Body String input) {
            validate(input);
            return Arrays.stream(input.split(","))
                .map(Integer::valueOf)
                .sort()
                .collect(Collectors.toList());
        }
    }
I do recognize the kind of code you pasted. Had to work in code bases like that for way too long. Never want to work in one of those again. There's probably lots of EJBs and other such nonsense around that?

Re: Code doesn’t have to be a mess

#183

Earlier quoted context omitted.

> People abstract before an abstraction is necessary. Sometimes an abstraction cuts to the core of the reason why. See for example https://algebradriven.design/ Good abstractions can communicate intent better than mounds of concrete code because they speak at a higher level. However, mounds of okay concrete code is way easier to deal with then poorly thought out abstractions. This means pragmatists get little practic…

I started designing an algebraic language by writing code. https://GitHub.com/samsquire/algebralang It's designed to be expressive and powerful and practical. The core insight to a problem is rarely what we spend most of our programming time doing.

> The core insight to a problem is rarely what we spend most of our programming time doing.

I believe that is a mistake.

I'll have to check your language out though!

Re: Code doesn’t have to be a mess

#184

Something that shocked me was working with junior programmers for the first time. For decades , I had either worked solo or with other experienced developers. It was an eye-opening experience. My style is influenced by Haskell and Rust, even when I program in, say, C# or PowerShell. A simple example: I will extract the read-only logic into a pure function and minimise the size of the mutable procedure. This makes it…

This is my current struggle. I've enjoyed mentoring in the past, but right now I'm getting very exasperated feedback. It's hard because I don't have control of the environment to alleviate the deadline pressure, but I still want to help people learn. The end result seems to be a pile of tech debt for now. C'est la vie.

Re: Code doesn’t have to be a mess

#185

Something that shocked me was working with junior programmers for the first time. For decades , I had either worked solo or with other experienced developers. It was an eye-opening experience. My style is influenced by Haskell and Rust, even when I program in, say, C# or PowerShell. A simple example: I will extract the read-only logic into a pure function and minimise the size of the mutable procedure. This makes it…

This is my current struggle. I've enjoyed mentoring in the past, but right now I'm getting very exasperated feedback. It's hard because I don't have control of the environment to alleviate the deadline pressure, but I still want to help people learn. The end result seems to be a pile of tech debt for now. C'est la vie.

Something I observed very early on in my career is that bugs will have to be fixed no matter what. You can put them on the todo list and fix them later, or fix them right now. Either way, you're going to have to do the task.

It's like a conservation rule in physics, for every bug found, a bug fix must eventually be implemented. Bug in, fix out.

But... if you leave a bug lingering, then it can cause test failures for unrelated code development. It can trip up other developers. It can cause false positives until resolved.

So the only logical conclusion is that all bugs must be fixed ASAP, otherwise they have a "multiplier" factor dependent on how long they're allowed to persist. If left unchecked, this can blow out exponentially, until you're unable to efficiently fix bugs because you're tripping over thousands of other unfixed bugs while doing so.

You would think this kind of thing is logical, but no-one ever believes me. There's just slow blinking and then a slower repeat of the same old mantra: "We'll fix it... later?"

Re: Code doesn’t have to be a mess

#186
post #8

Ah the Unix philosophy. `man ssh' gives `ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-J destination] [-L address] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] destina…

Works quite well in conjunction with Googling "how do I do X in ssh stackoverflow".

You can do X. X Window forwarding ;)

Re: Code doesn’t have to be a mess

#187
post #101

In my experience people refactor code to their own understanding of the problem and not all refactorings improve the code. People abstract before an abstraction is necessary. I find single file dense leetcode style code easier to understand and follow the flow. Algorithmic code I can reason around. A large mature codebase is far harder to get to know. One of the first things I do when I study a new codebase is find a…

> People abstract before an abstraction is necessary. This one really frustrates me. Write code to the complexity level needed to solve the problem, and nothing more. The only time I'd break from this is if I know for certain that the added complexity is going to be necessary in the near term. > ... not all refactorings improve the code. While true, I have a low tolerance for code that requires constant bug fixing, o…

>> People abstract before an abstraction is necessary.

> This one really frustrates me. Write code to the complexity level needed to solve the problem, and nothing more. The only time I'd break from this is if I know for certain that the added complexity is going to be necessary in the near term.

I worked with a guy who did that. He had a plan for what the project would look like 5 years down the road, and he built abstractions to support that. He could get away with it because he could hold it all in his head and it all made sense to him. When version 1 was half finished he was called away to work on another project, and those of us who followed in his wake struggled to make any sense of what he left behind. A year later he was laid off. The project was a success, but nobody ever asked for version 2.

Re: Code doesn’t have to be a mess

#188
post #45

In my experience people refactor code to their own understanding of the problem and not all refactorings improve the code. People abstract before an abstraction is necessary. I find single file dense leetcode style code easier to understand and follow the flow. Algorithmic code I can reason around. A large mature codebase is far harder to get to know. One of the first things I do when I study a new codebase is find a…

Maybe I'm weird but a lot of my refactoring actually concretizes overly abstract code. It's easier to think about adding functionality to a block of code when you acknowledge that at the moment it only does 2 things, rather than using obscure wishy-washy language that implies it could do a dozen things. Where I'm definitely weird is that I have a higher verbal score than your typical developer, and I'm not afraid to…

Yep, I do similarly.

More tightly bound code is often easier to understand and mechanically modify later - there are fewer places where you lose "if it compiles, it works" guarantees.

I feel like a lot of people are blindly pulling coding habits from libraries, and applying them everywhere. Libraries and applications (i.e. "terminal" products not used as a library by someone else) have different needs and different goals - don't write your application like a library, it'll be a huge pain.

Re: Code doesn’t have to be a mess

#189

Earlier quoted context omitted.

This is my current struggle. I've enjoyed mentoring in the past, but right now I'm getting very exasperated feedback. It's hard because I don't have control of the environment to alleviate the deadline pressure, but I still want to help people learn. The end result seems to be a pile of tech debt for now. C'est la vie.

Something I observed very early on in my career is that bugs will have to be fixed no matter what. You can put them on the todo list and fix them later, or fix them right now. Either way, you're going to have to do the task. It's like a conservation rule in physics, for every bug found, a bug fix must eventually be implemented. Bug in, fix out. But... if you leave a bug lingering, then it can cause test failures for…

I agree. I think a zero defect mentality keeps things moving along smoothly. Unfortunately, people think I'm just being a perfectionist. I'm just trying to not trip on the treadmill. Every bug is another stumbling block.

Re: Code doesn’t have to be a mess

#190
post #177

Earlier quoted context omitted.

The thing is that if you just need to understand a specific part of something you will need to jump as well even if everything you needed for that one thing is written sequentially in one file. You will want to skip over implentation details of certain things to get the general picture first on a more abstract level. Let's say you have a simple endpoint that takes a list of comma separated inputs, parses them as numb…

This would be the “simple” code. The “abstract” code would be more like this: public class EndpointManager { private EndpointInputManager eim; private StringSplitter splitter; private NumberParser parser; private Sorter sorter; public EndpointManager(EndpointInput input) { eim = new EndpointInputManagerFactory().setInput(input).build(); splitter = new StringSplitterFactory().setDelimiter(new Delimiter(",")).build();…

I was going to make the predictable joke that you need a factory. Disappointing that you took care of it already.
Post reply on HN