Skip to content(if available)orjump to list(if available)

Software development topics I've changed my mind on

latexr

> Most won't care about the craft. Cherish the ones that do, meet the rest where they are

> (…)

> People who stress over code style, linting rules, or other minutia remain insane weirdos to me. Focus on more important things.

What you call “stressing over minutiae” others might call “caring for the craft”. Revered artisans are precisely the ones who care for the details. “Stressing” is your value judgement, not necessarily the ground truth.

What you’re essentially saying is “cherish the people who care up to the level I personally and subjectively think is right, and dismiss everyone who cares more as insane weirdos who cannot prioritise”.

hliyan

There's another way to look at this: if you consider the school of thought that says that the code is the design, and compilation is the construction process, then stressing over code style is equivalent to stressing over the formatting and conventions of the blueprint (to use a civil engineering metaphor), instead of stressing over load bearing, material costs and utility of the space.

I'm fond of saying that anything that doesn't survive the compilation process is not design but code organization. Design would be: which data structures to use (list, map, array etc.), which data to keep in memory, which data to load/save and when, which algorithms to use, how to handle concurrency etc. Keeping the code organized is useful and is a part of basic hygiene, but it's far from the defining characteristic of the craft.

Retric

> the formatting and conventions of the blueprint

Some of those formatting conventions are written in blood. The clarity of a blueprint is a big deal when people are using it to convey safety critical information.

I don’t think code formatting rises anywhere close to that level, but it’s also trying to reduce cognitive load which is a big deal in software development. Nobody wants to look at multiple lines concatenated together, how far beyond that you take things runs into diminishing returns. However at a minimum formatting changes shouldn’t regularly complicate doing a diff.

hliyan

I 100% agree. The problem is that after a half a century, software engineering discipline has been unable to agree on global conventions and standards. I recently had an experience where a repair crew was worried about the odd looking placement of a concrete beam in my house. I brought over the blueprints, and the technician found the schedule of beams and columns within seconds, pinpointed the beam and said, "Ah, that's why. We just need to <solution I won't go into>". Just then it struck me how we can't do this in software engineering, even when the project is basically a bog-standard business app: CRUD API backed by an RDBMS.

desdenova

Fortunately nowadays formatting issues can be delegated to autoformatting in any popular language.

Some people still argue over autoformatter parameters, but then people will always find a bike shed to argue about.

skydhash

The value of software is both what it does now (behavior), and what you can get it to do later (structure). What you described as design and the compiled artiface is the behavior.

The craft is what gives you future choices. So when people cares about readability, writing tests, architecture, they’re just making easy for them to adjust the current behavior later when requirements change. A software is not an house, it doesn’t get build and stays a certain way.

binary132

There is definitely something to be said for the idea that a shitslop engineering blueprint which still conveys correct design (maybe; who knows really?) is shitslop, whether or not the design is sound. In the case of software engineering, the blueprint is the implementation, too, so it’s not just shitslop blueprinting, it’s also shitslop brickwork (totally sound bones though I promise!), shitslop drywalling, shitslop concrete finishing and rebar work — and maybe it’s all good under the hood! Totally fine if all you’re building is a shithouse! But I think you get where I’m going with this.

anuramat

> not the defining characteristic

Did anyone claim otherwise? Besides, I imagine bridges aren't rebuilt every week -- poor blueprints can only cause a finite amount of pain.

TickleSteve

architecture over implementation (for details).

chrisjj

> the school of thought that says that the code is the design

There's such a school?? Seriously??

xnorswap

The solution is to have computers enforce the code style. Pick a linter, pick a set of rules, and then forget about them.

Things I beleive:

- If you're picking up on code-style in PRs then your toolchain is backward.

- If you're changing linting rules every month then you're focussed on the wrong things

- It's better to have a consistent style than a perfect style

bjourne

While Python has some great linters, I don't know of any in C that can correctly and automatically enforce some coding style. Most of them can only indent correctly, but they can't break up long lines over multiple lines, format array literals, or strings. Few or none knows how to deal with names or preprocessor macros.

brandmeyer

