6 ms·
Yes it's tedious to write plumbing code, but it's also dead simple. Just write the damn code. Don't try to create some weird beast that "automagically" does the
by jackblemming 3y ago
Yes it's tedious to write plumbing code, but it's also dead simple. Just write the damn code. Don't try to create some weird beast that "automagically" does the n different things. Just. Write. The. Code.
Yes it does suck. You know what sucks worse? Zero separation of concerns and the tar pit you get from it.
- erik_seaberg 3y agoThis is sort of an argument for assembly over higher-level languages. Where do you draw the line for plumbing too tedious to write? I view abstraction as the single best way to make each other permanently more productive.
- jackblemming 3y agoGreat question. A good abstraction can offer an order of magnitude improvement in some dimension, whether that be clarity, speed, or the like. A bad abstraction trades a lot of one dimension for a little of another. In this case, I'll happily take an order of magnitude improvement in understandability, debuggability, extensibility, and a lower learning curve over a crappy ORM or DSL that saves me the effort of writing ~30 LOC; heck even ~5k LOC. If we get farther than that, we can talk. And even then, the solution is probably not going to be an ORM or a DSL.
- lovasoa 3y agoIt's not just writing the code. Writing the code is easy. It's maintaining it. And then debugging it. There is a limit to how many lines of code a single person can maintain.
- PNWChris 3y agoI'm of two minds on this, I both agree and disagree. Once a code base is a certain size, explicit but bigger can be a boon. Magic dynamic dispatch systems and other tools that simplify plumbing make onboarding and routine, drive-by maintenance way harder IME. I find that once you understand systems that have a dash of "magic", though, it is easier to add features and stuff. Single points of maintenance and all that. It's a continuum, with each side having different benefits.
- mawadev 3y agoThat is true, add more developers :)
- delusional 3y agoNo there is not. A line of code takes no resources, has no overhead, requires no upkeep. I think you may be referring to the drag complexity imposes in future development. That I agree with, but LOC is a poor proxy for complexity, and code that is static costs nothing.
- fragmede 3y agoEvery line of code has an overhead; has a chance of bugs, and demands upkeep just for existing. Having class A, class B, and class C, that do almost the same, but slightly different thing means that when the business rules change, that you have to be sure that similar, but slightly different changes to class B and class C, which aren't neatly going to be self-contained in B.cpp and C.cpp (or .py, .rs, .rb; you get the point) have to be made, and then you can't ever be sure that A.cpp doesn't also have some long-forgotten but similar and crucial bit of functionality that this one customer relies on (because that was written before TDD became popular). --- LoC itself is a bad proxy for complexity, but I think taking the log of the number of LoC tells you enough to build some expectations. A codebase where log LoC is ~6 (so in the neighborhood of ~1M LoC) is different enough from one where log LOC is ~3 (so ~1,000 LoC) that you have an idea of what you're getting into if someone asks you to make a change to either one of those.
- delusional 3y agoThe key to understanding our (apparent) disagreement is: > that when the business rules change Yes, when things change complexity has a cost. The inverse is also true however, if nothing changes, it has no cost. If class A, B, and C do almost the same thing, then nobody cares because the computer will gladly execute almost the same thing in different locations in memory. The modern computer built today is essentially perfect. It will execute the same thing every time, it will not suddenly require changes because there was some degradation in an adder, and no cogs need changing. All the maintenance is stuff we make up because we want it to do something it never did before.
- Supermancho 3y ago
- lawn 3y agoExtending and debugging complex code (eg autogenerating tools, macros etc) is much more difficult than simple code, even if the before can be written in fewer lines than replicating (nearly) identical but simple code.
- praptak 3y agoDebugging is easier when you have a backend server which logs the API calls. I did debug apps where UI and DB access lived in a single code space (VB/Delphi style). This was pretty hard to debug and logic was so tightly coupled with the UI code that it was nearly impossible to write tests for it.
- FpUser 3y agoBecause those Delphi apps were written by less capable people. I've done tons of Delphi's applications in the past and still do some now (both Delphi and Lazarus). In every case the UI and backend business logic was clearly separated.
- hyperman1 3y agoIn my experience, the limit does not depend on the volume as such, but more the complexity. This complexity can be intrinsic frombthe business domain, or accudental from technical choices. If frontend, backend and storage have parallell structure based on predictable patterns, the triple line cost is easily ignorable by skimming. Development heavily slows down under unpredictability. Maintainance is slower partially because knowledge loss hightens unpredictability. One-off half-documented pseudo-frameworks create much higher knowledge loss in maintenance, and are a much worse time eater than simple code, even if tripled.
- lovasoa 3y agoHey, I'm Ophir, the co-author of the post, and main contributor to the SQLPage one-off half-documented pseudo-framework :) I'm not sure if you had a look at what SQLPage really does. It is not a framework in the same sense as Django, Rails, or Laravel. It doesn't have a large set of functions you need to interact with. It lets you write the database queries you would have written anyway to get data out of your database, and just renders that as a nice frontend. All the components you can use for rendering are heavily documented with many examples on https://sql.ophir.dev/documentation.sql https://sql.ophir.dev/documentation.sql
- hyperman1 3y agoOK, here is a severe misunderstanding brewing. I definitely did not mean SQLPage when I said one-off half-documented pseudo-framework. In fact, I did not mean any real, standalone, named product with this. I do however see very much how you could think so from my description, so my apologies. What I meant: consider any random big software development. It might be mind-numbingly boring, very technically repetitive, you might have devs who never did any maintenance, or devs being expensive got the command to start building something anything while the business has yet to start delivering something resembling requirements. In this kind of case, programmers tend to start building abstractions based on their imagined needs, with an We-will-add-the-business-stuff-later attitude. The results are generally some kind of architecture astronaut horror. Abstraction will be very high, weird features and handling of useless corner cases will abound. In-code documentation, logging, debugging features will be absent. Higher level documentation was either not written or lost long ago. That's your average one-off half-documented pseudo-framework. I've seen plenty of these (and committed a few crimes of my own). From the top of my head, some of the worst: * A full-blown 3000 lines templating library, for rendering exactly 1 report that was basically a for loop dumping an sql query to a html file. * A C10K database connection manager built on top of apache commons pooling (which while a good library was not fit for this purpose at all), hyperoptimized for TCP port open/close speed, for an application making at most a few connections per minute. * A cache manager for files, deciding when to remove a file based on either AI or linear regression, with a web UI for configuring this decision and all the zillion config parameters and strategies, but the time to generate the cached data was shorter than the time to read it from disk and the files easily lived for months. * A java message building code that did everything humanly possible to only allocate a big buffer once at the beginning because 'GC is too slow', but the coder forgot how joining strings together created temporaries that were of course cleaned up by the GC. Needless to say, the people maintaining these beast cursed the devs who implemented them, and tended to rip them out on sight if possible, or pay the very heavy maintenance cost.
- simonw 3y ago"There is a limit to how many lines of code a single person can maintain." I used to believe that, but I don't think it holds true any more. The trick is to write code with automated tests and comprehensive documentation. If you do this, you can leave projects in a state where you can pick them up in the future as if you weren't the original author.
- lovasoa 3y agoOh, I hadn't noticed your username! On the topic of maintenance: could you have a look at this pull request I opened three years ago on a repo of yours : https://github.com/simonw/datasette/pull/1159 https://github.com/simonw/datasette/pull/1159 ?
- simonw 3y agoHah, wow, it looks like I've been procrastinating on making a decision if I like that or not for three years! I'll add it to the Datasette 1.0 milestone so it definitely gets my attention before shipping that release.
- lovasoa 3y agoIt's true that if all the code works well, is tested and all the features are supposed to stay the way they were when the code was written, then, any developer can maintain any amount of code, there is just nothing to do. The problem arises when there is a change in what we want the code to do. Changing a feature that is implemented over three codebases in three different languages is definitely much more work than updating something that was written in SQLPage, for instance.
- PartiallyTyped 3y agoI asked some developers to implement something with guidelines over how to do it. Ultimately they tried to do more than asked which then caused problems because maintenance is now harder, and some types were removed while others were “enriched”, and much like uranium, became more dangerous to wield.
- soulofmischief 3y agoWhen writing tests, my goal is to verify a given routine works as intended. I don't want to write tests for the same functionality over and over. Repeated functionality should be extracted, tested in isolation and then used in composition with other tested code. This is how you write correct code without stress or worry. People that take "just write the code" as dogma have produced some of the most untestable, bug-ridden code I've ever encountered.
- echelon 3y agoYou're talking about two entirely different things. OP is saying don't write a "magic thingcombobulator factory" that "simplifies X endpoints with Y and Z similar behavior". This might be an earnest attempt to try to speed development, but it all collapses under its own weight at scale. The maintainers after you will be left holding the bag and have immense difficulty refactoring, adding a new set of requirements, migrating to a new data model, or moving to an entirely new service. Clever abstraction kills. I've dealt with undoing insane balls of twine left by unthoughtful devs, mostly in magic method dispatch, included behavioral overrides, and monkey patching (some of these behaviors are a hallmark in Ruby land). One person once exposed the entire database as a "safe" SQL-like query parameter DSL. No more endpoints to write - just use the thing. There are so many problems with this. For example, when millions of transactions per day on mobile clients or via third party integrators bake these assumptions in, you can't easily migrate them away. You have to keep serving the same data assumptions, even while you're gutting and changing everything under the hood. You have to understand the callers, the data flows, the read and write paths. For complex spider webs of business critical logic, it can take several people entire quarters to even years to unwind the mess. Simple endpoint logic is best. Your data model should be well thought out, and the CRUD code serves as a well-defined, super literate, super maintainable means to manipulate it. Simplicity of design is important from the simplest Django endpoints all the way up to the most battle-hardened active/active 500k transaction per second endpoints.
- klodolph 3y agoAgreed. I’ve also gone into a codebase and seen the most boring code ever. It looked like examples from an intro to web programming class. The backend did simple parameteried SQL queries. It was a pleasure to work with. My conclusion is that the real “star” developers will, most of the time, write code that’s so simple, it looks like anyone could have written it. They ship a project on time, with good performance and availability, and then they move on. Anyone can come in and maintain it because the code is so obvious.
- dgb23 3y agoI’ve become a fan of code generation (data driven). The benefits: you write code faster, automatically uniform and the result is “dumb” and less abstract AKA easy to debug and modify. Tedium/boilerplate is gone, you focus in the overall model. The costs: you think more up front, you have to see the result first (hand written). It’s easy to see common patterns too early. With some patience, caution and experience some of the costs can be mitigated.
- deterministic 3y agoSame here. A code generator I wrote at work has saved an enormous amount of work hours for everybody. It is super popular. I routinely generate 80% of the code needed to implement a typical business application.
- lovasoa 3y agoI loved the idea of code generation when I first encountered it, but I've since come to hate it. A large code base that was auto-generated and then subtly modified in some places is hard to refactor, and if you need to change the signature of a function that is used thousands of time across the generated code, you are in for a long ride.
- deterministic 3y agoThere is an art to writing good code generators. Bad code generators are really really bad. Good code generators are absolutely awesome! I have saved thousands of hours using my own code generators. But I have also seen very bad code generators in the wild that I wouldn’t recommend using.
- dgb23 3y agoYes it’s easy to go overboard with it. I don’t have a clear recipe for which parts it makes sense, except that it emerges from hand written code.
- semicolon_storm 3y agoI work at a company that does a lot of code generation, and it gets uglier the longer you do it. It's much harder to write the code that generates the code you want than to just write the damn code in the first place. The abstractions & assumptions made for your code generator will eventually begin to break down, and when that finally happens everything goes from a simple refactoring to way overly complicated update to the generator.
- amelius 3y ago> Yes it's tedious to write plumbing code, but it's also dead simple. Don't we have ChatGPT/Copilot to do it for us now?
- DarkNova6 3y agoTo be fair, a good IDE can give you low-effort tools to one-click typical use-cases. Other than that I completely agree. Devs get hang-up on trivial syntax topics waaaay too often, when the actual time-killer lies in reasoning and performing test-cycles.
- bob1029 3y agoI find similar arguments around SQL. So much time & frustration expended simply to avoid typing out the magic database commands... And the constant ego trips attempting to outperform 30+ year old query planner codebases on 7-way+ joins by using baby's first ORM. > the tar pit If you find yourself stuck in one of these, I strongly recommend giving this a shot: https://curtclifton.net/papers/MoseleyMarks06a.pdf https://curtclifton.net/papers/MoseleyMarks06a.pdf "but it won't scale" We are in the era of hyperscale SQL engines. Database engines that are spread out across multiple servers, racks and buildings. Engines so vast & complex the compute & storage responsibilities have to be separated into different stacks. But, they (the good ones) still work just like the old school approach from an application perspective. The workload necessary to actually saturate one of these databases would be incredible. I some days wonder if Twitter could be rewritten on top of one without much suffering. And, if you aren't trying to go big and bold or spend a bunch of money, there's always SQLite. It also supports basically all the same damn things. It can run entirely in memory. It has FTS indexing. Your CTE-enabled queries will work just fine on it. If you find SQLite doesn't scale with you, swapping to a different engine really isn't that big of a deal either. You will have some dialect conflicts but it's generally very workable, especially if you use some thin layer like Dapper between your code and the actual connection instances.
- whateveracct 3y agoThe thought leaders at my job had this philosophy and now we have a gigantic project that takes forever to compile. And you do always have to compile all of it because it's all one commingled codebase. Tough place to be.
- DarkNova6 3y agoI wonder, for which language would that be?
- whateveracct 3y agoGolang