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.
When I'm prototyping or hacking something together, it eventually becomes production. I cannot relate to people who make prototypes to throw away, I've never done it, and I don't know why I'd do it.
Due to that, I write my first line of code as if it's going to be on production forever, because it will.
> I cannot relate to people who make prototypes to throw away, I've never done it, and I don't know why I'd do it.
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 prototype in C++ all the time. And then refactor it to production code if it makes sense. Switching between languages seems like a waste of time to me.
I can program in Assembler, C, Java, C#, JavaScript, Typescript, Ruby, Haskell etc. And there is zero empirical evidence that Python is “significantly” more productive in the short term. My guess is that it is only true if you don’t have much experience in any other languages.
when writing complex algorithms the best approach is usually to write pseudocode, just literally write comments that explain what you are going to do in that particular block of code but not actually code it at all. that lets you build the mental model of how it's all going to work, but without any of the overhead of actually writing code. then write the main algorithm but leave some functions as stubs, just name them and have an idea of what they're going to have to do. then finally you go through and write the low-level details.
using python is both unnecessary and counterproductive. variable names don't take hardly any time at all to type, the logical design is what's actually challenging, and python isn't going to help you understand what needs to be written faster, especially compared to just writing pseudocode.
using python because it's faster for design iteration is a lot like a coder who uses a dvorak keyboard because it lets you type faster. The actual difference between two programmers of equal skill using two different languages is, by and large, nil, because the actual act of typing a program is barely any of the time involved at all.
but on the other hand it does make a massive difference in the long term in code maintainability. having to read someone else's code, especially bad code from someone else, and figure out what goes in, what happens with every variable assignment, and what returns back? Python doesn't give you any hints there, everything is established by programmer convention particular to your specific codebase, it's a mental load on top of the actual programming itself. And sure there's IDEs to help carry some of that burden, but IDEs also make developing statically typed languages a snap, and IDEs for statically typed languages can be even more powerful with their refactoring tools because they can make more assertions about what is going on in the code they're working on.
there's a reason that basically any large codebase that starts out as dynamically typed realizes their mistake and hacks in static types after the fact. Facebook was written in PHP, then realized they were screwed and created a typed dialect of PHP called "hacklang" that they gradually rewrote their codebase into. Microsoft realized their Javascript was turning into a mess and wrote TypeScript to get types into their javascript. Same thing, it's a superset that lets them run their existing codebase while they port but port their existing code and write new code with types as they go.
Once you get a non-trivial codebase, the benefits are just too big to ignore. It's fine when you wrote all the code yourself, and you know how it works and it's all up to your personal quality standards, but once you have to start working with other people's code the regularity imposed by a statically typed language is just too beneficial to ignore. And that's what Microsoft and Facebook and others have all found out in practice. Small, highly skilled teams, sure you can do whatever. Big corporate teams with coders of varying skill? Types help.
Now, what do you do if you're not Facebook or Microsoft and can't afford to implement a whole new programming language/toolchain/etc to fix a bad choice of language? Make better choices up front.
dynamic typing is the dvorak of programming languages. it sounds super cool, and everyone hates verbose java 6 code, but it's just not a productivity boost in practice, in fact in the long term it's the opposite. Best case it improves on something that's not a bottleneck, worst case it actually reduces productivity in a large codebase, and that's the experience from Facebook, Microsoft, and other big companies with good engineering teams.
but the dynamic vs static typing is an age-old slapfight and nobody's mind is going to change.
python still has syntax and still requires you to actually write code. your trite meme aside, python is not actually executable pseudocode, and writing actual pseudocode is still faster and requires less specificity (therefore less mental overhead).
you're welcome to do whatever you want, but I'd rather do a pseudocode outline and then fill it in and have a statically typed program when I'm done, than to do a first-pass python program that is written as I go with no pseudocode.
again, the actual act of typing the code is a pretty insignificant part of development, what really takes the time is debugging all the edge cases and maintaining it for the next few years, and that's where static typing gives you a bit of an advantage. python is very much like the programmer bragging about their dvorak keyboard, it just doesn't improve on a part of the development lifecycle that is a particular bottleneck, and it does pose disadvantages down the road for maintenance and collaboration on a larger codebase. A little mandatory structure (not too much) is indeed a good thing when you have to work with other people's code (including past-you code).
And jeez, "ignore at your own risk!", maybe not intended but you just come off as dismissing a substantiative argument with a meme and a condescending dismissal.
The difference in productivity is substantial. Prototyping in a Python-like language and then porting to a more difficult but safer one has also shown good results as discussed in the rest of the thread.
Any condescension implied is a result of your long-winded rant of inexperience.
go run main.go works just fine and is blazing fast compared to many compiled langs.
There's also scripted go, which may solve some of what you need.
Print debugging works for 99% of introspection needs. Most times go does just as advertised, though learn of common pitfalls to avoid.
Haskell has REPL and dynamic introspection, but everything takes 4-20 longer times. Maybe it's faster/better with massive practice.
Honestly, most codebases just sucks, including my own, unless you redo alot and put deliberate efforts over time. Which is irrelevant to sales (point in link). Alot of value in battle-tested code turns invisible too, locking knowledge away in obscurity. Go at least is pretty readable and mostly explicit.
REPL with hot-loading is better than print debugging, especially if you work with graphics, but also if you do weird stuff in the memory space than make strings unreadable for human beings.
That said, gdb is probably in the same space as git is: hard to fully use, but the best in its own space.
I envy your use cases, but it's 25 years since I used debuggers. I just didn't have the use case.
With Haskell being a tough nut, maybe it could help though. So may as well try it.
I found git trivial to start using immediately, and almost possible to understand from first principles (ie. almost like versioned subdirs improved). It's a bit more involved, but with right online content, one starts to catch on (leaving magical thinking).
>I cannot relate to people who make prototypes to throw away, I've never done it, and I don't know why I'd do it.
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.
You do it to understand the problem you're working on before you start writing production code. If you understand the problem you're working on, there's no need for prototyping, which is probably true for most code an average programmer writes. I tend to write prototype code to learn how something new works before writing production code, or when I have multiple ideas how a system should work and need to iterate on them and pick what I should actually ship. If you know you need to build a specific feature and how it should work you don't have to prototype it.
Depends on the company environment. If your company does MVP's regularly to trial out stuff or features to get projects funded, they're more than likely will fund a short sprint to prove the concept or idea works and gauge if it's worth fully funding. These orgs move fast, have lots of tech talent and budget. They're usually ahead of other companies in terms of features or offerings.
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.
I did exactly this recently at work. I had a feature set I've been wanting to add to the customer service portal but very little time approved so we built a part of it using very little dev time. The feature was very popular and well used. Everyone wanted it expanded to do more (basically a task system which saves people from ad hoc management of various tasks). Before too long, the full version was approved and was built in very short order because of lessons learned with the mvp.
> I've never done it, and I don't know why I'd do it.
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
So I just hacked together an animated LED strip lamp on an Arduino. I didn't write any tests or setup production. What would you have done?
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?
Then write your code as if someone's going to throw production away - which generally means writing documentation (design docs, good commit messages, comments on the tricky parts of the code, API contracts between components, etc.), so that if someone thinks they want to to reimplement production, that decision can stand on its own merits.
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.
Currently on a project initially written with throwaway code. It became a production project. The code survives to this day and we don't dare poke it too much.
This. However for the last while I’ve been using a language on the front end that let’s me prototype ideas with a slightly higher up front cost and then when it ends up in production it’s close to bulletproof and easier to refactor (not that I always get the chance, but I still feel safer knowing it probably won’t break).
Then if the code / project / product refuses to die (success!), I can come back some day and refactor without being scared to dig in again.
So even though my original code is a bit messy, I’m not scared to change it a couple years later.
> I cannot relate to people who make prototypes to throw away, I've never done it
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.
Yes, but this often occurs a few months or years into production, way too late to throw it away.
I've never written a prototype, nor seen one written, in actual businesses. I've never had an employer with the patience to let me play with a prototype either.
Maybe, but then the previous one was version 1, not a prototype. I've never seen people actually write prototypes, nor management accept time invested on writing prototypes, in any job I've had.
Prototypes always directly become version 1 on production, unless of course the whole project gets canceled mid-development.
I've seen rewrites introducing massive bughunts and upsetting customers without improving too much. I've also seen customers expecting and even relying on old bugs for comfort.
Rewrite is always a business decision and need legitimate reasons. You rarely have those reasons, knowledge and time between projects.
When I was working on this https://codaris.github.io/UnderDeskBike/ I honestly didn't know if what I wanted to do was even possible at many layers. I didn't know how to do Bluetooth. I knew nothing.
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.
This is really how all new code is birthed. You start build something from no prior knowledge and few assumptions. It gives maximum agility and freedom to pursue multiple paths initially.
Well the other way to approach the problem is to basically craft out a whole framework: create classes/interfaces/tests and slowly fill them in.
Occasionally I will code that way when I'm fairly certain of what I'm doing but you have to be very careful that you're not painting yourself into a corner.
In my experience, new programmers tend to build a lot of structure for their code that it's not clear they even need yet or will ever need and then often end up solving a problem with much more code than was necessary. It's usually my advice to get something (anything) working end-to-end first and then expand on that rather than the more linear approach.
I have done quite a lot of prototypes and while the initial ones were throw away code, I quickly realized that I can re-use a lot of code in future prototypes. Especially code that involves building user management and database access. Also realized it is frustrating to write repeating code. So I quickly started making code slightly more readable and reusable.
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.
Same here. As I learn more and find better ways to do things, I simply spend a few minutes refactoring the code to improve it. I also program to interfaces so that subsystems can be completely rewritten/refactored with only local impact.
I use to write a prototype and rewrite, before I worked in startups. Now days I write once and it’s in prod within a couple of days. It has taken some adjustments, to be sure, my first ~6 months was full of submitting little mistakes that I normally would have caught in the rewrites.
I rarely prototype but the scenarios where I do are in the game engine context where I’m trying to hack together a real time graphics algorithm, meshing algorithm, etc. The difference between a one second and 15 second iteration time is meaningful.
I would recommend you try writing hacky code and then throwing it away and starting from scratch a couple times on the same project idea, just to see how it goes. It might teach you something.
The people I know who regularly take this approach end up with a really fantastic code architecture in the end, and avoid a lot of pitfalls from their first naïve attempts.
When dissatisfied with an approach I'll often copy a class/function or three into new versions. I'll append the names of the old with 0. Then I start writing new ones with the new approach. In effect throwing the old ones away, even if sometimes it is a gradual process.
This happens frequently in a new project, less frequently in a maturing project, to never in a maintenance project.
However, it has a lot in common with (a severe) refactoring. Generally you're keeping the "overhead" docs, code, and even files, so it is not a complete rebirth, perhaps ~30% of the core code.
Not a good idea. That is not a good idea of you let anybody in a management role see your prototype.
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.
I do not understand how you cannot easily "spin" a prototype that the company wants to sell into a good thing.
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
Spin? My leaky, fragile, missing important parts, flaky prototype has been sold for a lot of money and is now supporting business decisions.... Spin? Like tail spin....
When the prototype explodes in exactly the way I expect it to management are not going to reward me...
I said it is not ready. Several times. To the point where management stopped taking my calls.....
Manageable amount of bugs? There is a problem of definition here.
The cost of developing a prototype that demonstrates the interesting and cool parts of the project - whilst leaving the tricky bits for implementation is my job. So I gota ask: that cost is too high for whom?
> hat is not a good idea of you let anybody in a management role see your prototype.
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)
One of my interns thanked me several years later for what he said was the best advice he ever got from a mentor: learn to recognize when a project is about to collapse under its own weight and get out before it does.
- 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).
Wanna know what? Amen to that approach. Nothing like throw away papers and throw away prototypes. Nothing like getting the team on the same page --- more grounded in reality than chit chat or PPTs or bubbles and arrows --- while not under pressure to cross Ts and dot Is.
I'm still teaching myself full-stack web development but I've worked on a couple of projects with a friend who has a great amount of skill and experience. I was slightly horrified to see the kinds of haphazard and occasionally mildly crude comments he was putting in code and git commits, especially since I am very much a perfectionist, but... he gets the job done, and he gets it done well.
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.
Honest question - does that really make you finish up prototyping faster than having SOME level of organization? Unless I’m coding something so quick that I’ll be done in the same couple of hours, I feel like at least having some sensible names for things, some comments here and there (in particular TODOs), etc helps think (and prototype) much faster.
I do understand the sentiment. However I do think there is something to be said for maintaining good habits all or most of the time. It’s kind of like saying I eat trash all time, but when I need to get in shape, I can stick to a diet. Easy to say, hard to do.
Then also the core parts (with many dependents) deserve more elegance and readability compared to some less critical side module that can easily be thrown away and replaced.
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.
Except that technical debt is not about writing bad code, and the author of this article gets it completely wrong.
"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]
Weird post. The main insight is easily captured by the phrase "technical debt is a resource, not a vice".
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).
Technical debt not only makes it harder to add features, it makes it harder to remove technical debt and make technical improvements. Choosing not to pay down technical debt is fine, but at some point it will be such a mess you won't be able add features or fix the technical debt issues without a total rewrite scale project.
The fatal flaw of this article is assuming that having a single PHP file implies ugly code, or at least uglier than the average codebase.
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).
I've spent some time trying to pick up modern JS tooling. I used to code JS back in the early days of JS and stopped around the time Backbone JS stopped being used
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
If learning a couple of basic tools like an ORM and JS build tools is too much of a barrier, you probably shouldn’t be let anywhere near a database with real users data in it.
PHP is too easy to get started with and let’s you do some truely horrific things trivially.
I think it's ironic that the author claims that clean code is.......
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.
That's partly the reason why the term "best practice" has become a bit controversial in some communities --- it's seen as mindless dogmatic cargo-culting. I've heard the saying "best practices are best not practiced" from the opposition.
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 you are having difficulty navigating a project because it has many modules, I really don't think that is an argument for disavowing whatever best practices. Rather, it is more of an argument against whomever organized the code base in a way that they like and you don't.
This gave me a thought just now. When future changes are needed to a piece of software, these are usually driven by the business side.
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.
Given the drift of the article, as signalled by its title, I think this precis of 'clean code' was being presented sardonically - particularly that last point. As you point out, you can nominally follow all these rules and still not squeak.
Silly premise. There's plenty of open-source products out there that will attest to the fact that the quality of a codebase has no effect on its overall commercial viability.
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.
There's a DevOps Cafe episode, I forget which topic, but the idea was that users just want DNS to work. Nobody cares how clean your config files are for Bind.
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.
yarp. we dont love clean code for the user, that should be obvious for anyone who has written a medium amount of code. we love clean code for the fact that some day, we are going to have to read our code, trace it for a bug... etc.
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.
Exactly. Code quality is not an intrinsic good, but it is a technique for accomplishing the actual intrinsic good, which is whatever the function of the software is.
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.
It's not quite that simple: it is not unusual for an overall-clean solution in response to new requirements to require refactoring the existing codebase, even if that is a clean and minimal solution for the requirements up to that point.
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.
The problem with over-engineering is also that it makes other refactoring harder at later stages, or just discourages change. Some degree of shittiness actually improves agility, and encourages change.
I care about my clean code. Nearly every line of code I write is "clean", because it affects the bottom line.
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.
It's a lot easier to swap out contains() for startsWith() at code review time than investigate some obscure bug that only affects a handful of requests 3 years later.
Oh boy... I believe I'm this kind of psycho, when I see my name in a git blame after tracing a bug that I didn't foresee... I feel awful, disgusted, then I fix it and think "You sure are dumbass, now try to be a lesser one".
this is always fun with git-bisect because if you can reliably reproduce the bug it will always leads you exactly to the commit that caused the problem. Nothing worse than tracing for a half hour and... it spits out your name.
The thing now I see in the Go community is cargo culting coming from seasoned veterans who took advantage of Go's minimal set of rules and created their own "standards". Take this project in Github called golang-standards. It even got the attention of Russ Cox who dismissed it in this Github issue: https://github.com/golang-standards/project-layout/issues/11....
This article seems to focus on clean code not having a significant effect on the software in production for the experience of the end user.
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.
The OP's post is true iff you limit your timeframe to near term and if you luck out and get all or most of the domain requirements in early and they don't change or one decides the complexity and labor to evolve those requirements doesn't warrant potential income it might garner.
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.
Few things: 1 file != sloppy code. remoteok.io, like nomadslist, is fundamentally much more about marketing and network effects than the software. While that in and of itself is a lesson, sometimes a worthwhile idea is more complicated than a job board, or even what one can throw together for a hackathon.
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."
This is a false equivalency. Pieter does not run a hypergrowth startup. His businesses are completely different to AirBnB and Stripe.
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.
"Users couldn't care less about the programming language you used", and yet the author is so protective of his work that I can't copy paste this phrase. Unhappy user right here.
We code for ourselves. We deliver value to the costumer. Two different things.
The users may not care about clean code but they sure care when I can't bring on more developers to deliver features to keep them ahead of the market that are not riddled with bugs.
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. :)
It’s because it makes no effort to prevent people doing insanely insecure things. Rails has a lot of safeguards for insecure things like using user input to update a record.
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_”.
PHP has supported SQL parameter binding for at least 17 years now. It's the standard way to execute SQL queries and it replaces any usage of mysql_escape() or related functions.
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.
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.
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”.
Rails and ActiveSupport are a huge extension to Ruby and are bigger than the non Rails Ruby usage. If you read the average PHP tutorial, it starts you out connecting to a db, running raw sql and rendering templates in the same file. An absolutely horrible idea. If you start on the default rails tutorial, you gets set up with a decently safe configuration.
It's not a horrible idea, it's the simplest and easiest way to solve simple problems. Bringing in rails and all it's abstractions for something you can do in a single php (or ruby BTW) file is insane.
The easiest and simplest way is not the most secure way. Most of the beginner PHP tutorials show you something that technically works but should never ever be attempted on a real app. The problem is they do work so they get used with real users data.
> The easiest and simplest way is not the most secure way.
No, but the next simplest (using prepared statements) is. Why do you immediately jump to something so much more complicated and full of abstractions instead of the next simplest thing?
I wrote my website (where clients could hire me as a 3d artist back in 2008) I had zero experience with php. I liked the idea of using include("page.php") to insert part of a page into a "layout". I remember my friend (who was a better programmer than me at the time) telling me to not use $_GET["page"] with include, so people could not include unexpected pages via URL. I was like, yeah, that's kinda obvious. I feel the same way about sql queries.
Even if you are just talking about clean code for your own satisfaction whether or not a single PHP file is "clean" or not (to me) depends heavily on the complexity of the application.
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).
> "Often I see developers that seem to care more about writing clean and beautiful code just for the sake of it, completely forgetting the bigger picture, why they are doing it."
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.
> eventually you reach a point where maintaining that large (usually monolithic) codebase becomes so unbearable, so hazardous that you have to stop and rethink the entire design
This assumes that your app will grow indefinitely. What if we had more apps that were considered finished?
I don't understand why it's surprising to anyone that not every project needs the same approach to software engineering. Complex tasks need much more careful design than simple ones.
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.
It's true that users want software that works and they don't care about the code...
... 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.
If "nobody" cares you obviously never talked to someone running ops in your team, ever.
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.
Architect comes up with library to make it so even a monkey could handle use case X without fucking it up. Then they go to architect land where they all stay in their ivory tower. Then use case Y comes along but nobody thinks to switch from or extend what the legendary architect gave to the people. Those who try are heretics who have gone full cowpoke. Then when things get bad enough who should come to save the day but the hurdy gurdy architect, probably not the same one as last time.
Yes, definitely iterate and throw away at the start, and understand that clean code has quite a cost, but obviously strive to understand when it's worth it.
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.
What’s underestimated is attitude. Same situation, 2 ways of looking at it:
“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”
At first I thought "Meh, so what?" but then, after visiting remoteok.io, I'm impressed. That's a pretty polished site with a laser-like focus.
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...
Meta observation: OP says nothing new, but I guess that people have to (re)discover this sort of principles by themselves, no matter how many times they're told by the wise and old.
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.
Do we say we hate reinventing the wheel? I think the reason it’s even an axiom, “don’t reinvent the wheel,” is because it is so very tempting to reinvent the wheel rather than building on established wisdom.
If you are a single developer, sure, knock yourself out, and stick everything in a single file.
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.
I had to dig into a niche TLS library a few months ago and was aghast at the 50000 line source files with massive God functions all over the place. I don't know how it ever was allowed to get that fubared or how they maintain it all.
SSL/TLS are godawful messes of standards, they are insanely complex to implement which is part of why they have had so many bugs turn up in recent years.
Remoteok.io is a refreshing **ck you to all the over-engineered barely-more-than-static sites rigged-up with the latest version React hook form packaged up in Docker ready to be deployed on Kubernetes. People, we need a movement which embodies this sentiment.
A "eat more blueberries diet" will always be more popular than a "eat less" one b/c with the form you'll have farmers, super markets, etc behind you. With the latter, the message will be don't go to the store and buy something - not 'sale sustaining' (yes that was an awesome pun).
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.
I realized this after going from a floundering late-stage startup with very high code quality to a hyper-growth startup with lower code quality, but much more engaged engineers focused on shipping.
If you care about having long lasting competitive advantage rather than simply being the first to market, than you care about your code. It just depends on what you want to optimize for.
Keep in mind that the website in question seems to be a two-page CRUD website with no moving UI elements (save for opening and closing panels) that probably has not changed much in the last months save for some CSS edits.
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.
tl;dr Here's a web site that made a lot of money despite being a single file of code that we presume is ugly. From this we conclude that one must choose between writing clean code and focusing on what the user wants.
(In case it isn't obvious, I disagree. Maintainable code lets you adapt to an evolving understanding of what the user wants.)
Obligatory: Not every company is in "that category" (hyperscale startups trying to churn out their MVP).
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.
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.