clang-format and clang-tidy are both excellent for C and C++ (and protobuf, if your group uses it). Since they are based on the clang front-end, they naturally have full support for both languages and all of their complexity.

bayindirh

Yes. I love how gofmt has no settings, basically. Is this how you envisioned? Great. Now I don't have to think about optimizing it.

Coincidentally, the choices they made are the choices I'd made, but it doesn't matter in the end.

maleldil

IMO, gofmt doesn't go far enough. It should sort imports and break lines automatically, or you end up with different people with slightly different preferences for breaking up lines, leading to an inconsistent style.

Something like gofumpt + golines + goimports makes more sense to me, but I'm used to ruff in Python (previous black + isort) and rustfmt.

I'd say that if you're manually formatting stuff with line breaks and spaces, that should have been automated by tooling. And that tooling should run both as a pre-commit hook and in CI.

secondcoming

This is what we did with clang-format on our code base.

The result is occasionally ugly code and nobody is 100% happy but at least it's consistent.

maleldil

Gofmt's style is no one's favorite, yet gofmt is everyone's favorite.[1]

[1] https://go-proverbs.github.io/

hackflip

Have you ever noticed that anybody driving slower than you is an idiot, and anyone going faster than you is a maniac?

aswerty

In my opinion, I think the author is criticizing bike shedding [1] rather than meaningful decisions. Of course some people will differ on whether a decision is one or the other. But as a whole, not sweating the details is a good quality to have whatever road in life you are on.

[1] https://en.wikipedia.org/wiki/Law_of_triviality

The_Colonel

Everyone dislikes bikeshedding. But people disagree on which questions are bikeshedding and which aren't.

Cthulhu_

Thing is, you can care for the craft, but let the code style and linting tools do what they do best and don't stress over them. Code reviews are better now that there's tooling that automatically checks for, fixes, or marks common issues like code style so the reviewer doesn't have to do anything with them.

That is, I'd argue the "stressing" is not about what these tools check, but about the tools and their configuration itself. Just go with all the defaults and focus on bigger issues.

ozim

If you want to compare to artisans - they were stressing about details that customers see, details that customers don’t see were to cut corners on.

Making fuss about indentation in code file is not artisanal. It is insane weirdo if we are charitable and if not clueless and childish.

sumtechguy

Everyone wants a particular style. Except when they have to use someone elses style.

Pick a style stick with it. Review it every 6 months to year to see if anything needs to be tweaked.

If you hear 'we are professionals' you are about to see code that has 20 different styles and design patterns.

I worked with one guy who could not make up his mind and changed the whole style guide about every 2-3 weeks. It royal made him mad the original style guide fit on a couple of postit notes. Me and two other engineers bashed it out in a 1-2 hour meeting at the start of the project (odd number of people to vote on anything). It came down to the fact he came in after the fact and had no say in it. Then proceeded to change everything. One week it was tabs everywhere then spaces then tabs again. One day camel case, week later all lower, another partial hungarian, upper on random things, etc. Waste of time.

oytis

To me "craft" is about keeping code efficient, scalable, extensible, well-tested and documented. Code style is more about what naming convention to use, tabs vs spaces etc. - it's nice to have it consistent, but no need to spend more than 5 minutes arguing about it.

ctxc

Tabs/spaces is a non-issue, agreed - IDEs handle it.

But surely naming convention contributes to keeping code documented, extensible and efficient?

A deviation from the norm leads to people thinking x does not exist in a large code base, leading to them implementing duplicate methods/functionality, leading to one instance evolving differently enough to cause subtle bugs but not enough to be distinct, or leading to one instance getting fixes the other does not etc?

Sample size of 1, but I've seen it happen unfortunately.

hkwerf

There is more than one type of people who stress over code style. There's the group who wants to discuss about how to style your code and then there's the group who wants to just use a common code formatter and be done with that.

For example, I have objections to rustfmt's default style. I would never start discussions on rust projects about changing that to another formatter or changing its configuration. I definitely would carefully ask that people should really use rustfmt, though, if they don't do so yet.

xnorswap

Edit: This comment was based on misreading the parent comment. I've left it up, but I should have been more careful.

