Live data from Hacker News

The Stupid Programmer Manifesto

hasen.substack.com

201–210 of 239 posts

Re: The Stupid Programmer Manifesto

#201

Earlier quoted context omitted.

Yeah, I read this post as a dig at "cargo cult" programmers who read up on google-scale programming and best practice and unthinkingly apply those constructs to their own Bob's-Restaurant-scale task at hand where they are often at best an unneeded time and complexity overhead.

I've worked in a number of projects where they decided to move to microservices for reasons they wish they had, while not fully understanding microservices or applying basic litmus tests to where to split off services. So we ended up with great puzzles like how to link an order service with an inventory service to check if there's enough inventory to fulfill an order, all through a central event bus. Then of course t…

Unfortunately it's not a popular belief anymore, but [asynchronous] central event bus is a terrible idea on it's own, and it goes against what [micro]services are about.

If you want microservices to work you shouldn't have anything central in them, and you should avoid async as much as possible.

Re: The Stupid Programmer Manifesto

#203

For someone who's "too stupid" to understand these techs, they certainly can explain them and their drawbacks and alternatives well. This reminds me of a bit of advice from Austin Kleon that I've used frequently -- "Make bad art, too"[^1]: > “Good” can be a stifling word, a word that makes you hesitate and stare at a blank page and second-guess yourself and throw stuff in the trash. What’s important is to get your ha…

For a side project I used some PHP to get a job done. Why? because you can edit the file on the server and keep trying it out till it works. On 90s style hosting that is cheap and honest. The iteration speed is amazing. CI/CD took <100ms.

When I wrote PHP on the server I had real problems with the "CI" part- I would refresh my page an manually test each change. Do you have Continuous Integration tests (i.e. automated) for this code or are you also doing the manual refresh cycle?

No shame either way, I think the juice isn't worth the squeeze for automatic testing short-lived code myself

Re: The Stupid Programmer Manifesto

#204

Earlier quoted context omitted.

> So this anti-pattern assumes that users are using some memorable password like their mother's maiden name, probably for all the services they use. Anyone using sane password practices is penalized with stupid friction. I think you're really, really underestimating how easy it is to make a typo when entering a password into a masked password box, hence the 2 fields. Also, web-browsers don't let you copy-and-paste th…

> Also, web-browsers don't let you copy-and-paste the password from one box into another Point taken; perhaps simply having that widget that lets you see the password unmasked would be better, than forcing you to enter it blind twice (and getting it wrong twice). Fact is I don't try to copy/paste one field into the other; I paste the same stuff into both. FWIW I'm a normal person. I don't know what OIDC is, and I've…

> I don't know what OIDC is

It was a very, very painful learning experience.

Re: The Stupid Programmer Manifesto

#205
post #176

Earlier quoted context omitted.

You're citing an exception as if it was the rule. But even in this case, I don't have two representations of the same object. Rather I have two different object: Account (persisted) SignupRequest (not persisted) The SignupRequest is used to create the Account The signup form on the UI is about editing the SignupRequest object. This object will be sent from the UI code to the backend as-is. The backend code will use i…

In this case SignupRequest is your contract representation, Account is your storage representation, and the "backend code path" is the transformer/napping layer. >I don't have two representations of the same object. Rather I have two different object Exactly! Your api contract and your storage are ALWAYS two different objects, because they serve two different concerns. Sometimes by coincidence they can share the same…

> Also, mapping/transformation logic can often just be simple, pure, total functions

I find this is never the case - usually for the exact reason you inadvertently sold as some kind of "benefit": "it's reserving the right to change two pieces of data independently" - because when you need to map from, say `SignupRequest` to an `SavedAccount` object you'll encounter data-members required by `SavedAccount` which cannot be sourced from the `SignupRequest` object - for example, supposing the UX people come to us and say we need to split-up the registration form into 2 pages, such that most fields are still on page 1, but the password boxes are on page 2. Now you need to deal with how to safely persist data from page 1 for use in page 2 (so using hidden HTML inputs between pages won't work because that requires POST requests to work, but both pages should be able to be intiially-requested with a GET request.

Re: The Stupid Programmer Manifesto

#206

Earlier quoted context omitted.

I'm convinced the difference between the "10X" dev and the 0.5X dev isn't intelligence, it is rather the strength of the "rabbit hole detector". The 0.5X dev jumps right in, never to be seen again.

OT ramble: I met a -0.5x dev once. .NET dude, lots of experience. Standup, every day, was something gone awry with dependency injection. Every. Single. Day.

> standup

The one of you who came up with that idea was the true -0.5x engineer.

Re: The Stupid Programmer Manifesto

#207
post #132
post #101

Earlier quoted context omitted.

That's a particularly weird one in light of starting out with "I only use statically typed languages", because it's basically trivial in a statically typed language. You have "type UIData", "type StorageData", and functions/methods to convert back and forth between them. Those functions/methods may need additional parameters, which will be documented by the mere act of calling for them in the function signature. You…

