Software development topics I've changed my mind on
chriskiehl.com
chriskiehl.com
> (…)
> 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”.
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.
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
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.
Making fuss about indentation in code file is not artisanal. It is insane weirdo if we are charitable and if not clueless and childish.
I care deeply about the end result that is presented to the user who has no idea what code even looks like. How we put together the UI. How we load data to minimize delays. That's "the craft" to me.
I care much less about code style, linting etc. that no-one other than a small group of developers will ever see. To a certain extent the latter enables the former. But I've often witnessed the latter being valued over the former and that's where things start to go wrong.
I have seen so many people going on and on about best practices and coding styles and whatnot and using big words just in hopes to keep discussions going so no one figures out out that they don't know how to code.
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.
Every language has automatic formatters. Use them, configure them if you don't like the default (in accordance with your team), and configure your editor so that is applied automatically when you save. And use CI to detect PRs with bad formatting so devs who don't have configured their editor yet can't break it.
Same with linters, you still have to agree with your co-workers about which rules make sense to be enforced, but with good editor integration you can see it right away and fix it as you code.
No. The two aspects (let's call them the craft and the minutiae) are orthogonal, they're not different level of caring about the same thing. I've seen people obsessed over minutiae and writing buggy, careless and unmaintainable code.
As with other formal aspects (e.g., testing) the quality of the code and the level of adherence to convention or forms are independent of each other; but they do both consume the same limited resource, which is the time and attention of developers.
It’s kind of like what Bruce Lee said about punches. Before you know how to code, styling is just styling. When you become proficient in coding, styling is more than just styling. But when you’ve mastered coding, styling is just styling again. Be like water my friend.
The linter people are hypercorrectionalists of the type that would change “to boldly go where no man has gone before!” because it’s a split infinitive.
Yup. Doesn't matter.
Code style should be consistent and look nice, probably use the default without too much nitpicking. You have bigger fish to fry
There are better things in life to worry about
"Craft", most code goes to irrelevancy in 5 yrs. And if it doesn't it's fixable (amen for AIs)
Try to sweat up every detail right off the bat and you go nowhere
Theses are bullet points expressing general rules of thumb, not legal treatises. You're reading far too much into these.
And I couldn't care less about where you put the {}. I love autoformatters.
Linting is a little more. It's both style and genuine issues, like don't == instead of === in JavaScript.
At least with Python I just push everyone to follow PEP-8 makes it easier.
This may point to the dividing line. Software is required to be functional, not simply "artistic". You can certainly make the argument that there are non-functional considerations in its construction: readability, maintainability, extensibility, etc. And, these absolutely intersect with style, so it's tempting to apply words like "artistry".
But, is there a point where details veer into personal preference and insistence on style for the sake of style? I think so, and many of us have seen this. For those who haven't yet, stick around!
It’s like obsessing over the font on the packaging of the marker you use to write to the whiteboard in a math seminar.
Now, weird is beautiful but it’s not usefull and mostly irritating in a professinal context.
Cherish your weirdness and celebrate when you can find people of same persuasion. But don’t bother your colleagues with it.
I’m saying this as a person with very deep weird personal interests as several here do - and I’ve learned this slowly and painfully.
I cannot put it into words right, but you can see there’s usually a vibe. It will be different coming from an experienced developer knowing what they are talking about from lived experience, and from a clueless one who has seen shit but is hell bent on process and rules.
Abhored obstructionists and covert saboteurs are also the ones that care for the details.
You need to care about right kind of details. Any specific linting is not that kind. Linting at all is.
Artisan without a proper sense could spend weeks exquisitely decorating a spoon with gaping hole in the middle. State of nearly all software is more or less horrible. Choosing the right linting rules is most often than not putting lipstick on a pig.
On your own projects, choose a style, go with it. On someone else's project, go with the style chosen. On a shared project, come up with a style, go with it.
Code _organization_ matters way more than code _style_. Where style refers only to the aesthetic choices that don't impact the structure or flow.
Until you open a file that has 10 different coding styles from 5 different developers. Just the variations of variable naming schemes alone in individual code files that I see/edit, would drive anyone crazy.
At the end of the day, we aren't paid to produce code, but working software that works today and is easy to change tomorrow.
Yes, you need to care about this. But for the most part you should just follow the conventions of the language/framework, and not reinvent the wheel. Instead, you should put cycles into crafting architectures and algorithms.
Sure, have a style and a linter. Be DRY. Don't lose your head over it though.
You have to read between the lines to pick that up though, so your criticism seems valid.
I can also understand the fuss better in indentation-is-structure languages like python.
> What you call “stressing over minutiae” others might call “caring for the craft”.
So what? The presence of disagreement is not an argument in favor of relativism and subjectivism. People can be wrong, and they can be wrong about what is valuable. Value is not subjective. The fact-value dichotomy is false.
That's the general principle. As far as this particular example is concerned, the author didn't say things like code style and linting rules have absolutely no value. They have some value. The question is how much, especially in the grand scheme of things, and whether one's concerns, attention, and efforts are proportioned to the objective value of such things. That's how this question should be framed. The author's position, charitably read, is that it is objectively irrational to obsess over such things.
If you wish to rebut, then go ahead and provide an argument, but don't retreat into the bollocks of subjectivism.
Folks who care about the craft obsess (well within realm of being realistic) more about architecture, good use of design patterns, using good modern toolset (but not bleeding edge), not building monolithic spaghetti monster that can't evolve much further, avoiding quick hacks that end up being hard to remove and work with over time and so on.
If you don't see a difference between those groups, I don't think you understood author's points.
Well yea, but which detail you care about still matters and reveals a lot about your "craft". Code style is of such little consequence compared to semantics it's always a little eyebrow-raising to see people who are extremely opinionated about it.
I've also noticed that this sort of thing can sort of fade into the background after a couple decades of coding. I know people who go on and on about how "beautiful" code is—to me it's just syntax serving a purpose. Sometimes you can make really elegant code that works well with the language, sometimes you can't. But how the code is presented impacts my reading comprehension very little unless you're doing something very strange (looking at you, early 90s c code with one-letter variable names and heavy macro usage).
Actually, I recant one element of this—Javascript and Typescript are just straight ugly and hard to read.
Someone's style can be "different" without being "bad", and you have two basic options to deal with it. One is to authoritatively remove the soul via process (auto-formatters, code review, and to a lesser degree linters, etc. are all designed to create uniformity at the cost of individuality.) The other is to suck it up and deal with it, as this is just an inevitability of creating a team size larger than one: people have different tastes and those have to be reconciled. I somewhat prefer allowing for individuality, and individuals should endeavor to match the style of whatever module they're working in, out of courtesy to its owners/stakeholders if nothing else. However I have only worked independently or on small teams. Most large teams (/ open source projects) have gone the former route of automating all the fun/craftsmanship out of their systems, and even I think that makes sense at a certain scale.
Someone's style can just be objectively "bad", however, and I usually find it's evidence they just don't care about the source artifact that much, and they're focused on the results. (It can also be a sign of an under-performer that spends so much mental capacity just getting the code to work that they have no spare cycles to spend thinking about matters of taste.) If it compiles / works / passes the test-suite that's "good enough" and "their job is done" and they move on to the next task. These people tend to be hyper-literal thinkers that are very micro-task oriented: they see implementing a new feature as a checklist to be conquered, rather than being systems-level thinkers on a journey of discovery & understanding.
If the author is talking about the latter, I have to agree with you that the latter are quite difficult for me to work with; particularly since I know that the source has to be maintained & supported over a much larger time-scale. The source-code is like your house, you live in it, being comfortable to work with/in/on it is the key to success. The deployed artifact may live for only a few weeks, days, or even hours before it gets replaced. The source has evolved over decades. You (the organization) are practically married to it. To further the analogy: I don't mind if somebody wants to hang posters in their room for a band I don't like. (Hell I can even handle if a group of those posters are tastefully hung out-of-level to make some kind of statement.) I do mind if their furniture is blocking a vent, the outlet covers are hanging off, there's a hole in one of the walls, a light has been burnt out for months, and the window-blinds over there are clearly broken but they insist it's fine because daylight still gets through.
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.
Greenfield, absolutely design up front you lucky devils, but iterative is the way otherwise.
I have an extra ten years on you and couldn't agree more.
There are two jokes:
- A few months of programming can save weeks of design.
- A few months of design can save weeks of programming.
Inexperience is thinking that only one of these jokes is grounded in truth.
Recognizing which kind of situation you're in is an imperfect art, and incremental work that interleaves design with implementation is a hedge against being wrong.
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.
Your first draft may be qualitatively an MVP, but it's still just a theory of a final product you want, which requires a lot of iterative building before you get to that.
As such, there's no way to not shift between code and design, especially when business requirements are involved and which themselves may change over time.
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.
Something I do a lot, and even more with the LLMS, is that I make `scratch` projects where I sketch code over and over (and maybe make mockups in Keynote or similar, make some notes, etc), then write from scratch again in the real codebase.
He might have meant design, and I'm not sure about that.
But the other thing i think of is: Understanding the problem.
It's hard to do too much of that before you start coding, and easy to do too little.
It overlaps with design to some extent, because once you understand the problem better, some designs will naturally seem inappropriate or better -- without having to spend time allocated to "designing" necessarily, just when you design you're going to come up with things that work a lot better the better you understand the problem you are trying to solve.
How the stakeholders see it, and what's really going on, and why it's a problem, and what would make an acceptable solution, and what the next steps down the road might be.
The statement sounds like something out of a book on the waterfall method of software development.
But it basically sounds like waterfall development, which is a reasonable approach in certain contexts.
But this thinking doesn't really make sense for any of the projects I work on.
You should spend time thinking about stuff beforehand, sure, but getting your hands dirty is also going to reveal things.
- 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
> 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.
I interpreted that one as a suggestion to avoid welcoming needless complexity because of the false sense of pride it gives you to successfully manage that complexity.
To give an example, I believe C++'s enduring popularity is mostly because of exactly this false sense of pride. You practically need a doctorate-level understanding of the language to use most of its features without stepping on the dozen landmines the language places in your way (I'm so smart because I: remembered to declare my destructors virtual and understand why; can interpret this 2MB of template errors in the compiler output; can """cleverly""" use operator overloads). It can feel nice to be a master of such a complex tool, but that's a false sense of pride. The complexity of your tooling is not the point; the end product is.
This isn't too many comments, it's a poor quality comment. Try:
time++; // advance 1 simulated second
My thoughts, exactly. And considering that so much unnecessary complexity keeps being added to software (through poor understanding of requirements, technical debt, etc), it's an extremely valuable skill.
Software development looks super different when the org is a startup vs when the market fit is established.
When you are a pre-PMF, you have to establish trust. You deliver fast, cut corners, make sure customer needs are met, value is generated. Nothing else matters.
When PMF is established. You have to de-risk everything. All your work is at stake. Then best practices has to be in place to makes things scalable, code quality matters because it is a proxy for enforcing standards.
I don't think Software can be seen in isolation. It has to be seen from thr orgs perspective.
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.
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.
Some of these things are mildly annoying when you think about them in theoretical terms.
But all the professional teams I've been on a (a lot) have successfully dealt with exceptions without issue. The teams settled on an exception and error handling process early in the design phase and it rarely has caused a major issue.
Yet it seems out on the internet in any place where programming languages are discussed it is an insurmountable problem that has caused all projects in Java to fail and the language died an early and unpopular death. It seems if it caused anyone huge problems it was not Java's issue but that team's issue.
There are/were other much bigger issues over the years. Memory leaks have been issues. Spring was hard for many people to deal with back around 2005 or so. The first iterations were quite bad with XML. XML in general caused a lot of issues. J2EE caused a lot of issues just because it was so badly designed early on. (Some of this was because it was birthed out of CORBA, which was itself pretty horrible.) Plenty of issues were caused by using Collections with mixed objects in them early on before Generics were introduced. Visual J++ caused havoc. Different models of web application caused a lot of havoc before we got to Javascript UIs in the browser driven by Web API back ends. JPA was a big mistake IMO. But exceptions were never really a huge problem anywhere.
So many have blamed a problem on Java when it was actually a problem with a library, component, or framework written in Java that became way more popular than it should have been. And along the way there were a lot of "developer influencer celebrities" who were listened too far far more than they should have been. Many of these guys (I can't remember one ever being a woman) sold everyone on ultra complex designs and ways of doing things and the community almost always bought in to a ridiculous degree.
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.
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.
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.
This is not, of course, the only way that checked exceptions can be utilized. But, all too often, that is by far the easiest way to reason on them. They represent a decision that needs to be bubbled up to the operator of the overall system.
Worse, the easy way to explain how the system should resume, is to go back to where the exception happened and to restart with some change in place. Disk was full, continue, but write to a new location. That is, having the entire stack unrolled means you wind up wanting the entire process reentrant. But that is an actively hostile way to work for most workflows. Imagine if, on finding a road was closed, a cab driver took you back to pick up location to ask what you want to do about it.
If it is not something that you want to unwind the stack, or bubble up to the users, then you go through effort to wrap it so that it is another value that is being processed.
I work on an Inversion of Control system integration framework on top of a herd of business logic passing messages between systems. If I were to do all over again, then I’d have the business logic:
* return success or failure (invalid input)
* throw exception with expectation that it might work in the near future (timeout), with advice on how long to wait to retry, and how many retries before escalating
* throw exception with expectation that a person needs to check things out (authentication failure)
Unless the business logic catches it, unchecked exceptions are a failure. Discussion about what is what kind of exception is hard, but the business owners usually have strong opinions taking me off the hook.
I also find that generally exceptions can't be meaningfully caught until much higher in the call-stack. In which case, a lot of intermediary methods need to be annotated with a checked exception even though it's not something that matters to that particular method. For this reason, I've really come around on the Erlang way of doing things: throwing runtime exceptions in truly exceptional situations and designing top level code so that processes can simply fail then restart if necessary.
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.
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.
Now, with Vite I just don't mind the toolchain anymore, it just helps me instead of getting in the way. Similar to Go.
All the problems I have now are of my own creation.
I still think TS is annoying to work with but I'm coming around since I have to use it at work and libraries like React Native are using it by default. Swift/C++ has typing but yeah, I like plain JS for speed development and typing can get annoying especially for a personal app.
Up until roughly 4-5 years ago I was doing small front-end React apps on the side (I'm a backend engineer) and was feeling very productive with class components. They made sense to me, concerns were nicely separated, and I felt I could reason pretty well about what was called when and how state was manipulated.
Then hooks came around, I tried them a few times, but I just felt so lost. Suddenly everything is intermingled in one function and we're using side effects to react to changes and manipulate state. I could no longer understand when which code was executed, and especially following and manipulating state became impossible for me.
The projects I already, I kept with class components. Haven't done any new front-end projects since then.
> It's very hard to beat decades of RDBMS research and improvements
> Micro-services require justification (they've increasingly just become assumed)
That is so true. I am still deploying good old .war files to full blown Java app servers backed by simple SQL databases (all clustered and stuff) with some handwritten cli tools and a Jenkins server. Shit is fast, shit scales, shit just works. It is a pleasure to work with
This made me laugh it is so true. My last big project at "Big Co" ( Knee surgery robot ) My small group went through 4 project managers - just for our small team. The entire project had probably 20. While a few where enjoyable to work with, there was very little value added and a lot of time spent filling them in.
Whenever I've worked on a team where a developer is the team lead and has to do all that stuff on top of coding- or worse, it's just a free for all with no leader- , things in my experience go much worse, communication breaks down, and things slip through the cracks.
The rest? At best they were glorified QA/QC with a large stick to hit the engineers with when the spec wasn't met exactly. And when it was, and things still failed, they still hit the engineers with the large stick and were usually promoted for it.
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.
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.
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.
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.
I disagree with this. I’m a Clojure dev, and most of the time, I use the REPL to iterate on features, fix bugs, and refactor, thanks to the fast feedback loop.
I used to be a Java dev—oh god, restarting the whole app after every change made me want to shoot myself in the head. Now, I use the REPL to build what I want and then move on. This brings joy back to programming.
I’m not saying other languages are bad, but working with Clojure is more enjoyable for me. I’m at least 2-3 times faster than I was with Java. Of course, there are techniques you need to know to write efficient and idiomatic functional code.
If you want to argue the point with non lisp people, I'd go to javascript or SQL as great examples where you really use repl's quite a bit.
Supposedly there are some Java shells around but I haven't tried them out.
The standard runtime didn't like some redefinition. But there were alternatives. Eclipse, for example, would purposely let you get otherwise broken code running so that you could breakpoint and replace as you went.
https://www.graalvm.org/latest/reference-manual/espresso/hot...
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 be built, 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 always ends up bumping into unforeseen realities, and you end up with sunk cost around the planning so instead of pivoting you keep on suboptimal course.
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.
For backend web dev though, I can plan it all in advance. I have done it enough times that there are rarely any surprises and I know the pitfalls. I am really just limited by customers not knowing their own requirements.
I really love the iterative style but the problem is that I never worked in a company that allowed for enough time for large scale refactors. They might promise you that but it will never happen. You have to get it right the first time around or you will have to suffer until the system gets rewritten in a decade or two.
Of course plans can absolutely be too rigid but I generally found that more planning results in better products.
But if you are an expert in both of domain and the technology itself, you can well design it before starting the coding, because you already know the technical issues you are likely facing.
At least I have personally managed to design some projects and implement them without any design changes. But I also read countless blog posts about the limitations of these programming languages every day.
Of course there will always be something you didn't consider.
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.
> # 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
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.
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.
1. Mapping result rows back to objects, especially from joins where you will get back multiple rows per "object" that need to be collated.
2. Automatic handling of many-to-many relationships so you don't have to track which ids to add/remove from the join table yourself.
3. Identity mapping so if you query for the same object in different parts of your UI you always get the same underlying instance back.
4. Unit of work tracking so if you modify two properties of one object and one property of another the correct SQL is issued to only update those three particular columns.
5. Object change events so if you fetch a list of objects to display in the UI and some other part of your UI (or a background thread) add/updates/deletes an object, your list is automatically updated.
6. And finally in cases where your SQL is dynamic having a query builder is way cleaner than concatenating strings together.
For those who are against ORMs I am curious how you deal with these problems instead.
As far as I know this is a very oldschool view on how to treat dbs, but I still think this is the only correct one.
I hate ORMs with a passion - they're just a potential source of bugs and performance issues, coming from either bugs in the engine, devs not understanding SQL, devs misjudging what query will get generated, leaky abstractions etc.
It's big enough of an ask to understand SQL itself, it's the height of folly to think you can understand SQL when it's being generated by some Rube-Goldberg SQL generator, especially if said generator advertises that you don't need to know SQL to use it.
Statically-typed queries written in a mini-DSL within your application language seems like such a joy!
But then the configuration is a hassle. The DbContext lifecycles are a hassle. The DbContext winds up a big ball of mutable state that often gets passed all up and down your call stack, reducing the ability to reason about much of the code locally. Was this instance initialized with or without change tracking? How many and what changes have been applied? Were these navigation properties lazily or eagerly loaded?
And it promises to keep your domain persistence ignorant with its fluent configuration syntax. But then you have compromise on that here, then compromise in it there.
Pretty soon, you realize that you started out building a project for domain X or domain Y, only to realize that you're trying to shoehorn domain X/Y behavior into your Entity Framework app.
There's a saying - if you hate ORMs and don't use them, eventually you're going to write your own ORM.
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.
OO is not evil, but it also shouldn't be your default solution to everything.
Also, who is this person? I immediately distrust someone who calls themselves 'a pretty cool guy'. That's for the rest of us to decide.
Sure, if you disregard good object design, like the single responsibility principle and using mutability only when really needed.
I’m also more in the FP camp - even wrote a book on the topic of FP. But I also acknowledge OO is not inherently a bad choice for a project, and many languages nowadays do exist along a spectrum of OO and FP rather than being strictly one of the other.
To me a benefit for OO might be the ubiquity - you can generally assume people will understand an OO codebase if they have done a few years of coding. With more strict FP that is just not a given - even if people took a Haskell course in Uni a decade ago :).
With Smalltalk and Objective-C both being effectively dead at this point, that really only leaves Ruby (and arguably Erlang) as the only languages that are able to express OO. And neither of those languages are terribly popular either. Chances are it won't be your default solution, even if you want it to be.
This becomes easier when you've transitioned from someone who cares to someone who doesn't. Some of us burn out from the industry and fall out of love with the job.
I understand my curmudgeon-ly ex-colleagues a lot more nowadays.
Stop listening to functional programming bros. Watch someone like Zoran Horvat. While I can't cosign all of his opinions, he tries to bridge the functional/OOP gap for OOP programmers. OOP programmers urgently need to distance themselves from this binary narrative. Everyone should understand functional programming and how they can utilize functional approaches in every language or paradigm. For me it is a requirement of understanding software development.
Absolutely every institution teaches OOP practices, they also need to teach functional practices. These aren't sports teams.
It's a bit like how doing single-entry bookkeeping doesn't stop you from doing double-entry bookkeeping.
I don't think I've ever seen good management. Anyone care to explain what that would look like?
You don’t know it, but your manager playing up your teams contributions to the company, arranging happy coordination with other teams, occasionally intervening to resolve intra-team disputes, privately managing egos and careers, and jiu jitsu’ing any attempts to distract your team.
They trust your competence and decisions, but they understand enough to keep you on-track and provide a valuable outside view perspective.
1. For a non-manager, an indication that there is good management (project, process, etc.) in place is that the management aspect sort of seems to disappear/ moves into the background.
2. Communication becomes efficient or smooth.
How is it achieved?
1. High level goals and metric. And incremental upgrades to those. I think people/ teams need to get comfortable with one set of those before you want to improve better those metrics. Jira story points and velocity are not good metrics.
2. A manager acts as a buffer. A manager absorbs some shock and filters some data/ emotions which would otherwise flow between one (ideally more) pair of layers: one above them and one below them.
3. One kind of non-sense (from many kinds) is that people- junior or senior- are 'trying to prove their value'. This is why some people speak unnecessarily in meetings, emails go back and forth, senior management chimes in on low level issues, etc. A couple of good managers I saw were able to limit that- over a period of time.
A good manager is at the service of their team. That means they will do anything to keep the team productive. In most cases this means shielding them from corporate bullshit. In practice this also means that you will barely notice them.
So when you notice your management being intervening and bad, it's probably bad. When you barely notice your management and can't see what value they are adding, it's most likely excellent management.
They balance the above with the current business needs of course. Generally the two should be inline, but where they are not they help you manage that.
> Most programming should be done long before a single line of code is written
I would say “most engineering should be done before a single line of production code is written”.
Formalizing a “draft process” is something I’m really trying to sell to my team. We work in an old codebase - like, it’s now older than most of the new hires. Needless to say, there’s a whole world of complexity in just navigating the system. My take: don’t try to predict when the production code will be done, focus on the next draft, and iterate until we can define and measure what the right impact will be.
The problem is that there’s a ton of neanderthal software engineering management thinking that we’re just ticket machines. They think the process is “senior make ticket, anyone implement ticket, unga bunga”. What usually happens here is that we write a bunch of crappy code learning the system, then we’re supposed to just throw that in a PR. Then management is like “it’s done, right” and now there’s a ton of implicit pressure to ship crap. And the technical debt grows.
I haven’t quite codified a draft process, but I think it’s kind of in line with what Chris here is talking about: you shouldn’t worry about starting with writing production code until you’re very confident you know exactly what to do.
Ah well, it’s a fun list of opinions to read. Chris’ WIP book is an interesting read as well
The fact that you just summarized about an hour worth of argumentation from my last annual planning meeting with that one sentence has just destroyed me. I kneel.
At this precise moment in time, if anybody seriously thought the above was the way the process works or should work, they should be advocating for firing all the juniors and replacing them with LLMs.
I wish he'd say which people are the weirdos: the ones who say let's just pick a standard and rigorously enforce compliance, or the ones who complain about the burdens of compliance and try to undermine enforcement. I'd say the latter. I'm surprised he didn't feel the need to be specific.
This week wrote an article on this, since I found there's a lot to explain wrt this topic:
https://dev.to/cies/the-case-against-orms-5bh4
On HN:
While I agree with this in spirit, I once made the observation that:
"Code quality can be measured by the number of occurrences of 'WTF' uttered by other developers per minute when reading a PR."
Elegance might be subjective, but how easy code is to read and understand probably can be quantified even if we don't have the best tooling for that yet.
Meaning that if 10 engineers less experienced than me all tell me that they think expressing something one way is easier to understand than another, I take that as objective feedback and change course.
These particularly stood out to me:
Frontend development is a nightmare world of Kafkaesque awfulness I no longer enjoy
ORMs are the devil in all languages and all implementations. Just write the damn SQL
Monoliths remain pretty good
It's very hard to beat decades of RDBMS research and improvements
Micro-services require justification (they've increasingly just become assumed)
Most projects (even inside of AWS!) don't need to "scale" and are damaged by pretending so
I did agree with the following as well:
Typed languages are essential on teams with mixed experience levels
Java is a great language because it's boring
REPLs are not useful design tools (though, they are useful exploratory tools)
Most programming should be done long before a single line of code is written
Given a long enough time horizon, you'll deeply regret building on Serverless Functions
Types are assertions we make about the world
Most won't care about the craft. Cherish the ones that do, meet the rest where they are
Code coverage has absolutely nothing to do with code quality (in many cases, it's inversely proportional)
What is the regret about? I've been almost exclusively using AWS Lambda (not using the "Serverless" framework), since 1 month after AWS released Lambda in Nov 2014. I've built quite a lot on top of AWS Lambda, and I love it. It just works. It's not difficult to work with, and I don't really have to worry about scaling it. Is 10 years not enough of a "time horizon" to regret it?
A lot of people (definitely here) need to understand this.
HN discussions on that post: https://news.ycombinator.com/item?id=25887373 (4 years ago|686 comments), https://news.ycombinator.com/item?id=32162716 (3 years ago|58 comments), and https://news.ycombinator.com/item?id=41633156 (4 months ago|56 comments).
Can anyone elaborate how does one do that? I have seen this advice many many times but never anything actionable attached to it.
I believe my soft skills are my biggest weak point right now and is holding me from growing further in my career and I would like to do something about it. But I have no idea how.
Yes, and: it's difficult to describe, must be led from the top, and extremely difficult to evaluate from above.
The three questions are:
- What should we start doing?
- What should we continue doing?
- What should we stop doing?
This is an immensely powerful tool. Thanks to the awesome person who introduced me this.Addenda: "Theory X" is something really bad. If you're working with a team which responds positively to Theory X, you have much bigger problems IMHO.
I don't try to foresee abstractions (premature optimization), but I often encounter them when adding to a codebase. A recent example would be a tool that uses property info from a public database. The first version was hard coded to the database from one jurisdiction. When I added support for a second jurisdictions, abstractions helped avoid code duplication.
I just want to set up a linter that’s standard for the language and let CI deal with it. Anything other than that is mental to me.
> Most programming should be done long before a single line of code is written
I think via programming, and I think we should be building more prototypes. Upfront design almost always falls apart, and if you've invested too much into the design, you end up with some nasty frankenstein code. Get a good prototyping process in place instead, and write code and interfaces as early as possible, just make sure you're very willing to throw them away, review what worked, etc. The sooner you prototype, the sooner the "natural" design appears, and the less you've invested in it.
> Frontend development is a nightmare world of Kafkaesque awfulness I no longer enjoy
I like React much more than the shit I've enjoyed any of the run-up to it, and I've been building websites since the late 90s, working my way through server-side includes, hidden refreshing iframes, XMLHttpRequest, Prototype.js, jQuery ... and today's React just Makes Sense, man.
I would posit that the exact enviroment you are in changes massively what is correct, what is a good rule of thumb and what is a bad practice.
What applies to a game developer does not apply to a web developer. What applies to a product developer does not apply to a library developer. What applies in a startup does not apply in a legacy org.
I'm sure there are some universal truths, but usually they are principles and not prescriptions.
E.g. Code should probably lean toward readability, but you quickly come up against time constraints, language constraints, performance constraints, interpersonal conflict, etc.
Edit: To that end, I would ask that when discussing what we find to be useful or not useful, that we caveat with the enviroments that we have found this to be true.
This is further complicated by the fact that not all RDBMS engines are created equally.
It took me 2 decades to develop appreciation regarding why one would actually want to pay for something like SQL Server when options like SQLite and Postgres are free and easy to use.
My take on this would be: ORMs are the devil in all languages and all implementations. Static SQL queries with parameters will have a lot of duplication (lots of similar queries), whereas dynamically generating complex SQL will be hard to debug and maintain (e.g. myBatis). Write some good DB views in SQL. Generate some dumb ORM entities against those views for passable querying/filtering/pagination and do whatever works for altering it. Don’t go fully into the opposite direction either and don’t put 99% of your business logic into the DB, that will be hard to work with because the tooling isn’t very good (e.g. stored procedures).
I'm 30 years in now, and on balance, whilst they have clear advantages, I'm still not convinced that typed languages are essential, particularly for low level or module programming.
One of these days I'd like to see a "typed assembler". It still matters what the contents of registers mean, even if they all look the same to the instruction set.
Dynamic languages work great for scripting and rapid prototyping, but if you are working with a team maintaining a large monolith, I would rather have a statically typed language and avoid at least a class of runtime issues due to dynamic typing.
Case in point, I love writing my Jupyter notebooks with Python but am amazed that entire platforms like Dropbox (and instagram?) chose Python as their default language.
Do you think the Linux kernel could be written in a language without types enforced?
In my Spring Boot applications I log every SQL that is generated, and quickly spot unoptimizations, like lazy loading of entities instead of using join.
How ORM's behave in other languages and frameworks, like Python, Go, Rust is probably another story.
This sticks out like sore thumb to me and I think you are coding solo for 10 years. If you manage to lead a team of developers or work with them you are screwed without linting rules and standardized code style. Even if they are applied it takes months to get to a get a team working in harmony - without them it will be a disaster.
- merge conflict hells because code style diferences - bad for code reviewers - bad to ready everyone's different code sytles.
What's that?
Idris is dependently typed.
> Gradual typing is a type system that lies inbetween static typing and in dynamic typing. Some variables and expressions may be given types and the correctness of the typing is checked at compile time and some expressions may be left untyped and eventual type errors are reported at runtime.
That sounds miserable. I can't see how one would guarantee anything when types of other things aren't known. And I can't see how to connect that to dependent types either.
I really interested why the author thinks this.
I've seen the general sentiment wrt "the future" go from C to C++ to Java to Ruby to JS (also server-side) and Python.
My own sentiment went from Ruby to Haskell to, well, Kotlin I guess...
I looked into Idris (dependently typed), but did not think it would fit the Overton window[1], to be a reasonable expectation for the future.
This hilariously works for a lot of things. Biggest trouble with legalization of drugs is the drug use of the ones that love to talk about why it should be legal. Biggest trouble of prohibition policies are the people that love going on about why they are better for not drinking.
I assert that this is, essentially, "The trouble with THING is the group of people that think THING is a panacea at what it does."
I think distributed locking is hard because it only offers certain properties and requires that the application work together to achieve consistency, just like what you said about DynamoDB:
> DynamoDB is a good database (IFF your workload lines up with what it's offering)
I have written a blog post about distributed locks: https://blog.damnever.com/en/2020/the-consistency-problem-of...
Add Jupyter notebooks to the list.
Currently in a corporate environment where that seems to be the go to way of coding and it’s just fuckin awful compared to an IDE
Good, empathetic UI design is invaluable.
Get a professional UI designer. Engineers are (in the main) appalling at it and will cost you time and sales.
> There is no pride in managing or understanding complexity
To the point that intentionally creating complexity or allowing it to continue to exist where it can be simplified, I agree - but some systems are necessarily complex and having pride in understanding and managing them is a good thing. If no one had pride in this, why would anyone care about the things that aren't simple - or bother to train the ability to simplify the complex in the first place!
> Micro-services require justification
I used to believe this, but have changed my mind on it. Micro-services are great in the current CS ecosystem (at least in the US) because they allow smaller parts of the whole to be more easily refactored when you find your development team with none of the people that were present when design decisions were made and a major feature needs to change.
It's an unpleasant situation to be in, and one that you ideally want to avoid happening, but is common enough that preparing for it in your application landscape is reasonable.
I wonder how much of this can be qualified with "after you've been hired".
Between two university graduates with equal skills in technical interviews and splicing linked lists and recursive-descent parsing and whatever, if one has better soft skills, you hire that one.
The question is what you do between one who is better at soft skills and another who is better at doubly linked lists or group-by queries or docker orchestration or whatever tech you're asking about in the interview. Empirical evidence suggests you hire the second person and support and expect them to skill up once they're in.
If you have spare time at uni, working on both soft and techy skills is great, if you have to trade off opportunity costs, the advice I hear a lot is invest on the technical side first.
Additionally such an extend experience gives us another point of view on trendy subjects that are experiences from the past newly repacked.
And desilusion, seeing so many great ideas taking decades to become relevant, or never at all.
>The query planner is a cruel mistress
>ORMs are the devil in all languages and all implementations. Just write the damn SQL
>DynamoDB is the worst possible choice for general application development
>It's very hard to beat decades of RDBMS research and improvements
All these points tell a beautiful story
I think I might get this tattooed on my chest.
I am holding back on stressing out regarding syntax like PEP 8. My role right now is great where we get to prototype random things.
> There is no pride in managing or understanding complexity
interact with
> If I think something is easy, that's a sure sign I don't understand it.
? Is it implying that you must understand the irreducible complexity, but mustn't take pride in that understanding? Or is "difficult" the opposite of "easy" here, rather than "complex?"
I regret how neglected interpreted languages have become. I'm much more productive with interpreted languages than compiled (or worse; transpiled) languages. The iteration time is crucial for me. I don't want to wait even 30 seconds to test a change. After 20 seconds waiting for a compilation, my brain is already going into sleep mode. I can't have that.
For most application-building use cases, I will choose an interpreted dynamically typed language over a compiled statically typed one.
When it comes to low-level embedded use cases, or high-performance systems programming I will tolerate a compilation step but I won't pretend like it's not a negative.
Yep. At some point in React (maybe 5 years in) ‘how do I handle state?’ started to be ‘read this essay about the true nature of FRP from Dan Abramov’ and it just seemed to get worse from there. I worry Svelte will do the same in future.
I think most projects need careful attention to handling unexpectedly large throughput gracefully.
My monolith horror started when I was working with Ruby developers. The problem with a monolith is when it becomes too big for itself. Realistically something between microservices and monoliths are where quality of life resides.
If you need a small service that needs to be fast and focused microservice it. If you need a service where it relies heavily on the same logic and shared across many things. As long as it is performant, modular and easy to fix, monolith it.
Either way conforming to one design certainly cripples the potential of services.
I've come to the conclusion that in almost all cases, you should avoid providing any abstraction from your own library / service, and let consumers figure out what abstraction makes sense in their domain. By stipulating the abstraction, you're robbing your consumers of the ability to make things work the way they want, and painting your own thing into a corner.
When you build the abstraction, it seems like you're doing your consumers a favor. But that favor is short lived as the abstraction changes and breaks your consumers.
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.
As a former Scala dev, I feel this in my bones.
Good management is life and death, particularly for a startup. If you think you can do without it and you're not a good manager yourself then it's going to be a struggle to execute.
> ...you'll deeply regret building on Serverless Functions
Whatever serverless functions promise in scalability, they'll cost you in terms of complexity. Trying to build a cohesive backend entirely in a serverless environment just isn't worth it when it's trivial to boot up a simple, long-running server. Even running locally is a pain in the ass compared to `rails s` or `fastapi dev`.
God forbid your serverless environment is actually on the edge, at which point most of the stuff you're used to using won't work.
Also the observation of "The trouble with functional programming is functional programmers" is absolutely correct.
This needs to be said more. Way more.
P.S.: You can ask why, and I can answer honestly, without hostility.
Understanding and managing complexity is one of the first steps required in order to eliminate complexity. Some of the greatest achievements in my software development career have been instances where I carefully pulled apart inscruitable solutions, often short-term and built in desperation, and re-constituted them into well tested and much less complex solutions which were more understandable by devs and users.
I agree with most of Chris' observations and enjoyed reading his insights. Makes me want to do the same!
A lot of great coders have psychological oddities. Some things help them focus. Whether it’s neat environment, listening to music, consistent code formatting.
I listen to them and try and accommodate even if I disagree. I’ve changed my mind about several topics multiple times now. I felt strongly about some at one point over the past few decades as well.
In my experience when working on and/or leading a team, having good and clear code style/guidelines helps the members of the team understand other people’s code much more easily. It often also serves as much easier to understand historical record when looking at previous contributions. I find it’s best to leverage tooling that enforces team conventions so that programmers don’t have to “stress” about it.
In my opinion, almost every developer I've worked with who advocated for generous amounts of comments has overestimated their (and or others') ability to write good quality comments.
Obvious ones like `a = b; // set a to b` while useless are also mostly harmless, but I've been lead astray by outright factually wrong comments, many more times than I can count. I certainly don't feel confident in my own ability to not write factually incorrect comments. So yeah, I'd rather the code do the talking.
13 yoe here, I don't find this true, in fact I find the opposite - storing data in binary (to minimise de/serialization overhead) and precomputing indices and relations in a simple K/V store easily and immediately annihilates best case performance you could get out of a typical relational DB. I don't work in FAANG so we don't get millions of reads/writes per second, but there's probably more use-cases like us than like FAANG.
This line piqued my interest - what does an algebra mean in this context? Does anyone know of any good resources for further exploration?
My two differing thoughts:
1) Gradual, dependently typed languages are the future: no, just go with something typed. We are trying to type our python code base right now. It sucks.
2) People who stress over code style...: I love go fmt. Use tooling and linters. Be consistent in the code base. Inconsistent styles can lead to misreading code.
My theory from working at a company that demanded high unit test coverage is that it encourages coding patterns that are easier to create coverage for. Not necessarily easier to genuinely test, but easier to get a high coverage metric.
For example, try/catch blocks are bad if you want coverage. Now you have to do things like inject exceptions. People will try to design things so that's not required, with odd side effects.
- Don't get too fundamentalist about OO or functional programming. Each has its place.
- "Spend time hunting for an algebra" is somewhat obscure, but truly excellent advice, and I have spend a lot of my career doing exactly that. That has never been time wasted. This connects to a couple of other points. 1) Once you have an algebra, you have the basis of a good API for functional programming. (This point is not explicit in the list.) 2) The things manipulated by your algebra are also the basis of a good OO design.
- "Elegance is not a real metric." It is absolutely dangerous as a metric, because it is a subjective goal we all aim for, and can therefore be used to justify anything, no matter how dumb. That said, elegance is something to strive for in your day-to-day programming life. You know it when you see it in someone else's work, and you appreciate it. You see a small set of principles, implemented in one place, that can then combine in many ways to do many useful things. Hmm, sounds a lot like an algebra!
I think this one keeps on being viewed as a % metric. You have 50% code coverage, 75%, 99.9%, 100%, etc. In that sense it is useless. Where I think code coverage has an enormous value is in showing what parts of your logic are/are not covered by test code. Being able to eyeball that and see where key parts of logic are not tested is extremely helpful and tends to get lost in these discussions.
Constructive criticism: tell the reasoning behind those opinions. I really believe that they are based on facts and experiences, so tell them! Only telling "after 10 years in the industry" may look like the argumentum ab auctoritate fallacy (https://en.wikipedia.org/wiki/Argument_from_authority)
This was in the "picked up along the way" category. Better a slow learner than a no-learner.
That was actually one of the first things I understood about programming 30 years ago. Accidental complexity is the root af all evil.
Code maintainability certainly is something to consider that will bite you if you're not thinking about it.
Could not agree more.
I cannot agree with this. I've constantly ran into issues around where you can insert data into with an attribute name such as "status" and then when you query it, it says you cannot query with a reserved keyword.
There is a myriad of other issues I've found and when asking around chat groups and forums, people universally dislike dynamo db.
Considering anyone who is any good is gonna automate these things… and they are very important for long term maintenance and readability and predictability…
… probably the author is terrible. Sad to waste a decade.
At some point, you have to have someone looking "up and out" to make sure the folks looking "down and in" are all still moving in the same direction.
This definitely contradicts a previous article on Discovery Coding [1]. I can't say I agree with it _at all_, despite 20 years in the business.
What are the main issues people run into with ORMs? I've used Django ORM for years and written some relatively large applications using it without much problems. Complex queries and aggregations can result in quite hairy code though.
Agreed, or just use a key/val JSON document database and it's get/set APIs for basic operations. All the main ones also provide indexing and SQL APIs if that's needed.
> Frontend development is a nightmare world of Kafkaesque awfulness I no longer enjoy
These two may be interrelated. I do app (frontend) development, and it greatly benefits from an iterative, evolutionary approach.
I was agreeing with most opinions and then I saw this one. Having used Ecto from the elixir ecosystem completely changed my mind on this. It's an amazing piece of software.
Let's just apply "Hitchens's razor" to this kind of none sense:
What can be asserted without evidence can also be dismissed without evidence
> 3%, maybe 95.2%, of project managers, could disappear tomorrow to either no effect or a net gain in efficiency. (this estimate is up from 4 years ago)
This is 100% of immediate line manager that I have had in my career.Anyone else?
My feeling is that a lot of negativity towards the frontend stems from assuming that the entire field is like React and its community. It's really not like that.
Anyone have more context on this? I've never thought of a repl as a design tool. Does he mean loading your app in a repl, calling functions manually and then manually swapping them out in real time?
100% of project managers could disappear with no change in efficiency - not 95% ;)
1) Nix. I finally came around after one too many bricked Linux installs, and learning Docker and being kind of unhappy with it. And while I still haven't completely mastered it, you can learn enough in a reasonable amount of time to maintain a Linux install.
> Blind devotion to functional is dumb.
Except when it's not "blind" and informed by hard experience (years of OOP). Which leads me to...
2) Functional programming/immutable data. For the vast majority of use-cases, these just lead to better code, fewer bugs, and less LOC needed for a given functionality. (I just wish Elixir had the option to compile to a single binary. Roc-lang looks interesting, in that space, if you aren't into Rust.)
3) Typing. I'm coming around to it, and to a general principle of "happy-path strictness" in general. All to achieve determinism.
> Java is a great language because it's boring
No. The people who disparage software devs who have tool preferences are a special bunch and not really "software devs" (with apologies to the No True Scotsman fallacy). If everyone was supposed to be "fine" with Java, then no new languages need be developed!
> Java is a great language because it's boring
This. Especially the thing about mixed experience levels.
This is true of working with LLMs, too
What does this mean?
"is"? I see plenty.
by the way, whats wrong with serverless functions?
Given a long enough time horizon, you'll deeply regret building on Serverless FunctionsMaybe "mutable objects"? Maybe these were intended to be isolated statements? Personally I believe functional programming is great with objects too...
It is however true that many OOP-embracing languages tend to favor an imperative style. Scala is an example of a language that embraces both.
I wish this were the case, but have found that "No plan survives first contact with the enemy".
> Objects are extremely good at what they're good at. Blind devotion to functional is dumb.
Blind devotion to anything in engineering is dumb, but if you go full functional on the frontend it’s definitely not “Kafkaesque”
> Typed languages are essential on teams with mixed experience levels
Essential, meaning 'cannot exist without', it's not. I've seen this work a number of places.
> Blind devotion to functional is dumb.
Managing/limiting state is always a worthwhile pursuit. I'd think he would agree since he seems to value simplicity
> People who stress over code style, linting rules, or other minutia remain insane weirdos to me. Focus on more important things.
That's like saying don't check if your cars tires still have any pattern left, the engine is more important. Until it isn't. Streamlining the smaller details allows the brain to focus on more important stuff, but the details matter and their value increases exponentially with the size of the project.
"The correct tool for the job."
Seeing a document database used for tabular purposes gives me a sad.
sure, but I think the status quo is to way overuse objects. my preferred style is to bias heavily towards value objects, and to never ever use things like inheritance for control flow
"ORMs are the devil in all languages and all implementations." hard agree lol
Um, "minutiae", erm, uh.
Guess this hits home. But Blind anything is bad. I spent a decade blinded by objects being everything (original gang of four book). Then a decade where everything is functions.
Why not pass a list of objects to that function.
Stopped reading there. Ironic that one is right below the other.
Actually I recently discovered it is, it's just not what people think. Elegance is a function of the probability measure of how much someone likes your idea/solution/thing. There is a curve upon which people will think it is more or less elegant.
The problem is you can't actually see elegance from your own perspective. You might think it's elegant and it later turns out it's not to anyone else. And vice versa. It's like quantum physics: you have to observe it externally and your guess won't always be right. That doesn't mean it's not a metric. It just depends on multiple probabilistic measures.
It's important to gauge the elegance of things because in general, engineers will fight you harder the less elegant your idea is. It might be a better idea, despite its inelegance, but if you're working on a team, the team's acceptance of the idea is more important. (Unless you have total authority, in which case you can do whatever you want)
> Most projects (even inside of AWS!) don't need to "scale" and are damaged by pretending so
Actually it's the opposite: literally all projects need to scale. The problem, again, is perspective: the scale of the scaling varies.
If you have a physical business where you move goods around, you have to choose how to do that. You could buy a bike, or a car, or a truck, container ship, etc to move the goods. You might need just one or you might need many. Your business might increase or stay the same.
If you buy a container ship, probably you will never need to add another container ship again, as very few do that much business. But if you buy a bicycle, probably you will need to at least add more bicycles, if not change completely to a car or truck, or multiple.
If you use the smallest measure of compute on AWS, it's pretty much a guarantee it won't be sufficient for your entire workload. If you buy the biggest measure of compute, it's almost guaranteed it will be more than big enough. The scale of the scale matters.
Scale is therefore, again, a probability measure of whether your workload will match its container. If you could perfectly predict your workload and the capability of the container then this wouldn't be probabilistic.
But not only is your workload usually variable, so is the container. Bicycles/cars/trucks/container ships all can fail, so the scale of your workload may reach 0 at some point. The ability to scale dynamically is important in order to eventually deal with failure. Otherwise if your car died you could never get or rent another one, you'd have to sit there becoming an auto mechanic to get your business working again.
This is more obvious when you self-host. People take it for granted on AWS, where they don't realize that literally everything in AWS is scalable, and so tell themselves scalability doesn't matter... until it does. If we didn't have a way to scale bicycles/cars/trucks etc (by temporarily or permanently getting another one), the world would be much harder to do anything in.
Could someone expand on this point?
Ehhh..lots of nuance to this one
> Micro-services require justification (they've increasingly just become assumed)
I say the opposite is true. Monoliths have a negative value return with the expansion of an application.
My issue with Java is not that it's boring, which it is not, but there is so much that needs to be done to get a simple "Hello World" program to run which also depends on an external library. It feels like you first have to build a castle just to put a bed in a room.