You've set yourself up to always be the outlier. To always need to have that discussion or tweak the rules on every project you work with.

You've increased the overhead of onboarding anyone used to the default style. You've increased the overhead of you working on anyone else's projects that is more likely to have the default style.

All of that is friction introduced because you haven't learned to live with the default style.

Do I love that the default C# rules put a new line before the else block? No, but I've learned to live with it so that I can work on all manner of projects without fussing over that style option every time.

By adhering to default rules, you never have to have the endless arguments such as tabs vs spaces again. ( Spaces won, and the tabbers got over it fairly quickly once it was the default in almost all formatters. )

latexr

What I understood from your parent comment was the exact opposite, i.e. that they’re saying “I disagree with some of the default choices of the formatter (and so would prefer they were different) but I never voice those because it’s not worth it. However, I do think everyone should use something, whatever it is (even if the default style), as opposed to nothing”.

hkwerf

I believe you may have misunderstood my comment, as I agree.

dtquad

>Frontend development is a nightmare world of Kafkaesque awfulness I no longer enjoy

As a backend/systems engineer I recently had to look at a React + Typescript + MobX app from 2019/2020. It is true that that some things, especially the webpack config and Typescript loading, were outdated but the overall design and architecture of the app was still understandable and modern. With some help from ChatGPT it took very little time to migrate to Vite and update dependencies. By 2019/2020 React Hooks had already been out for some time but there were still some class components in the app. They were easily migrated to functional components + Hooks using ChatGPT.

kovacs

it's the best comment in the entire post IMHO and made me LOL

ZaoLahma

> Most programming should be done long before a single line of code is written

Nah.

I (16+ years developer) prefer to iteratively go between coding and designing. It happens way too often that when you're coding, you stumble across something that makes you go "oh f me, that would NEVER work", which forces you to approach a problem entirely differently.

Quite often you also have eureka moments with better solutions that just would not have happened unless you had code in front of you, which again makes you approach the problem entirely differently.

VyseofArcadia

Iterative work is THE way to work in large legacy codebases. The minute you wade into the code, all of your planning is moot. You don't know what's lurking below the surface. No one knows what's lurking under the surface. Except maybe Dave, because he vaguely remembers about 15 years back talking to some guy who wrote some code 30 years back about it.

Greenfield, absolutely design up front you lucky devils, but iterative is the way otherwise.

renewedrebecca

Every development shop has a Dave.

Kichererbsen

Most programming is actually figuring out what already exists and what (and more importantly: why) the requirements are. This is best done long before a single line of code is written.

I think the author is taking a wider view of "programming" than the actual writing of code as the end product. Some of the most important work I've done is spend the time to argue that something doesn't need to be done at all.

AnimalMuppet

Always think bigger picture than what you're immediately working on. (I don't mean that you can't ever just focus on the problem you're trying to solve for, say, hours. I mean you can't focus like that for the entire time you're in that development phase.)

Think about design and code (and functionality!) before you start coding. Think about design as well as code while you're coding. Think about design, code, and functionality while you're testing.

gmm1990

I assume there are people who are able to have those eureka moments before writing any code. I definitely write a lot of code before figuring out the final design but always think I should be designing more.

gaptoothclan

ok that sounds bad, you should have the option to go back to design, but depending on what point you find that issue, depends on how much time you have wasted?

ZaoLahma

It's about defining and solving small problems all the way, and avoiding trying to solve big problems.

If you manage to restrict yourself to only solving small problems (THIS is the true challenge with software engineering, in my humble opinion), then you won't ever have wasted too much time if (when) you need to reset.

naasking

> You literally cannot add too many comments to test code (I challenge anyone to try)

I think it is possible, depending how you write them. If you write long comments interspersed with the code, you have a lot of scrolling to do follow the control-flow. Long block comments should go at the top to "set the stage", and then lightly interspersed comments throughout to remind of the specific steps, where necessary.

> Very few abstractions exist in general application development. Just write the code you need

I think they exist, but they're either not well known or are hard to engineer because of missing context; good abstractions are just hard. Solve the immediate problem and you'll maybe, eventually converge on the abstraction and you'll have your "aha!" moment.

lmm

