When I'm prototyping or hacking something together, I don't write tests, I don't comment/document much, I use lots of shitty variable/type names, lots of commented out code, debugging printfs, not much organization of files (often one large file).
The prototype software is write-once, read-maybe. Maybe I'll want to see what I did down the road, but more likely I'll be shortly rewriting what I did somewhere else, using the fresh state still in my head.
That next thing? If it's meaningful in any way and I want other humans (or future me) to expose their sight-orbs to it, then it'll be "clean code" to the best of my ability. While users won't care what your code looks like, they DO care about bugs, new feature turnaround, and downtime, all of which are exasperated by shitty code. You don't want to be staying up late on the weekend unfucking something you fucked up three years ago.
Don't write shitty code for other people. That includes future-you.
Due to that, I write my first line of code as if it's going to be on production forever, because it will.
When I'm at the prototyping stage, I don't yet know how to solve the problem. That means I need to iterate quickly, which affects my choice of language (Python) and the amount of time I'm willing to spend keeping code clean (very little, because I could hit a dead-end at any point).
But once I have a working prototype of a solution, my users need it in the form of a fast, standalone binary, and my colleagues need code that can be easily understood. This requires using a different language (C++) and more disciplined coding practices. The only way to get this is to rewrite for production, and then "throw away" the prototype.
I did it a lot through university. If you have no experience tackling a certain type of problem, your perception of it tends to change significantly as you build the solution and become familiar with the problem space. It makes sense to throw away what you've written, because most of it was based on assumptions that were wrong.
Other companies take ideas, consider them long and hard - and usually follow other orgs doing something similar who have already proven something works. They do a lot of planning and tend to put much more funding in up-front.
Both approaches suit different businesses. The former being startups and SME's, the latter where market share is already won and now they just acquire other businesses that develop the former way.
If we're considering what people develop at home however.. 99.9% of the stuff I write is never publicly visible, and it's terrible because I'm not a great developer. But I'm not a regular open-source contributor. I issue the occasional patch for shit that's broken for me.
The original waterfall paper[1] advocated for doing an initial version, by which point you'll have understood the problem domain (in miniature) enough to make a better attempt by throwing it all away and reassessing what tradeoffs make sense.
> Without this simulation the project manager is at the mercy of human judgment. With the simulation he can at least perform experimental tests of some key hypotheses and scope down what remains for human judgment, which in the area of computer program design (as in the estimation of takeoff gross weight, costs to complete, or the daily double) is invariably and seriously optimistic. [2]
The myth goes that someone in the Department of Defense looked at the first diagram (which the author claims right underneath is flawed), copied it in a rush for a diagram and that became enshrined in history as "How best to develop software" until agile and what not
[1]: http://www-scf.usc.edu/~csci201/lectures/Lecture11/royce1970... [2]: Page 7 of the above PDF
To me, "I write my first line of code as if it's going to be on production forever" means setting up a testing infrastructure, a reproducible build that can be automated, a CI that runs my tests. An auto-commit system where I can create a PR and submit it to the CI and if it passes it will automatically get merged to main, etc...
Instead of my lamp project taking 1-3 hrs it would have been a week of setting all this up before I was ready to write my first line of actual code.
Are you saying you'd actually take that week? Would you therefore never write something on shadertoy because it's missing all that infrastructure and you can't write code as if it's going to be in production forever?
All of the worst production systems I've worked with are systems where people are running code from many many years ago because they don't know what it does and are scared to touch it.
Write one to throw away, even - perhaps especially - if it goes into production. Write production to throw away.
Have you ever had that moment when you say: "Oh damn, now I got it! I should do it entirely differently!" — and then you code up a different approach, the approach that works well enough.
If you had this moment, it was the moment of throwing away the prototype.
It's not worth doing things "the right way" right off the bat because you might not know what that is. My first version was literally a linear file of statements and console output.
Once I got something working and understood the problem space then I could back and fix it up. The final code looks like nothing like the original prototype although at no point did I actually throw it away -- I just transformed it heavily -- but the theory is the same. It started as a console app even though the final product was not one.
It's not the holy grail of software development but it ain't shitty code either. Also I tend to use only one web framework - FastAPI, one database - mostly Redis or MySQL and one front end React. Saves a ton of time as I can reuse a most parts of the code.
I do think there is a lot of merit in using something like GAE. Saves a boat load of time but comes at a cost and I am willing to bear the cost to save time.
It will be the product. They will start selling it straight away. If there are any problems, you, my dear young and foolish friend, will be the one at fault. It is your wonderful self that will staying up all hours desperately trying to fix the problems.
Otherwise peachy!
When you write that awesome prototype, your management will be thinking about rewarding you, not blaming you. They will listen to your concerns.
So, you can say that it's not ready. You can mention that you alone are not enough to fix the bugs that come up in greenfield code right away. You can even ask for people to help on your project. Why would management say no if they want to sell it?
Then when a manageable amount of bugs come down the road and everybody is happy, you are now in a far better position to negotiate a higher salary. You have far more responsibility. You have a great track record. Nobody wants you to leave.
The cost of developing a prototype when you handle every error you see along the way, set up all of those dev tools (tests, logs, CI, formatting, etc.), and test every branch like a madman is too high. You'll probably end up taking weeks to develop something that you could "code in a weekend". Then, since you never verified, it may turn out that nobody wants to use the prototype for obvious reasons
That also goes for your REAL goals or technical debt or other list of minor-todos you've created. They will meddle. They can't help it. Only give status/etc for clear goals.
Kind of like the driving test. Of course you don't break the speed limit pass the person weaving in the lane ahead of you. (but irl you do, and you should)
- I paper prototype until we have something that makes sense, fills the space our crew sees an opportunity in, and seems to do the job without needing too much work to implement. Takes about half a day to a day of "what if we did this" and "how about that" scribbling to do this if everyone's available and focused, and then we discuss what we have and whether it works for us and whether we actually have a business or not.
- Next, I spend a day or two thinking: What architecture makes the most sense? What language makes the most sense (in terms of what it can do for us and how many people know it)? What technologies will cut away the most work without requiring a lot of shoe-horning? etc.
- Next, I write the minimum within that framework to get a visual prototype that allows us to go through the various sections and see it in action.
- Next, we look at this prototype and decide how closely it matches our vision, and whether our vision needs changing.
From there, the most common changes to the actual code are tweaks to systems rather than the whole architecture, but the architecture itself makes this easy since it's designed to be modular for our particular use case.
I actually can't think of a single prototype that I've thrown away to rewrite in the last 20 years, including a complex 6-minigame educational product I brought from zero to live-and-generating-revenue in the app store in 3 months as the only developer. Clean code isn't for your clients; it's for YOU and your team. Clean architecture, code and discipline make your work go easier and faster IF you actually do it.
If you're starting with code prototypes rather than paper prototypes, you're doing it wrong and it will take you longer as a result (and you'll probably also need a rewrite).
"aaaand, I'm going to need to pull you off of this xyzzy, and put you on this high-priority-showstopper-stop the presses project ..."
and then 10 years later you're writing this blog article where you explain where someone else shipped unfinished code and ...
I think a good team or a good partnership comes from finding one or more other people whose strengths offset your weaknesses and vice versa.
But seriously, they call it "tech debt" for a reason. It's not a problem until suddenly you're no longer able to add needed features to your project, because every little bit of development takes hours and weeks and months.
There are so many posts about how "Engineers Need To Learn About The Business," and yeah, it's helpful sometimes, but really there are different types of jobs. Some jobs require the engineers to understand the product and business rules, and other jobs need engineers with deep technical engineering abilities. There's nothing inherently better or worse about either! What's bad is if the job is one type and you are the other type. (Similarly, you think you want to be one type, but really you want to be the other type).
So go ahead! Fiddle with an esoteric language or framework, because there are plenty of open positions that need you.
"The metaphor of debt is sometimes used to justify neglecting internal quality... Teams who do this end up maxing out all their credit cards, but still delivering later than they would have done had they put the effort into higher internal quality."[1]
"the whole debt metaphor, let's say, the ability to pay back debt, and make the debt metaphor work for your advantage depends upon your writing code that is clean enough to be able to refactor as you come to understand your problem"[2]
"write the best code possible given a partial understanding of the problem so later when you do understand it better you improve the solution"[3]
1. https://martinfowler.com/bliki/TechnicalDebt.html
It also disregards that developers who care about clean code do exist, such that the title becomes merely metaphorical, and is more accurately rendered as "users don't care about clean code".
Except that they do, they just don't know it. Time to new features and time to bug fixes (both of which users do care about (though, of course, not unanimously)) is inversely proportional to how easy a codebase is to navigate and understand (read: how clean it is).
Finally, all software developers (or all workers?) prefer their work to have a high ratio of accomplishment to drudgery. The primary benefit of clean code is developer quality of life, as indicated by the nascent field of DX (Developer Experience).
I would, in fact, guess that its code is much cleaner than the average Fullstack Javascript app.
If you're capable of writing a full, functional website in one PHP file, you know what every line of code does, you have only what you need and the ways to factor your code become more obvious.
Using the "modern" Javascript stack usually means that you had to spend months or years trying to learn this mishmash of Javascript libraries (React, react-redux, Express, an auth library, an ORM, etc.) and you don't know what most of those things do under the hood.
The lesson I take away is: Simple (PHP + Jquery) can be better than complex (React, Redux, Express, Passport, etc).
The learning curve right now in JS is ridiculous. Onboarding developers is hard. We wrote a new project in ember js and threw it away for react.
Sometimes new tools, like Ruby on Rails, make it way easier to get started. Not so with JS. But I'm sure you get a lot of dynamic rendering power to make up for it
PHP is too easy to get started with and let’s you do some truely horrific things trivially.
Package your code down into small, atomic and reusable units
Follow the single responsibility principle
Use frameworks and libraries to avoid reinventing the wheel
Whatever language you pick, don’t pick PHP
These are best practices. It is possible to follow every one of those rules and still have a pile of broken, insecure, garbage code. Likewise you can have a very elegant one-liner that fits none of those and gets a job done cleaner and easier than any alternative. You can even have a single page app that fits most of those, and I would argue that it would probably stay cleaner without adding a framework. Frameworks in many ways bind you to a certain style.It's all about keeping the scope of what you're doing in mind and using the correct tool for the job. Saying "this tool is better for every job" is going to get you a lot of arguments.
Also, with the exception of the third bullet point, you can follow all of those practices and still fit your app into a single file. There is nothing more frustrating than working on a codebase that puts 12 lines of code in each file and then spreads that code into 1,000 files.
And the final bullet point in regards to PHP is just false. But I digress.
There is nothing more frustrating than working on a codebase that puts 12 lines of code in each file and then spreads that code into 1,000 files.
In other words, "Enterprise" code, which is in my experience usually designed more to hit all the "best practices", and often according to the opinion of some idiotic tool (as in computer program, although sometimes a person too...), than do anything sanely.
If the original developers have moved on, and the current developers do not have a good handle on the software, there could be some troubles making changes.
What if we approach the problem by structuring the code and choosing names to better reflect the business terminology. Make it such that a business person could understand the software at high level.
Then years later, it becomes much easier for a new set of developers work with the business side to make enhancements and changes.
The adage "Move Fast and Break Things" is a cancer on the software industry. I've personally had the displeasure of working in numerous teams, departments and companies that adopted such silly philosophies in the pursuit of being "innovative". I've never seen it work in the long-term in a single instance. The cost of such mistakes are easily quantifiable. I'm sure most people here can think of fitting personal anecdotes where they've seen entire codebases rewritten to make them into scalable, maintainable solutions. Even this article lists several examples which attest to this. I shudder to think of the amount of money that has been invested in migrating codebases away from NodeJS, or MongoDB, for instance.
> "...or grow in a steady, sustainable and healthy pace and be eaten up by competition..."
Implying that it takes an order of magnitude more time to make responsible technology choices, or to write tests? This is rubbish. A stitch in time saves nine. I've never seen an instance where better management, better planning, and more responsible development couldn't have prevented a project from needing to be rewritten in twelve months.
But indirectly they actually do care because if the config files for Bind are maintained well then there's less room for human error and ... that contributes to overall stability of the service.
You can feature bloat something up to a certain point and then.... kaboom goes the rewrite. Hopefully into clean code, but usually not since clean code is a culture and mindset, not a code base.
This is like saying “no one cares about training for a marathon, they only care about running a faster time”
Well, sure, but up the WAY you run a faster time is to train. You need a technique and strategy to accomplish the actual goal.
this is like telling a mechanic that people don't want them to maintain their cars, they just want a reliable car that won't leave them stranded
also, why does a php and jquery app mean it isn't clean? the better takeaway is that customers don't care about your stack
Even if you had anticipated that these additional requirements were likely, preparing in advance for their possibility would often mean over-engineering for the initial requirements, which would likely delay the initial release.
If there wasn't a genuine conflict of interests here, we would not still be wrestling with it.
Messy codebases and bad architecture quadratically drive up the cost of development time. I've experienced this countless times for over 10 years, and it's endlessly frustrating.
The state of web has gotten so tirelessly messy, I had to write my own framework to return to the clean web architecture we once had. And my clients love it, even if they're not directly aware of it, because everything takes less time (and therefore less cost) to build.
"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
I'll just add that the psychopath in question might be your own future self.
One example where I have experienced the benefits of a clean codebase is when onboarding new developers. It takes a few days of handholding but once they've started working with the code there's very little room for gotcha situations where they get stuck or inadvertently introduce bugs due to being misdirected by the code that was already there.
My employer started quickly and grew exponentially ... but ... our client requirements didn't stay fixed. What were N pieces eventually had to be integrated because clients didn't wanna hear subsystem N1 works with N3 but not N5. And after around 10 years a lot of that code became debt, and the company has had to fix/remove/evolve it while it works in production for any number of reasons: it's too slow; it doesn't scale; we relied on vertical scaling and that's long dead; can't know or can't well manage capacity concerns; customer A's load breaks customer B's work; the code is so over hacked it's a big ball of mud etc.. And eventually software engineering concerns become cool again. This is a long way to say that true success inevitably brings with it the need to expand and integrate. Here maintainability is a core business strategy.
Here's something else worth remembering: the old school idea of TQA (true quality attributes) v. SQA (substitute quality attributes). Nobody (minus experts) rolls into a dealer and starts by asking the steel v. aluminum mix of the block. They don't ask how mm of coating was put on the __widget_here__ Those are SQAs. They ask about TQAs: price, quality, warranty, HP, resell value, whether it has AWS, power steering etc... but if anyone of those things breaks and the dealer has to fix it or the manufacture has to do a recall, the focus goes right back to the SQAs, the opportunity defects which allows those crappy SQAs etc.. etc.. So yes the client doesn't care what's under the hood, until one day you have to because one of the TQAs is violated. SQAs are the producers/suppliers implementation to gain the TQAs. They are separated in time --- time to when the client sees an issue --- but not in cause and effect. Software isn't magic. A lot of the SQAs eventually align with maintainability for the long haul.
I feel a major problem in the culture of the programming community is that we feel the need for this kind of click-bait conviction. A bit too many blog posts fit the format "Nobody cares about your _____... Ultimately, there is no right or wrong approach."
He does this because he's the only person who works on the codebase and because it generates a lot of attention due to how polarizing this choice is.
I'd also argue that messy code is the product of hypergrowth, rather than messy code being required for hypergrowth. Purposefully writing shit code because you're "moving fast and breaking things" seems like a dumb idea.
Projects that don't care about collaboration don't scale.
In my experience, it's much easier to overbuild than it is to underbuild.
I definitely agree that collaboration is essential though!
We code for ourselves. We deliver value to the costumer. Two different things.
I'm more pissed off that my user agent (firefox) even allows this sort of control by third parties.
Users couldn't care less about the programming language you used or how beautiful, clean, modular and maintainable your code is. In fact, they don't give a crap about it."
This applies to some users, for sure, but not all. The few people on the planet who read, edit and write source code are also users.
As a user, I do care about the choice of language and what the code looks like, for a number of reasons. It tells me about how the program works. It is often the best "documentation" provided. It makes a difference if I want to edit the code. It reveals something about the mind of the author. Does this person have an appreciation for the same qualities in software that I have. Is the person careless or careful. Verbose or succinct.
Where possible,^1 I generally avoid program written in languages I myself do not use. All those Go programs posted to HN. I skip them all, no matter how good they sound. Python. NodeJS. Rust. The list goes on. I save quite a bit of disk space this way, avoiding large binaries and library installs.
1. I once commented on HN that I do not use programs written in Java and some JavaCard programmer got offended and said I was wrong because Java is in all sorts of devices, and JavaCard is running on SIM cards. That was not the point. The point was I am a user and if given the choice between a Java program and nothing, I will choose the later. The trick developers in "tech" use today is to remove user choice. (See, e.g., "dark patterns.") When choice is removed, then it does not matter if or what users would choose.
Turns out there is at least one user who does care and he does give a crap. :)
PHP won’t even fix bugs due to backwards compatibility. They worked out their sql string escape function didn’t escape properly but instead of fixing it and telling everyone to check their code, they duplicated the function and prefixed the name with “real_”.
It seems your criticism towards PHP is the use of legacy code which is kept for backwards compatibility.
No sane person in the industry writes code like that. Those who do would have had concatenated user input to SQL queries in any language anyway be it Java, C# or whatever fancies your boat.
https://phptherightway.com/#databases
In my view, PHP most glaring problem is the often outdated negative image it carries outside its industry. But that's to be expected when a technology is 25 years old while striving for backwards compatibility.
PHP maintainers do fix bugs.
I don't use PHP right now, it's not my favorite language, but I hate when people are trying to excuse their own laziness and incompetence by saying “it’s all because of tool X”.
If your service only needs 50 lines of business logic, a single PHP file probably would be easier to understand and maintain than modularizing it. (I have no idea how many lines of code remoteok needs).
Here's what I've learned over the past 35 years developing software: I typically don't care much about implementation. There are many ways to skin a cat and it's not very productive to argue amongst them. Whatever. What is important however are interfaces. Function interfaces, class interfaces, subsystem interfaces (mediator design pattern). Factory methods are also extremely important: how do I get an instance of the thing I need? These are the things that are important. How a piece of functionality is actually implemented is far down on the list of things to care about.
This assumes that your app will grow indefinitely. What if we had more apps that were considered finished?
The million dollar home page made a million dollars and was probably a single file of PHP.
Users do care about how maintainable your code is. They're often committed to your piece of software. If you code is bad, they will eventually feel it. I've experienced that with my own software over time and software built by other companies. At work, the end users know our financial system is fundamentally unmaintainable and we aren't going to buy the fancy total re-write new version from that vendor.
The other lesson is that it's entirely possible that a single file PHP monolith is not a crappy ball of mud. It might even be cleaner and easier to work with than "best practices" over-abstracted over-built monstrosity.
... But, code quality if a pretty good heuristic for "does it work". It's possible to write a working program where the code isn't clean but as the program grows and grows you'll have more and more trouble keeping it working.
In the case of remoteok.io, it's not really a surprise. It's a complete website but not a very complicated one. Post data, view posted data. Everything public. Mostly read traffic so trivial to cache.
Or the CFO when he hears about that little nasty bug hidden away in a gigantic ball of mud (https://en.wikipedia.org/wiki/Big_ball_of_mud) halting production over the SLA thresholds causing a massive financial issue.
Customers likely don't give a shit about code, but it can and probably will eventually run your org into the ground.
Hidden value of clean code: Developer's sanity and willingnses to work on it.
Code has the 'Broken Windows' problem: if it's a pile of dirt, people will treat it like a pile of dirt, and not want to work on it. If it's clean, their their work will have legacy, they're more likely to value their own time and effort.
“Our codebase sucks, we’re constantly running into issues, can’t change things. We’ll have to rewrite it all. I hate this”
“This codebase allowed our company to scale to XXX $s/users! It served us well but now’s a time to rewrite it to fit our new needs: reliability, scalability. This is a great challenge and opportunity for those working on it. I love this”
If you have a large complex system, making it clean up front (i.e. by deployment) means someone a few years from now will appreciate the work.
As for the single page app: when (if!) you want to upgrade it, just rewrite it wholesale. Until then it's creating value as it is.
Still seems crazy to have the whole site in a single PHP file, though. A dozen files (or even a few dozens) might have been saner. But then again, in that case we wouldn't be talking about the site...
We often say that we hate reinventing the wheel. But life is actually full of reinventing-the-wheel experiences. Maybe that's the point of a life.
If you actually ever plan on ever having other developers contribute to and maintain your code, or god forbid multiple teams of developers, you better have things structured in a way that they can understand.
END USERS in particular do not give a rats about clean code or the number of code reviews that have been done. They only care that it works. Technical debt, refactoring, reuse? Nobody cares except developers. The paying customer is all that matters.
Also this is the difference between a indiehacker and a SDE. Pieter is a indiehacker not a SDE.
(Unless it explodes mid-air, that is. Please don't explode mid-air. Please don't explode mid-air. Please don't explode mid-air ...)
How that in any way compares to a full blown application-in-browser like eg Figma or an infrastructure product like Stripe or a household brand marketplace like Airbnb that have to cater to various user groups, iterate at breakneck speeds and keep a triple/quadruple 9 uptime is beyond me.
1) never shipped
2) does not make money
and the site makes billions a year. the code? complete utter crap.
Written by a person that read a book on how to write a website.
It still makes billion a year.
(In case it isn't obvious, I disagree. Maintainable code lets you adapt to an evolving understanding of what the user wants.)
Some places where clean code really matters:
- The personal project where, if you can't figure out how you did something, you'll quickly get bored and quit.
- The open source project that needs to onboard hundreds or thousands of developers across language barriers in order to successfully solve problems.
- The medium-to-large startup or enterprise that needs to maintain velocity on a product line.
- The small startup that never quite hit hyper growth and needs to retain developers.
- ... many more
If you're trying to get rich quick, or quickly iterate through many different, dissimilar ideas, then writing sloppy code is fine. I'd argue that that's _not_ most codebases (though perhaps it is in the entrepreneur community).
Lots of people think they are good authors. They will write novel upon novel. L Ron Hubbard wrote more than anyone and it was all garbage.
You have new coders (less than the few years it takes to go down enough dead ends and see what works and what doesn't work) who think their code is good but it's just the worst. They are like novelists writing crap stories with a sex scene between a navy seal and a sexy scientist with big boobies.
The only good code is code with no ego but not so little ego that's it's dogmatic about not having an ego.
These last few years I've seen the barrier to entry be lowered for programmers resulting in even more terrible code written by people who think knowing Angular is the zenith of good code.
It's all bad. You can't tell them it's bad.
It's actually worse than millions of bad novelists because you have to use third party code which is also bad so even good programmers have to use bad code. There's just no winning. So while you bang your head against the wall for three days getting dependencies to work with your brilliant creation and it stretches your probably strong brain to its limits just remember your boss, who gets paid more than you and gets to think big picture, didn't have to learn ALLLL the stuff you did and doesn't care about how much you know as long as the end result is good enough.
Only idiots write software these days.