But, _what_ is the point of using a different layout/structure for storage vs the UI layer? Remember I'm a 0.5x developer. If I have to write code to transform data for every kind of entity/object I need to store and have a UI to view and edit, that's way too much. I'm already very slow. No need to slow me down further by telling me I have to write so much extra code that does no useful work.

I think of it this way, actually: I have a different structure for every major use in my system. A fairly general variant is having a structure for input, a structure for my internal operations, and a structure for output, but I use that just as an example. Each of them can be used as I outlined above, with methods to transform between them as needed.

This is necessary because each of those things represent completely different needs, because they operate in different domains. In particular, the guarantees are different; the input must effectively be treated as having no guarantees, and you must check them all. Your internal operation may add additional guarantees it provides, things you don't need to check anymore because the mere act of being passed a value of a particular type means that the code can rely on this particular thing being true, thus saving me a ton of code everywhere. For the output, you don't care at all about any guarantees but you need to conform to what the external world needs.

In general, trying to cover all these bases with one structure is a bad idea which leads to pain. I've seen it many times, where developers try to overload one structure to do too many things.

In specific... it so happens that 95%+ of the time, covering all the needs with one structure works out fine. But I conceptualize this differently than you. I do not say to myself "It's OK, one structure is all I even need because anything else would be overcomplication." I say "It so happen here that the structures are so similar that I can conveniently elide them down to one without significant loss. I can do this because I have examined all the needs and guarantees and verified that they do not conflict."

But the difference is, as soon as they do conflict, as the codebase changes over time, I split them, leaning on the compiler to guide me through the process, because I know from experience it is not particularly hard. When you need to do this, it is easier to just do the split of types than to try to make one type straddle the gap. (Besides, once you have one type straddling one gap, the odds are by the time you're done it's going to be straddling more than one gap. This tends to happen precisely to those most central types.)

I bet you have at least one type somewhere that is suffering from trying to straddle too many use cases. But I would also bet you don't actually have many such types. It turns out that the majority of the time the elision is safe. But I think it is a useful perspective to still mentally model that as an elision and having separate types as the underlying model. I think the way you are advocating for thinking of it works fine the 95% of the time our models agree, but in that other 5%, someone following my system is going to be a lot happier than someone following yours.

I do a lot of relatively small programming, projects in the single person-year range. I do a lot of this sort of elision, because bringing the full power of generalized architecture to such projects can cost you a lot more than it gains. But I also do this sort of modelling in my head a lot, too, and when I notice a particular elision is starting to cost me something, I will on-demand unelide some particular architectural elaboration on the spot. In fact I am taking a break from this exact process to type this post, as I need to replace an increasingly complicated hard-coded structure of decorator-based plugins for a fully configuration-based model of arbitrary combinations. For any given such re-elaboration, it is perhaps more expensive to do than if I had started with that architectural feature in the first place, but across the full space of possible architectural features I win big versus starting with an architecture that is too heavy weight in many ways that I will ultimately never need in this particular project.

Re: The Stupid Programmer Manifesto

#208

Earlier quoted context omitted.

I've worked in a number of projects where they decided to move to microservices for reasons they wish they had, while not fully understanding microservices or applying basic litmus tests to where to split off services. So we ended up with great puzzles like how to link an order service with an inventory service to check if there's enough inventory to fulfill an order, all through a central event bus. Then of course t…

> I've worked in a number of projects where they decided to move to microservices for reasons they wish they had I've advised engineers to rewrite code before, mostly for resume building to help jumping ship to somewhere better. Basically, use the current job as a way to train on the stack the company you really want to work for is using. If a company doesn't have a stock-based comp and sticks to prevailing wages/CoL…

It's unprofessional to do this in conflict with your company's interests. Use your own hobby projects to learn instead of leaving a maintenance project for your coworkers.

It also creates an invisible bias towards worse companies in your next position, because smart companies are wary about this kind of behavior, and will be savvy to filter out candidates that have displayed it.

Re: The Stupid Programmer Manifesto

#209

Earlier quoted context omitted.

OP makes the same mistake that those chaps who use Kubernetes to run an app with 10 lines of code: thinking that there is one right solution for every kind of problem. OP's approach might work for a personal project or a small company, but when you need to work in a large and complex system you start to appreciate the beauty of tools like Docker. It's cool to question cargo cult, but don't throw the baby with the bat…

I work at a very large company with very complicated systems. Fighting unnecessary complexity at every opportunity is the only way to keep things near comprehensible. A lot of the articles rules are even more important in complex environments.

Me too, and I wouldn't apply most of OP rules to my day job. They just aren't a good fit. Sometimes using the right tool (e.g. Docker) actually decreases the overall complexity of the system, even if it raises it locally.
Post reply on HN