Hard to have any kind of productive discussion when it's just a set of claims without rationales. I agree with some and disagree with some (RDBMSes are overrated and solve the wrong problem; ORMs are a useful tool and bypassing the ORM because you want to use your l33t SQL skillz is the devil; programming should be done by writing lots of code from the earliest stage on (and throwing most of it away)).

donatj

> Most programming should be done long before a single line of code is written

This is the only point I strongly disagree with. I have been doing this for twenty years now and every time we've gone into something with a STRONG plan for how it's going to work, it's ended up an inflexible nightmare when we inevitably end up having to work around things that were not considered in the design phase.

The plan almost always ends up in the way of the realities.

You can spend months planning the smallest feature and there will always be something you did not consider.

Rapid prototyping in my experience is the way. Throw something together that works, see how it can be improved, don't be afraid to throw the entire thing out.

Kototama

> Typed languages are essential on teams with mixed experience levels

I like this one because it puts this endless dilemma in a human context. Most discussions are technical (static typing ease refactoring and safety, dynamic typing is easier to learn and better for interactive programming etc.) and ignore the users, the programmers.

wesselbindt

I'm kind of wondering where the "mixed experience levels" part comes from. What is it about more homogeneously skilled teams that makes them less susceptible to the productivity boost that statically typed languages give in large code bases?

Cthulhu_

I'm reading in it that experienced developers (be it overall or in a specific codebase) "know" all the ins and outs, types, conventions etc, whereas less experienced people cannot yet know all of that; being able to lean on good types and / or other types of automated checks helps them make more confident changes.

flir

UX really is everywhere, once your eyes are opened to it.

cies

I think the size of the code base also matters: bigger size = having types is more important.

There is a contradiction here as: bigger size = compile speed more important AND types slow down compilation. More advanced typing features slow down compilation even more.

pjc50

> More advanced typing features slow down compilation even more.

C++ is a bit of an outlier here. But really people should think of typechecking as shifting fault detection earlier in the process than runtime. It doesn't matter if your test suite starts slightly quicker if you have to wait for the whole thing to run to find something you could otherwise have found with types.

cies

I agree. But the nice thing about types is that they are not an afterthought, but more a "pre thought". TDD tries to make testing a pre thought...

Kenji

[dead]

andyish

> People who stress over code style, lining

You can do it whatever way you want but match the style of the project. I've worked on too many projects where someone decides their way is best and you end up with a mix of everything.

If you want to change the code style, okay, but change it everywhere and don't forget to test everything you've changed.

> Frontend development is a nightmare

But is it weird I kind of enjoy it every so often/

> Elegance is not a real metric

You're dam right it's not! Next time someone proudly presents a super elegant, refined, and minimalistic solution I'm going to phone them at 3am on a Saturday and get them to debug it while screaming at them about lost revenue or something.

> DynamoDB is the worst possible choice for general application development

Oh man, the amount of times I've seen some form of noSql and it's used as a relational database. 9/10 some rendition of SQL is more than sufficient.

Cthulhu_

Code style is one thing - formatting that is - but there's others like how features are implemented tend to change over time and with different developers as well, which is difficult to automatically test and hard to keep in line except with good code reviews, but for that to work you already need to install a culture of consistency, which also means that innovation may be stifled and developers demotivated (e.g. because the better solution requires the 100 existing solutions to be rewritten, which is too expensive or requires a whole team to be blocked until it's done).

Consistency trumps a lot of things IMO, but not everyone is on board with that... myself included, I'm guilty of breaking with my own consistency all the time.

Twirrim

I've grown to be a big fan of opinionated linters like gofmt, rustfmt, black etc. They avoid so much time spent disagreeing about code formatting and personal preferences. Instead engineers can do mutual grumbling sessions about weird formatting choices they see it do, and move on.

Terr_

> Java is a great language because it's boring [...] Types are assertions we make about the world

This is less of a mind-was-changed case and more just controversial, but... Checked Exceptions were a fundamentally good idea. They just needed some syntactic sugar to help redirect certain developers into less self-destructive ways of procrastinating on proper error handling.

