18 ms·
Back in university I had an experience that was really instructive. For a project we had to write a program that differentiates mathematical equations. I dove
by jcbrand 5y ago
Back in university I had an experience that was really instructive.
For a project we had to write a program that differentiates mathematical equations.
I dove in and just started writing code. Eventually, I realized that I had made a design error and that my code was much more complicated and cumbersome than it needed to be and I was getting stuck due to the complexity of the monstrosity I created.
Unfortunately I figured this fundamental design flaw the night before we had to hand the assignment in and there was no way I could rewrite everything from scratch. I had to push through and put lipstick on this pig as best I could.
In the end, I had spent way more time working on this project than my friends who had spent time upfront designing their programs instead of just jumping in.
This has taught me the lesson to always first try and think things through and come up with some kind of initial design, instead of just jumping in and writing code blindly. Yes you can always refactor, but some early design mistakes can cost you a lot of time, and perhaps make refactoring unfeasible compared to a complete rewrite.
As they say "measure twice, cut once".
- skohan 5y agoYeah this just hasn't been my experience. If you're working on a house you measure twice and cut once because the cost of reworking physical materials is a lot more expensive than the cost of doing a second measurement. If you could delete half your house and re-build it at zero cost, it might be more valuable to just go for the first attempt and learn from it rather than trying to do everything in theory up front. If you find yourself working on a "monstrosity" maybe you haven't seen the signs soon enough that you need to take a step back and refactor. But in my experience, at least starting on the problem with a POC gives you so much more high quality information that even if you have to scrap and re-write part way in, you're going to reach such a better result than if you try to map the whole thing out first without actually having tried to solve the problem.
- gefhfffh 5y agoWhen can you rebuild at zero cost? I have made similar avoidable mistakes of not thinking it through enough, could have saved me a lot of rewriting, which was pretty expensive
- runald 5y agoProbably not literally without cost, but if the code was written with disposability in mind combined with just a little bit of pre-planning, then rewriting or refactoring should be indeed trivial.
- gefhfffh 5y agoWhen start off with "wrong" higher level design concepts, neither of those is trivial. If you're writing a function implementation without thinking about design, well you might be right.
- sseagull 5y agoI sometimes wonder if there is a miscommunication. I’m scratching my head sometimes like “how can rewriting/refactoring an entire 10-20k project take negligible time?” Maybe some people have very small projects compared to what I work on? Or maybe they are talking about the design of a single small component? I inherited a codebase that needed some refactoring because it was written “to just get it shipped”. If completely fell apart with more users and has taken me a year to get it where it needs to be.
- deleted 5y ago[deleted]
- skohan 5y agoBut how often would you actually have to rewrite an entire 10-20k LOC project at once? As you need to add functionality, you can opportunistically find ways to improve the codebase toward a better/more maintainable structure. I have several large codebases I work on which probably get totally rewritten every 18 months or 2 years, however incrementally. If you have a working project and you think you need to throw it all out and start from scratch probably it's worth a second thought.
- hinkley 5y agoWe always talk about time when the elephant in the room is energy. People say we don’t have “time” for that and someone else gets out a calendar and tries to disprove them. Followed by a bunch of backpedaling with other excuses and followed up with foot dragging. The second elephant in the room is job security. People who write baroque code are hard to fire. Nobody wants to invest energy in understanding their private little Bedlam.
- AlchemistCamp 5y ago> "If you could delete half your house and re-build it at zero cost, it might..." I look forward to that day when atoms are commanded like bits!
- nthj 5y agoI’ve found people often overlook that while code can be very quickly deleted, gigabytes or terabytes of production data is a huge pain to ETL later. Investing in the data model upfront has huge payoffs for your code and avoiding ETLs later on.
- Aqueous 5y agoAs someone who is currently over a year into rewriting a massive system with a fundamental design error by the original designer I can assure you that failing to plan your data model up front can have huge costs not just for you but for anyone who picks up your code in the future, and can hamstring a system so that it is impossible to extend or evolve.
- skohan 5y agoWhat was the design error?
- deleted 5y ago[deleted]
- Aqueous 5y agoIt's a platform for managing a kind of appointment, but it doesn't have an appointments table. The appointments data is combined with a different table, and there was no way to disentangle them easily because the entire system was built around that object model. Case study in failure to normalize. The hard part is done, but basically we had to switch the engine while the car was running so to speak. In order to switch this out you need to start writing the correct data shape, then switch everything over to reading that shape. When people work strict 9 to 5s this will take you forever especially when managing a large amount of volume, which requires you to be extremely risk-averse and slow.
- nfw2 5y agoUsually you can't delete half your codebase and re-build it at zero cost. The cost of developing a codebase is often the primary cost for software companies.
- hinkley 5y agoThe cost of the knowledge of that code and the techniques that created is spread in five to fifty other brains. That’s the hard part. You keep finding new copies of patterns you’re trying to remove. In a couple of notable cases, that didn’t stop until I removed the last copy. My theory is that certain people were cutting and pasting code from one of the three surviving copies.
- hinkley 5y agoThis is a very self-centered way to think about things. I don’t mean selfish, I mean thinking as a “me” problem instead of an “us” problem. If I have to rewrite a bit of my code then them’s the breaks. But I work on a team, sometimes a big team. I don’t have “a house” I have a construction crew that is building many houses and will go on building them. If they’re doing it wrong then I have not only the problem in front of me but five copies elsewhere. And I can’t fix problems N times faster than they are made. And I can’t always sell them on the better technique, even when there are demonstrable problems with theirs.
- skohan 5y agoI want to work with people who I trust to rewrite my code. And of course I don't mean that you should check in code which is a mess. But from the time you start a feature to the time you open a PR, you can go through several iterations of messy code before arriving at a solution which is fit to share with your colleagues.
- hinkley 5y agoI do too, but I can’t spend my whole life interviewing, and sometimes great teams just run out of money.
- mannykannot 5y agoThe development of the relational model of databases is an example where thinking things through led to a radically different and superior solution, going in a very different direction than ad-hoc development had produced, or was ever likely to produce. At the time Codd published his seminal paper, there were no implementations of those ideas. It is also notoriously difficult to get the design of concurrency primitives correct without thinking things through.
- geodel 5y agoYeah, but >99% code is about using relational DBs and concurrency primitives not developing them. There are somethings that would depend on solid theoretical understanding but most of the software today is much more amenable to trying out things first and reworking failed parts.
- mannykannot 5y agoIn practice, one does not write a single line of code without feeling that it is somehow getting you closer to the desired outcome. If you have the ability to anticipate that it will not contribute to that goal, or that it will create problems on the way, or that there is a better way, even before you have written and tested it, then it would be counterproductive not to do so.
- skohan 5y agoBut there's also such a thing as over-planning. If every function you write, you are thinking about 100 different rules about "best practices" you can end up not writing anything at all. Sometimes it's better to accept some level of imperfection first and refine later.
- mannykannot 5y agoSure, but your reply to Jcbrand was dismissive of the idea that there is any value to thinking ahead. Jcbrand was not advocating 'thinking about 100 different rules about "best practices"', only that it is useful to try to work out the consequences of the choices you make, in advance of those consequences being revealed to you by failed tests (or failures in use.) I have no idea why there is a large (or at least vocal) community of developers whose dogma seems to be that thinking things through is a waste of time (though maybe it is just an overreaction to the equally dogmatic clean coders and similar prescriptivists.)
- d0mine 5y agoI don't know about your experience but refactoring is just not on the menu in most commercial environments I'm familiar with, therefore if you always pick the first solution that cones to find, it is likely you have to leave with the consequences of the hack for a long time (until the system crumbles under its own complexity).
- skohan 5y agoI guess I have been lucky - I've always been able to negotiate for time to refactor if needed, or just find time for it in lulls between tasks. If you're in an environment where engineers don't have the freedom to improve their codebase I would not consider that to be a healthy practice, but that certainly would change the value proposition around upfront design.
- mbrodersen 5y agoI refactor all the time and have done it for 25+ years. The result is solid code that is easy to maintain and close to bug free (no bugs in production the last 5+ years).
- d0mine 5y agoCould you describe the process: did you need to justify the time spent on refactoring in any way? ("why known bugs, requested new features should wait until the refactoring is done"--I'm playing devils advocate here. I'm interested, how you justified it before the management if you had one)
- mbrodersen 5y agoI never asked permission to do it. I consider refactoring to be part of my job. Small refactorings I do right away when implementing a new feature. Large ones I split into many small steps and work on for months in-between working on new features. Never underestimate the power of making a small improvement every day. I make sure that the long term refactorings never breaks the system or introduce new bugs. I have solid tests in place making sure changes doesn’t change behaviour.
- rawoke083600 5y ago>upfront designing their programs instead of just jumping in. >This has taught me the lesson to always first try and think things through and come up with some kind of initial design, instead of just jumping in and writing code blindly. 100% One of my favorite techniques is "Super Pseudo Code" ! Why SUPER ? Lol cause the "pseudo code" I write can barley be called "code at all" - It is usually just a text-file with a bunch of loosey-goosey-function-calls and parameters. You know just to get a "feel" for how different entities(classes,struct,tables or libs - pick your poison) will interact and what might be needed. We not talking any UML-Diagrams here - really just text-files and functions/entities This also works super-well for any multi-step-processes.
- mpartel 5y agoThis is true for early high-level decisions. For every-day coding of smallish components in a large project, it matters much less. The more code your design decision will affect, the more up-front planning it deserves.
- skohan 5y agoI would argue if “high level design decisions” are getting in the way of coding, this is a sign of over-design or premature abstraction. If you write sufficiently loosely-coupled code, it’s not hard to re-organize later.
- mpartel 5y agoSome examples of high-level decisions: - which web framework? - which database? which ORM? which transaction isolation level by default? - will this game/UI be multiplayer? - what's our testing discipline? You can't loosely couple around questions like these most of the time, at last not without excessive abstraction. For "how do I structure this reasonably isolated 0-1kLOC component", I agree, easy to fix later if needed.
- skohan 5y agoI think there are always ways to minimize coupling. For example if most of the code you write is pure functions operating on values, then swapping out your ORM might be a bit laborious, but it's going to be largely just a matter of typing, not tricky problem solving. And like for example if you want to change web frameworks, that's something you can do incrementally. If you're talking about front-end, just find a way to encapsulate your old code behind a clean interface and start implementing new components in the new framework. If you're talking about back-end, then you can just implement new endpoints in a new language if you want even, and gradually migrate things over when you have to modify them.
- CipherThrowaway 5y agoI think this is the kind of thing you learn at uni and then potentially unlearn later on. Over the years I became better at using code to explore problem spaces and as a design tool. Nowadays I feel that incremental design delivers better results in less time than upfront design.
- marcos100 5y agoI think your incremental design delivers better results because you already know or at least have a hunch of what wouldn't work and avoid that. You have an abstract architecture when starting and change accordingly on the fly, while programming, using your own best practices. Top down and bottom up architecture have their places. Being extreme in favor of one side is usually bad, as almost anything in life.
- skohan 5y agoI'm just having trouble understanding what you're talking about. Like what would be a concrete example of how a poor up-front design decision would paint you into an unrecoverable corner?
- kaba0 5y agoMy experience says that you might not need much design for a typical CRUD app, but try to write a JVM/compiler/database and you will quickly see that a bad design pretty much aborts the given project and you have to start from almost scratch. There is no incrementel rewrite between different stack/heap handling as those are an absolutely central parts of the design, which are pretty much impossible to try to encapsulate, as opposed to the 34th API endpoint. So what it means is that certain domains have much higher essential complexity and at that point the average encapsulation given by OOP/language tools are not sufficient to contain these parts, complexity will triumph and the whole program has to be viewed as one unified whole. Concurrent applications are a similar can of worms.
- skohan 5y ago
- bschwindHN 5y agoWeeks of programming can save you hours of planning!
- skohan 5y agoYou can also spend weeks trying to solve a problem on paper which can be solved with hours of experimentation
- agumonkey 5y ago> As they say "measure twice, cut once". and also the reuse of the term architecture.. don't put beams at random and see if it works, plan in advance and calculate. They probably had these realizations thousands of years ago, it's a generic economy principle. I forgot what the saying is but solution unfold themselves when you thought about the problem long enough. Oh and lastly, Grothendieck said he wasn't in the business of solving problems, but expressing them.
- skohan 5y agoIf architects could freely reposition beams in a building, they might take advantage of that fast iteration rather than spending a lot of time calculating up-front.
- agumonkey 5y agoI think it's antithetical, their profession exist only to avoid moving complicated stuff when it's too late. Of course architect can design wrong and then it's costly too.
- bobthechef 5y ago