This is really an overly simplistic way to code. I urge people to think deeper up front about performance.
Know your performance goals going in and code accordingly. If you require 100 micro average latency and you coded in Node.js, step 3 will be a rewrite.
Every single line of code I write, I can tell you my performance goals. If indeed it is a simple crud screen by a user, the goal may be "meh, document.ready called when viewed from 100ms browser lag within 1 second". Backend trading code would have different goals..
Yeah, when starting a new project I tend to write a POC, throw it out, make a ton of notes on the problem and possible solutions, write a second POC, throw it out again, refine my notes, make sure i really understand the problem and my solution is actually working, and if everything looks good, write it "for real".
The management question, therefore, is not whether to build a pilot system and throw it away. You will do that. […] Hence plan to throw one away; you will, anyhow.
Then the problem is an academic endeavor and hopefully not something to be sold to a customer. If it is open source, then it is likely to fall into disuse like 99.9% of open source endeavors. If it is in the 0.1% of open source projects then the community will find the effort for a rewrite, but it could be painful like python 2/3 or perl 6/7
I usually iterate. Building upon what was already built.
All to often a 'prototype' becomes the finished product without the intervening iterations. If that was the plan from the start it works more smoothly.
Exactly. Completely ignoring performance considerations until after you got everything working right potentially means a substantial or complete rewrite of much of the code.
My posit was that 80% of the software an engineer will write will not require optimization and based on the responses i've been getting I should have used "rule of thumb" vs mantra. My intention was to warn the ones that read this and say, oh i gotta do all of this for every piece of software that I write, which will undoubtedly lead to overly complex code when a simple solution would have worked just as well.
"Know your performance goals going in and code accordingly."
I this is key sentence here and its worth repeating. Know your performance goals before your fingers touch the keyboard.
> My intention was to warn the ones that read this and say, oh i gotta do all of this for every piece of software that I write, which will undoubtedly lead to overly complex code when a simple solution would have worked just as well.
No that is not true at all.
I am writing a crud app to be used by 1 person, some manager of a widget factory. I say "my perf goal is to have page loads in 10 seconds or less". How will that make my code more complex? If anything it will make my code MORE simple, as I can relax all kinds of constraints like "making 72 database queries per page is generally bad".
I believe the GP's point was that if you know that your performance goals are very relaxed, then you can make the code appropriately simple from the beginning. Conversely, if your performance goals are stringent, then you can take an appropriate approach from the beginning.
I disagree completely with your 80% number. I haven't worked on a project that had 0 performance work ever.
Performance is a first class design constraint just like development time, budget & functionality, if you don't treat it as such from the beginning you are asking for trouble.
But different parts of a project usually have different performance goals. Typically just the important/frequently used parts need to be optimized. Infrequently used things (maybe setup, admin interface, options dialog) can usually just be "good enough."
So one could say that within a project, 80% of the code isn't performance critical.
No kidding. Who ever said anything about not knowing what the requirements are?
The point you were disagreeing with here was "80% of the software an engineer will write will not require optimization". ie, 80% of any given system hitting the performance requirements naively. So... why are you still arguing?
Because blind adherence to the "Make it work then make it fast" advice has been the bane of my career.
Generally speaking, I have not found it to be true that you can make something fast if you didn't think about performance first. If you thought about it, and came to the decision "it will be fast enough no matter what we do" bully for you, but for me that happens way less than 80% of the time.
That's all well and good, but still "make it work" should always come before "make it fast". For example the code I'm writing right now in my other window is terribly inefficient, quite naive and may very well have to be re-written, but I don't care at the moment. All I care about right now is: Is what I'm trying to do actually practically possible in the general case. If so what approach will give the best/good enough results. And finally, if I manage to do what I'm trying to do, will this particular approach offer a better solution to the higher level problem I'm dealing with than my other approach.
Once I've answered "yes" to all those questions then I can think about heading back and trying to make it fast. Writing really high performance code that doesn't solve the problem you have or give you the results that you need is, of course, a waste of time.
You misunderstand "make it work" includes performance goals. The difference is if you consider them upfront it includes the explicitly not implicitly.
You'd never say that the you've made the code "work" if you knew it would take 3x of your budget to get there. Similarly with performance, it doesn't "work" if it doesn't meet the perf goals of the project, no matter how relaxed they might be.
I guess we're arguing semantics at this point. For me "make it work" means that I'm able to write a piece of code that takes the input I want and returns the output I want eventually, doesn't matter if it takes a week instead of a minute to run. Before I get to that point then any optimization I do is probably not the best use of my time. Also if I can't get to that point then it means I really don't understand the underlying problem and I'm probably not in a position to start reasoning about making it fast.
Generally speaking I find it much easier to take slow, working code and making fast, as opposed to fast, broken code and making it work.
Generally speaking I don't. The only way I've ever been able to be successful on the performance front is to conclude that code that is slow is broken, not that it is working before then.
Backing into acceptable performance after the fact just doesn't work for the problem domains I work in (which on first blush have not been exclusively performance based).
Even better is: Know your performance goals going in and choose your tools and approaches accordingly.
You still mostly want to follow the rough priority above. You absolutely may prototype to convince yourself a performance goal can be met early on, but if the goal is high performance code you are still far better off making the first pass for correctness. Skipping this step often leads to highly performant code that is wrong, and is a pain in the ass to debug.
The "make it work, then make it right, then make it fast" mantra is both overly simplistic and deeply true.
How do you know the speed expectations? Do you always talk concrete numbers with the stakeholders before each change you make, or just use reasonable rules of thumb you determine?
Not before each change but before any major new initiative or refactor. Having those numbers up front is the only way to make appropriate trade offs.
Having this conversation with stakeholders often educates them on the costs of performance as well. Getting 100% of responses sub 200ms is frequently orders of magnitude more expensive than getting 99% of them there, and stakeholders usually get that fast when you show them budget info.
Replying to the second paragraph, there often is a real value in maintaining strong upper bound for the latency, especially in distributed real-time systems (which are most of the real systems, anyway).
E.g. (99% sub-200ms and 1% _unbounded_) vs (80% sub-200ms and _always_ sub-500ms) means 1% of potentially unanticipated crashes (a hell to debug and explain to customers!) vs a highly reliable system and happy customers.
For sure, thats the definition of a real time system after all. But having conversations about what the long tails do to the "normal" path and what the costs (both in money and performance in the "normal" path) is quite simply something that you can't back into.
Maybe I didn't understand you correctly, but you can at least have a "return error on timeout" and process that with a predictable logic. Or maybe you do have an architecture when any individual tardy request absolutely cannot impact others. After all, I come from stream processing systems where there's only few "users" with constant streams of requests, and these users are interdependent (think control modules in a self-driving car).
What I'm suggesting is the decision on what you do in the case of long tail performance problems, is not something you can back into.
If you are going to have timeouts with logic, that has down stream implications. If you are going to have truly independent event loops, that is a fundamental architectural decisions.
None of those things match the "make it work, then make it fast". You literally have to design that into the system from jump street as it is part of the definition of "works".
Except I also see crud apps that take 8 seconds to load, and you can't just fix it with a cache. EVERY app has performance considerations. Literally every app. Some may be very loose.. but then spell it out, and use that to think about it.
If you're following basic REST guidelines regarding idempotency then, yes, you can "just fix it with a cache." That's the whole point of the guideline. Updates can still take awhile, but you can fix that if you need to with a backend jobs server.
Performance should always be in your mind somewhere, but it doesn't always need to be at the forefront.
Unless it's taking 8 seconds to load because your user is on 2G. Then the only way you can avoid that hit is by not making the requests in the first place.
Know your performance goals going in and code accordingly. If you require 100 micro average latency and you coded in Node.js, step 3 will be a rewrite.
Every single line of code I write, I can tell you my performance goals. If indeed it is a simple crud screen by a user, the goal may be "meh, document.ready called when viewed from 100ms browser lag within 1 second". Backend trading code would have different goals..