In brief for non-Java folks: Checked Exceptions are a subset of all Exceptions. To throw them, they must be part of the function's type signature. To call that function, the caller code must make some kind of decision about what to do when that Checked Exception arrives. [0] It's basically another return type for the method, married with the conventions and flow-control features of Exceptions.

[0] Ex: Let it bubble up unimpeded, adding it to your own function signature; catch it and wrap it in your own exception with a type more appropriate to the layer of abstraction; catch it and log it; catch it and ignore it... Alas, many caught it and wrapped it in a generic RuntimeException.

pjc50

It was botched from the start because there's so many opportunities for unchecked exceptions as well. Without a more sophisticated type system that represented nullability, you can get NullPointerException anywhere. Divide by zero. And so on.

You also have a problem similar to "monads and logging": if you want to log from anywhere in your program, your logging function needs to be exception-tight and deal with all the possible problems such as running out of disk space, otherwise you have to add those everywhere.

jeroenhd

Unchecked exceptions are just Java's weird way of what languages call panicking these days. They suck, but as long as you don't throw them yourself and catch them in a logical place (i.e. at request level so your web server doesn't die, at queue level so your data processing management doesn't lock up, etc.) you can usually pretty much ignore them.

The worst part about them is that for some reason even standard library methods will throw them. Like when you try `list.Add(1)` on a list without checking if said list is read-only. The overhead of having to read every single bit of documentation in the standard library just to be ahead of panicking standard methods is infuriating.

That's got nothing to do with the concept of checked/unchecked exceptions, though, that's just Java's mediocre standard library.

pjmlp

I agree, although I would like to point out Java usually gets the blame for what was actually an idea being done in CLU, Mesa, Modula-3 and C++, before Oak came to be and turned into Java.

Additionally, the way result types work, isn't much different, from type system theory point of view.

I really miss them in .NET projects, because no one reads method documentation, or bothers to have catch all clauses, and then little fellow crashes in production.

baq

> adding it to your own function signature

This is precisely why they are so bad: checked exceptions must not be allowed to be used outside the package (or jar, or whatever, just limit it) otherwise they cause non-local build failures in all dependencies. They're fine if you are developing the artifact that's going to be deployed.

The_Colonel

> They just needed some syntactic sugar to help redirect certain developers into less self-destructive ways of procrastinating on proper error handling.

Syntactic sugar it needs is an easy way (like ! prefix) to turn it to a runtime exception.

Procrastinating on exceptions is usually the correct thing to do in your typical business application - crash the current business transaction, log the error, return error response. Not much else to do.

Instead the applications are now littered with layers of try-catch-rethrow (optionally with redundant logging and wrapping into other useless exceptions) which add no benefit.

jeroenhd

The try/catch/rethrow model can easily be substituted by just adding a `throws` to the method. If you truly don't care, just make your method `throws Exception` or even `throws Throwable` and let the automatic bubbling take care of making you handle exceptions at top level.

girvo

Checked exceptions as an idea are great (Nim’s usage of something similar is excellent) but yeah Javas particular implementation was annoying and easy to avoid, so most did.

Cthulhu_

I mean on paper they're a good idea and well implemented etc. However, the main two flaws with exceptions are that one, most exceptions are not exceptional situations, and two, exceptions are too expensive for dealing with issues that aren't exceptional like that.

flir

> Alas, many caught it and wrapped it in a generic RuntimeException.

Actually sounded great right up until this point. Deal with it, or explicitly acknowledge that you do not. It's honest.

Apparently other developers are why we can't have nice things.

mrkeen

It's already very unlikely that you can 'recover-and-proceed' in the context of any business app exception (Security violation, customer not found, no such payment, etc.).

So what's left in exception handling is logging and/or rethrowing. And the 'nasty hackish way' of doing it (RuntimeException) already passes a complete stack trace up to the caller.

kaapipo

Nah, I think having a monadic Maybe/Option type and first-class support for it is the correct solution. Exceptions are fundamentally flawed.

rixed

"None" to represent any type of failure sounds similarly fundamentally flawed too.

lmm

That's why you need not just an Either/Result type, but proper monads so that you can use the same functions with both.

pgsandstrom

> Most programming should be done long before a single line of code is written

I'd rephrase this to something like: Most programming should be done before 5% of the code is written. Because "no plan survives contact with the enemy". I often develop a plan, work for just a tiny bit, and realize some new constraints. It's after that point that you should construct your grand battle plan.

latexr

From “The Cathedral and the Bazaar”:

> # 3 “Plan to throw one away; you will, anyhow.” (Fred Brooks, “The Mythical Man-Month”, Chapter 11)

> Or, to put it another way, you often don’t really understand the problem until after the first time you implement a solution. The second time, maybe you know enough to do it right. So if you want to get it right, be ready to start over at least once.

https://en.m.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar

The_Colonel

I've made an opposite progression from the op. I was a strong believer of upfront design, but now value iterative approach as you do.

For the first try, hack together something working, you'll learn things along the way, validate/disprove your assumptions. Iterating on this will often bring you to a good solution. Sometimes you find out that your current approach is untenable, go back to the whiteboard and figure out something different.

v3ss0n

Its wrong in those day , exploratory coding is better for dynamic languges like python using jupyter notebook , and then do proper coding after exploratory step..

imjonse

> ORMs are the devil in all languages and all implementations. Just write the damn SQL

It depends on what you're writing. I've seen enough projects writing raw SQL because of aversion to ORMs being bogged down in reinventing a lot of what ORMs offer. Like with other choices it is too often a premature optimization (for perf or DX) and a sign of prioritizing a sense of craftsmanship at the expense of the deliverables and the sanity of other team members.

qaq

It's not so much optimization but experience that on any sufficiently large project you gonna run into ORM limitation and end up with mix of ORM and direct queries. So might as well...

The_Colonel

Starting with raw SQL is fun. But at some point you find out you need some caching here, then there, then you have a bunch of custom disconnected caches having bugs with invalidation. Then you need lazy loading and fetch graphs. Step by step you'll build your own (shitty) ORM.

Same thing for people claiming they don't need any frameworks.

wesselbindt

> you find out you need some caching here, then there

Forgive my ignorance, but how do ORMs help with adding caching? Or are you implying they obviate or reduce the need for caching?

Twirrim

One job I had, we got handed a code base with at least 4 different reinventions of an ORM in it.

It became clear that each developer who'd worked on the code had written their own helpers to avoid direct SQL. It took a fair bit of persuading leadership, but the first task ended up being doing a huge reactor of everything SQL. Unsurprisingly enough, lots of bugs got squashed that way.

magicmicah85

It’s the devil I know and for most of my projects I’ll likely never forsake ORM for raw SQL.

hitchstory

Depends upon the ORM. Like all frameworks, a really good one is a significant productivity boost while a bad one is faworse than none at all.

GuB-42

Just personal opinions, I guess, I agree with most, but here are some I disagree with:

- There is no pride in managing or understanding complexity

Complexity exists, you can't make it go away, managing it and understanding it is the only thing you can do. Simple systems only displace complexity.

- Java is a great language because it's boring

That is if you write Java the boring way. A lot of Java code (looking at you Spring) is everything but boring, and it is not fun either.

- Most programming should be done long before a single line of code is written

I went the opposite extreme. That is, if you are not writing code, you are not programming. If you are not writing code on your first day your are wasting time. It is a personal opinion, but the idea is that without doing something concrete, i.e. writing code, it is too easy to lose track of the reality, the reality being that in the end, you will have a program that runs on a machine. It doesn't mean you will have to keep that code.

- Formal modeling and analysis is an essential skill set

Maybe that explains our difference with regard to the last point. Given the opportunity, I prefer try stuff rather than formalize. It is not that formal modeling is useless, it is just less essential to me than experimentation. To quote Don Knuth out of context: "Beware of bugs in the above code; I have only proved it correct, not tried it." ;)

- You literally cannot add too many comments to test code (I challenge anyone to try)

time++; // increment time

snapcaster

I agree with you, i'm much more on the "try stuff out" scale vs. formal methods. That being said, i've worked with people who are the other way and still very effective. I think this one is more of a trade-off or personality thing than something that's "true" or "false"