12 ms·
How I build software quickly
- anonzzzies 1y agoWe encounter many rough drafts (yours) in production systems. If the original devs are still there, it is usually something along the lines of: I showed the rough draft to my manager, they flagged is as done and I was assigned to another task.
- mattmanser 1y agoWork with bad companies, be surprised by poor managers? Who is the "we" in this context, I assume an agency? So that's not a problem with this process itself. You're describing problems with managers, and problems with developers being unable to handle bad managers. Even putting aside the manager's incompetence, as a developer you can mitigate this easily in many different ways, here's a few: - Just don't show it to management - Deliberately make it obviously broken at certain steps - Take screen shots of it working and tell people "this is a mockup, I still have to do the hard work of wiring it up" It's all a balancing act of needing to get feedback from shareholders and managing expectation. If your management is bad, you need to put extra work into managing expectations. It's like the famous duck story, from Jeff Atwood (see jargon number 4), sometimes you have to manage your managers: https://blog.codinghorror.com/new-programming-jargon/ https://blog.codinghorror.com/new-programming-jargon/
- anonzzzies 1y agoSure, but we actually thrive here; my company gets called in when systems are not functioning, badly broken, etc and they cannot fix it themselves (usually because the people who built it are gone for decades and they just kept it running with ductape for this time). We never stay for long, we just patch the system and deliver a report. But for figuring out what went wrong and writing the report, we find out how it got to be that way and it's always the same; they suck. Talking banks, hospitals, factories, it really doesn't matter; it's all garbage what gets written and 'TODO: will refactor later' is all over the place. We see many companies from the inside and let me tell you; HN is a lovely echo chamber that resembles nothing in the real world.
- jimbokun 1y agoI think the main lesson here is that most entities shouldn't be writing serious software themselves, but purchase software from reputable software companies whenever possible. At least who to hold responsible or sue is clearer in that case.
- croes 1y agoThis will get worse with AI
- anonzzzies 1y agoWe already see it; the combination of job-hopping & AI are a perfect storm really. From launch to failure is definitely getting fast-tracked; few months ago we had yet another hospital system that just lost data; reading the code (no tests, no peer reviews; they don't use versioning) shows clear signs of LLMs; many files that do almost the same thing, many similar function names that do almost the same thing or actually the same thing, strange solutions to trivial problems, etc. The problem was that there was a script ran at startup which added an admin user, but if an admin user already exists, it truncates the table. No idea why, but it wasn't discovered earlier because after testing by the devs it was put live, devs left (contractors) and it just ran without issues until the ec2 instance needed maintenance by aws and was as such rebooted after which all users were gone. Good stuff. They paid around 150k for it; that is not a lot in our field but then to get this level of garbage is rather frightening. This was not life threatening, but I know if it was, it would not be better as you cannot make this crap up.
- skeeter2020 1y agoAnd let us be very clear: this happened REGULARLY pre-AI, with long-lived systems adding contractors 12, 6 or less months over 20 or more years. Now we have AI that allows even faster iterations of this with even less conceptual integrity. The big problem: the decision makers(c-suite executives) never really understood what was happening before, so you can't expect them to see the root cause of the problem we're actively creating. This means it will not get the attention and resourcing needed - plus they'll be gone and on to the next one after taking a huge payday for slashing their R&D costs.
- anonzzzies 1y agoAgreed.
- roane 1y ago
- skeeter2020 1y agoI see this an awful lot. Msot recently was presentation of hackathon projects with product managers & executives asking how much work was left to turn them into production features. It's pretty obvious how their brains are spinning.
- big_hacker 1y agoI like the writing style. It is simple and effective. The author said LLM helps. Let's lynch him!
- Metalnem 1y agoI love his writing too! I read this post a few days ago and really liked it, so I started going through his older posts. It's no coincidence that his writing is good—he's actively working to improve it: https://evanhahn.com/economist-style-guide-book-takeaways/ https://evanhahn.com/economist-style-guide-book-takeaways/.
- EvanHahn 1y agoOf all the comments the post received, this one meant the most to me. Thank you.
- gbuk2013 1y agoAn important dimension that is not really touched upon in the article is development speed over time. This will decrease with time, project and team size. Minimising the reduction rate may require doing things things that slow down immediate development for the sake of longer term velocity. Some examples would be test, documentation, decision logs, Agile ceremonies etc. Some omissions during initial development may have a very long tail of negative impact - obvious examples are not wiring in observability into the code from the outset, or not structuring code with easy testing being an explicit goal.
- bayindirh 1y agoEven as a solo developer, I can swear by decision logs, test and documentation, in that order. I personally keep a "lab notebook" instead of a "decision log" which chronicles the design in real-time, which forms basis of the tests and documentation. Presence of a lab notebook allows me to write better documentation faster, even if I start late, and tests allow me to verify that the design doesn't drift over time. Starting blind-mindedly for a one-off tool written in a weekend maybe acceptable, but for anything going to live longer, building the slow foundation allows things built on this foundation to be sound, rational (for the problem at hand) and more importantly understandable/maintainable. Also, as an unpopular opinion, design on paper first, digitize later.
- gbuk2013 1y agoRight, an important part of keeping in mind other future developers working on your codebase. You 6 months later is that other developer once the immediate context is gone from your head. :)
- bayindirh 1y agoThat's very true. I like to word this a little differently: > Six months ago, only I and God knew how this code worked. Now, only God knows. :)
- lou1306 1y agoThis is why I have grown to appreciate gradual typing, at least for solo projects. In Python-land I can just riff over a few functions/scripts until I get a rough idea of the APIs/workflows I want, then bring mypy into the mix and shape things into their "final" form (this takes maybe a few hours away). Rinse repeat for each new feature, but at every iteration you build up from a "nicely-typed" foundation. Sometimes a redesign of the types you relied on becomes necessary to accommodate new stuff, but that would be true under any language; otoh, the "exploratory" part of coding feels faster and easier.
- KronisLV 1y agoThe initial rough draft almost reminds me of the old "Build One to Throw Away" approach, which I think is pretty nice - not getting caught up in making something production ready, but rather exploring the problem space first. I do admit that modern frameworks also help in that regard, instead of just stitching libraries together, at least for typical webdev stuff instead of more minimalistic CLI utilities or tools. The likes of Ruby on Rails, Django, Laravel, Express and even the likes of ASP.NET or Spring Boot.
- manmal 1y agoWhere I live we have this saying about building houses: Build one for your enemy, then build one for your friend, and then build your own one.
- rmdashrfv 1y ago> It can reveal “unknown unknowns”. Often, prototypes uncover things I couldn’t have anticipated. This is the exact opposite of my experience. Every time I am playing around with something, I feel like I'm experiencing all of its good and none of its bad ... a honeymoon phase if you will. It's not until I need to cover edge cases and prevent all invalid state and display helpful error messages to the user, and eliminate any potential side effects that I discover the "unknown unknowns".
- skrebbel 1y agoI think you're talking about unknown unknowns in the tool/framework/library. I think the author is talking about unknown unknowns in the problem space.
- nasretdinov 1y agoYeah, typically when you start thinking something through and actually implementing stuff you can notice that some important part of the behaviour is missing and it might also be something that means that the project is no longer feasible
- rmdashrfv 1y agoI think this applies to both tools/frameworks/libs and problem spaces
- rmdashrfv 1y agoI was talking about both. Sometimes even in a problem space time constraints demand that you utilize something off the shelf (whether you use part of it or build on top of a custom version of it). Tools aside, I think everyone who has 10+ years can think of a time they had a prototype go well in a new problem space only to realize during the real implementation that there were still multiple unknown unknowns.
- rightbyte 1y agoYe it is something like how making tools just you yourself use is so smooth. Like, they can be full of holes and be a swaying house of cards in general but you still can use them sucessfully.
- nasretdinov 1y agoOne important aspect, also highlighted by others, is that for the long term you actually _don't_ want to focus solely on the immediate task you're solving. Sure, short term the tasks are getting done quicker, but since the end goal typically is implementing a full coherent solution you _have_ to step back and take a look at a bigger picture every now and then. Typically you won't be allocated specific time when to do this, so this "take a bird's eye view" part has to be incorporated into day-to-day work instead. It's also typically easier to notice bigger issues while you're already in the trenches, compared to doing "cleanup" separately "later".
- pythonbase 1y agoThis post resonates deeply with how I build products, especially in the era of LLMs and AI-assisted coding. I usually start top-down, sketching the API surface or UI scaffold before diving into real logic. Iteration drives the process: get something running, feel out the edges, and refine. I favor MVPs that work end-to-end, to validate flow and reduce risk early. That rhythm helps me ship production-ready software quickly, especially when navigating uncertainty. One recent WIP: https://zero-to-creator.netlify.app/ https://zero-to-creator.netlify.app/. I built it for my kid, but I’m evolving it into a full-blown product by tweaking the edges as I go.
- albertgoeswoof 1y ago> Data modeling is usually important to get right, even if it takes a little longer. Making invalid states unrepresentable can prevent whole classes of bugs. Getting a database schema wrong can cause all sorts of headaches later So much this. Get the data model right before you go live, and everything is so simple, get it wrong and be prepared for constant pain balancing real data, migrations, uptime and new features. Ask me how I know
- skeeter2020 1y agoI came of age in SW dev when we started with the (database)schema. THis doesn't seem to be common any more and I regularly see experienced devs with low to no SQL exposure. Seems they typically work at an abstraction (or 2 or 3) above the API or maybe the ORM, but would struggle to write the resultant query, let alone profile it. I'm not convinced this was a good abstraction that really helps us be more effective.
- jimbokun 1y agoAPIs, data models and architecture are the main things you can't Agile your way out of. You need to get them right up front before you start iterating on the implementation.
- marginalia_nu 1y agoI think scale matters quite a lot here. If you're building something yourself or in a small team, I absolutely agree with everything written in the post. In fact, I'd emphasize you should lean into this sort of quick and dirty development methodology in such a context, because this is the strength of small scale development. Done correctly it will have you running circles around larger operations. Bugs are almost always easy to fix later for a small team or solo dev operation as you can expect everyone involved to have a nearly perfect mental model of the entire project, and the code itself will regardless of the messes you make tend to keep relatively simple due to Conway's law. In larger development projects, fixing bugs and especially architectural mistakes is exponentially more expensive as code understanding is piecemeal, the architecture is inevitably nightmarishly complex (Conway again), and large scale refactoring means locking down parts of the code base so that dozens to hundreds of people can't do anything (which means it basically never happens). In such a setting the overarching focus is and should be on correctness at all steps. The economies of scale will still move things forward at an acceptable pace, even if individual developers aren't particularly productive working in such a fashion.
- sisve 1y agoHmm, context matter a lot. Im not sure on what you consider large development projects, so maybe its even bigger then what I'm thinking on. But getting the apis between apps up and ready early and getting a working setup from the database team to the frontend teams and apps teams trough some kind of backend/api team has always proven to be the correct choice for me. Also getting it as fast as possible on to a production server so its just the dns missing from beeing in production help so much for testing and highlights bug and other problems between teams. So the author mostly talks about this from a code perspective, but IMHO its even more important on larger teams. (Sidenote: having this kind of architecture where you create layer of deps from one team to another is a bad idea from my point of view, but is still done a lot)
- marginalia_nu 1y agoIt's a scale. On the one extreme you have solo development, on the other you have the gargantuan code bases at e.g. Google, or the Linux kernel. What you're describing is somewhere in the middle (if you imagine a logarithmic scale), it's at a point where working like a solo dev begins to break down especially over time, but not at a point where it's immediately catastrophic. Startups sometimes work in that sort of hybrid mode where they have relatively low quality code bordering on unmaintainability, where they put off fixing its problems into the future when they've made it big.
- jillesvangurp 1y agoFast builds are important. I've been doing server side stuff for a few decades and there are some things you can do to turn slow builds into fast builds. I mostly work on the JVM but a lot of this stuff ports well to other stacks (e.g. Ruby or python). Basically there are things you can't avoid that are not necessarily fast (e.g. compilation, docker build, etc.) and things that you can actually control and optimize. Tests and integration tests are part of that. Learning how to write good effective tests that are quick to run is important. Because you might end up with hundreds of those and you'll be spending a lot of your career waiting for those to run. Over and over again. Here's what I do: - I run integration tests concurrently. My CPUs max out when I run my tests. My current build runs around 400 integration tests in about 35 seconds. Integration test means the tests are proper black box tests that hit a REST API with my server talking to a DB, Elasticsearch and Redis. Each test might require users/teams and some content set up. We're talking many thousands of API calls happening in about 35 seconds. - There is no database cleanup in between tests. Database cleanup is slow. Each build starts with an ephemeral docker container. So it starts empty but by the time the build is over you have a pretty full database. - To avoid test interaction, all data is randomized. I use a library that generates human readable names, email addresses, etc. Creating new users/teams is fast, recreating the database schema isn't. And because at any time there can be 10 separate tests running, you don't want this anyway. Some tests share the same read only test fixture and team. Recreating the same database content over and over again is stupid. - A proper integration test is a scenario that is representative of what happens in your real system. It's not a unit test. So the more side effects, the better. Your goal is to find anything that might break when you put things together. Finding weird feature interactions, performance bottlenecks, and sources of flakiness is a goal here and not something you are trying to avoid. Real users don't use an empty system. And they won't have it exclusive to themselves either. So having dozens of tests running at the same time adds realism. - Unit tests and integration tests have different goals. With integration tests you want to cover features, not code. Use unit tests for code coverage. The more features an integration test touches, the better. There is a combinatorial explosion of different combinations of inputs. It's mathematically impossible to test all of them with an integration test. So, instead of having more integration tests, write better scenarios for your tests. Add to them. Refine them with detail. Asserting stuff is cheap. Setting things up isn't. Make the most of what you setup. - IMHO anything in between scenario tests and unit tests is a waste of time. I hate white box tests. Because they are expensive to run and write and yet not as valuable as a good blackbox integration test. Sometimes you have to. But these are low value, high maintenance, expensive to run tests. A proper unit tests is high value, low maintenance and very fast to run (it mocks/stubs everything it needs, there is no setup cost). A proper integration tests is high value, low maintenance, and slow to run. You justify the time investment with value. Low maintenance here means not a lot of code is needed to set things up. - Your integration test becomes a load and stress test as well. Many teams don't bother with this. I run mine 20 times a day. Because it only takes less than a minute. Anything that increases that build time, gets identified and dealt with. My tests passing gives me a high degree of certainty that nothing important has broken. - Most of the work creating a good test is setting up the given part of a BDD style test. Making that easy with some helper functions is key. Most of my tests require users, teams, etc. and some objects. So I have a function "createTeam" with some parameters that call all the APIs to get that done. This gets called hundreds of time in a build. It's a nice one liner that sets it up. Most of my tests read like this: create a team or teams, do some stuff, assert, do more stuff, assert, etc. - Poll instead of sleeping. A lot of stuff happens asynchronously so there is a lot of test code that waits for shit to happen. I use kotest-assertions which has a nice "eventually" helper that takes a block and runs that until it stops throwing exceptions (or times out). It has configurable interval that it tries again that backs off with increasing sleep periods. Most things just take a second or two to happen. - If your CPUs are not maxed out during the test, you need to be running more tests, not less. Server tests tend to be IO blocked, not CPU blocked. And your SSD is unlikely to be the bottleneck. We're talking network IO here. And it's all running on localhost. So, if your CPUs are idling, you can run more tests and can use more threads, co-routines, whatever. - Get a decent laptop and pay for fast CI hardware. It's not worth waiting 10 minutes for something that could build in about a minute. That speedup is worth a lot. And it's less likely to break your flow state. This stuff is a lot easier if you engineer and plan for it. Introducing concurrently running tests to a test suite that isn't ready for it can be hard. Engineering your tests to be able to support running concurrently results in better tests. So if you do this properly, you get better tests that run faster. Win win. I've been doing this for a while. I'm very picky about what is and isn't a good test. There are a lot of bad tests out there.
- kukkeliskuu 1y agoIn recent years, I have learned how to build sufficiently robust systems fast. Here are some things I have learned: * Learn one tool well. It is often better to use a tool that you know really well than something that on the surface seems to be more appropriate for the problem. For extremely large number of real-life problems, Django hits the sweet spot. Several times I have started a project thinking that maybe Django is too heavy, but soon the project outgrew the initial idea. For example, I just created a status page app. It started as a single file Django app, but luckily realized soon that it makes no sense to go around Djangos limitations. * In most applications that fit the Django model, data model is at the center of everything. Even if making a rought prototype, never postpone data model refactoring. It just becomes more and more expensive and difficult to change over time. * Most applications don't need to be single-page apps nor require heavy frontend frameworks. Even for those that can benefit from it, traditional Django views is just fine for 80% of the pages. For the rest, consider AlpineHJS/HTMX * Most of the time, it is easier to build the stuff yourself. Need to store and edit customers? With Django, you can develop simple a CRM app inside your app in just few hours. Integrating commercial CRM takes much more time. This applies to everything: status page, CRM, support system, sales processes, etc. as well as most Django apps/libraries. * Always choose extremely boring technology. Just use python/Django/Postgres for everything. Forget Kubernetes, Redis, RabbitMQ, Celery, etc. Alpine/HTMX is an exception, because you can avoid much of the Javascript stack.
- physicsguy 1y agoI also like Django a lot. I can get a working project up and running trivially fast. In my day job I work with Go and while it's fine, I end up writing 10x more code for simple API endpoints and as soon as you add query parameters for filtering, pagination, etc. etc. it gets even longer. Adding a permissions model on top does similar. Of course there's a big performance difference but largely the DB queries dominate performance, even in Python, at least for most of the things I do.
- aatd86 1y agooh that's interesting. Is that due to missing libraries in Go? That could be a nice open source project if so.
- amelius 1y agoHow I build software quickly: get rid of team members first, communication slows things down.
- whstl 1y agoI actually try to build it "well" in the first pass, even for prototyping. I'm not gonna say I succeed but at least I try. This doesn't mean writing tests for everything, and sometimes it means not writing tests at all, but it means that I do my best to make code "testable". It shouldn't take more time to do this, though: if you're making more classes to make it testable, you're already messing it up. This also doesn't mean compromising in readability, but it does mean eschewing practices like "Clean Code". Functions end up being as large as they need to be. I find that a lot of people doing especially Ruby and Java tend to spend too much time here. IMO having lots of 5-line functions is totally unnecessary, so I just skip this step altogether. It also doesn't mean compromising on abstractions. I don't even like the "rule of three" because it forces more work down the line. But since I prefer DEEP classes and SMALL interfaces, in the style of John Ousterhout, the code doesn't really take longer to write. It does require some thinking but it's nothing out of the ordinary at all. It's just things that people don't do out of inertia. One thing I am a bit of hardliner about is scope. If the scope is too large, it's probably not prototype or MVP material, and I will fight to reduce it. EDIT: kukkeliskuu said below "learn one tool well". This is also key. Don't go "against the grain" when writing prototypes or first passes. If you're fighting the framework, you're on the wrong path IME.
- vendiddy 1y agoI personally find that doing it well in the first pass slows me down and also ends up in worse overall designs. But I am also pretty disciplined on the 2nd pass in correcting all of the hacks and rewriting everything that should be rewritten. There are two problems I have with trying to do it right the first time: - It's hard to know the intricacies of the requirements upfront without actually implementing the thing, which results in designing an architecture with imperfect knowledge - It's easy to get stuck in analysis paralysis FWIW I am a huge fan of John Ousterhout. It may be my all time favorite book on software design.
- whstl 1y agoI have found that too much coupling between product requirements and the architecture can be detrimental. It's often the reason why people tend do too much upfront work, but also slows down the evolution of the feature. So I don't really want to know the future requirements, or refactor on the 2nd pass to "match". If some feature needs too many modifications or special cases in the current architecture, it's a round peg in a round hole. I prefer to have those places be a bit more "painful" in the code. The code doesn't have to be bad per se, but it should be clear that something different and not traditional is happening there.
- ChrisMarshallNY 1y agoI've found that a "rough draft" is pretty hard to maintain as a "draft," when you have a typical tech manager. Instead, it becomes "final ship" code. I tend to write ship code from the start, but do so, in a manner that allows a lot of flexibility. I've learned to write "ship everywhere," even my test harnesses tend to be fairly robust, ship-Quality apps. A big part of that, is very high-Quality modules. There's always stuff that we know won't change, or, if so, a change is a fairly big deal, so we sequester those parts into standalone modules, and import them as dependencies. Here's an example of one that I just finished revamping[0]. I use it in this app[1], in the settings popover. I also have this[2] as a baseline dependency that I import into almost everything. It can make it really fast, to develop a new application, and can keep the Quality pretty high, even when that's not a principal objective. [0] https://github.com/RiftValleySoftware/RVS_Checkbox https://github.com/RiftValleySoftware/RVS_Checkbox [1] https://github.com/RiftValleySoftware/ambiamara https://github.com/RiftValleySoftware/ambiamara [2] https://github.com/RiftValleySoftware/RVS_Generic_Swift_Toolbox https://github.com/RiftValleySoftware/RVS_Generic_Swift_Tool...
- pandemic_region 1y agoTangent, is it a Swift thing to have "* ################################################################## / comment markers ? It becomes quickly very visually dominant in the source code: > / ###################################################################################################################################### / // MARK: - PUBLIC BASE CLASS OVERRIDES - / ###################################################################################################################################### */
- ChrisMarshallNY 1y agoNope. It's a "Me" thing. I write code that I want to see. I have fairly big files, and it makes it easy to scroll through, quickly. It also displays well, when compiling with docc or Jazzy. My comment/blank line-to-code ratio is about 50/50. Most of my comments are method/function/property headerdoc/docc labels. Here's the cloc on the middle project: github.com/AlDanial/cloc v 2.04 T=0.03 s (1319.9 files/s, 468842.4 lines/s) ------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- Swift 33 1737 4765 5220 ------------------------------------------------------------------------------- SUM: 33 1737 4765 5220 -------------------------------------------------------------------------------
- paffdragon 1y agoThis is very familiar. Rough draft, some manual execution often wrapped in a unit test executor, or even written in a different scripting language just to verify the idea. This often helped me to show that we don't even want to build the thing, because it won't work the way people want it to. The part about distraction in code feels also very real. I am really prone to "clean up things", then realize I'm getting into a rabbit hole and my change grows to a size that my mates won't be happy reviewing. These endeavors often end with complete discard to get back on track and keep the main thing small and focused - frequent small local commits help a lot here. Sometimes I manage to salvage something and publish in a different PR when time allows it. Business mostly wants the result fast and does not understand tradeoffs in code until the debt hits the size of a mountain that makes even trivial changes painfully slow. But it's about balance, which might be different on different projects. Small, focused, simple changes definitely help. Although, people are not always good at slicing a larger solution into smaller chunks. I sometimes see commits that ship completely unused code unrelated to anything with a comment that this will be part of some future work...then prio shifts, people come and go, and a year later we have to throw out all of that, because it does not apply to the current state and no one knows anymore what was the plan with that.
- hamdouni 1y agoWhen possible, I try to use real data for both volumetry and heterogeneity testing. It helps reveal unknowns in the problem space that synthetic data might miss.
- dirkc 1y agoI try to do UX design with real data too. Not sure if that is what you mean with heterogeneity?
- hamdouni 1y agoNot quite UX-focused, but related I meant data heterogeneity - the variety in formats, edge cases, and data quality you encounter in production. Real user data often has inconsistencies, missing fields, unexpected formats, etc. that synthetic test data tends to miss. This helps surface integration issues and performance bottlenecks early.
- jimbokun 1y agoThis is very important and requires some foresight when the real data is personally identifiable information, private health information, etc. It's possible, but requires designing a safe way to run pre-production code that touches production data. Which in practice means you better be sure you're only doing reads, not writes, and running your code in the production environment with all the same controls as your production code.
- hamdouni 1y agoYou are right. I have a pre-production environment with a copy of production data and a script that scramble names and personal infos.
- hobofan 1y ago> For example, if you’re making a game for a 24-hour game jam, you probably don’t want to prioritize clean code. That would be a waste of time! Who really cares if your code is elegant and bug-free? Hate to be an anecdote Andy here, but as someone who has done a lot of code review at (non-game) hackathons in the past (primarily to prevent cheating), the teams that performed the best were also usually the ones with the best code quality and often at least some rudimentary testing setup.
- kqr 1y agoThese two statements do not contradict themselves. That teams have the best code quality does not mean they must have prioritised clean code.
- tikhonj 1y agoI mean, it's pretty strong evidence that they value good code. You don't get quality by accident. (But you do get it by habit!) But, in another sense, they didn't "prioritize" good code because it isn't really a tradeoff. They're just better.
- bob1029 1y agoThe gaming use case is what makes this apt advice. If you've got 24h to make a game and you're spending more than ~1h worrying about the source code cleanliness, I don't think it's gonna go well. Systems like UE blueprints showcase how pointless the pursuit of clean anything is when contrasted with the resulting product experiences.
- jimbokun 1y agoIf you're an experienced developer, writing clean code doesn't add any more time than writing shitty code. It's just ingrained habits of what makes for the best productivity.
- pydry 1y agoI think some people look at code cleanliness in aggregate (this code base is dirty vs. it is elegant and bug free) and others have a fine grained cost/benefit analyses of nonfunctional code improvements. Im pretty sure the latter vastly outpeform the former under all circumstances - whether quick and dirty hackathon or ultra hardened production code.
- shireboy 1y agoThis pretty much exactly describes my strategy to ship better code faster. Especially the “top down” approach: I’m actually kind of surprised there isn’t like a “UI first” or “UI Driven Development” manifesto like w TDD or BDD. Putting a non functional UI in front of stakeholders quickly often results in better requirements gathering and early refinement that would be more costly later in the cycle.
- deleted 1y ago[deleted]
- zwnow 1y agoWhy not build a simple functional UI, its not a huge time sink between non functional and functional (as long as kept simple)
- vinibrito 1y agoWell, most of the times people I worked with preferred something earlier even if just by a few days that they could see and comment on. Maybe that is why for him too.
- shireboy 1y agoWell, sometimes I will, but for example take a simple list+form ontop of a database. Instead of building the UI and the database and then showing the stakeholder, who adds/renames fields, changes relationships etc. I will intentionally build just the UI not wired up to database. Sometimes just to an in-memory store or nothing. Then, _after_ the stakeholder is somewhat happy with the UI, I "bake" things like a service or data layer, etc. This way the changes the stakeholder inevitably has up front have less of an impact.
- gavmor 1y agoI call it "outside in", but sometimes like to de-risk a lower level component before investing in the UI.
- whizzter 1y agoI think at that point it's almost better to come with paper printouts for 2 reasons. 1: Tacticale/shareable/paintable in a physical meeting 2: It drives home that it's a sketch, with bad customers a visible UI so easily hides the enormous amounts of complexity that can sometimes be under a "simple" UI and make it hard to educate them as to why the UI sketch one did in an hour or two then needs 1500 hours of engineering to become a functioning system.
- ifoxhz 1y ago"Learn to walk before you run. I firmly believe in this wisdom. First build a foundational model, then tackle boundary challenges and efficiency optimization."
- bad_username 1y agoWhat the article calls "rough draft" I like to call "executable architecture", a nice term from the "rational unified process".
- TechDebtDevin 1y ago>(I recently had a branch where an error message was logged 20 times per second.) Lightwork
- MeetingsBrowser 1y ago> What is my team’s idea of “good enough”? What bugs are acceptable, if any? Where can I do a less-than-perfect job if it means getting things done sooner? I hop between projects regularly, and this has been the biggest source of inter-team conflict in my career. Different people from different backgrounds have an assumed level of what "good enough". The person from big tech is frustrated because no one else is testing thoroughly. The person from a startup is frustrated because everyone else is moving too slow. It would be nice if the "good enough" could be made explicit so teams are on the same page.
- leetrout 1y agoThis is a team charter. A “how we work” document. https://asana.com/resources/team-charter-template https://asana.com/resources/team-charter-template
- Surac 1y agoi often use c# and Visual Studio to write prototype code. C# can be used in a C like syntay (my destination language) and has much better turnaround times
- tikhonj 1y ago> For example, if you’re making a game for a 24-hour game jam, you probably don’t want to prioritize clean code. That would be a waste of time! Who really cares if your code is elegant and bug-free? Having worked on some 24-hour game jams and similar, I've found completely the opposite. It's when you're in a real hurry that you really can't afford bad code. Writing better code will make it easier to get it right, will put less pressure on my working memory, will let me try things faster and make those last-minute changes I wanted, will make adding features towards the end easier rather than harder and, crucially, will both reduce the chance that I need to do intense debugging and make debugging I need to do easier. Working with good code just feels lighter. The thing that breaks 24-hour projects isn't writing code too slowly, it's writing yourself into a corner or hitting some problem that derails your work, takes hours to solve or doesn't even get resolved until after the deadline. A game jam isn't the place to try to squish all bugs, sure, but that's a question of what you're doing, not how. I still want to write good code in that situation because it makes my life easier within the time constraints, and because, even if I'm fine with some bugs, there are still lots of bugs that render a game unpleasant or unplayable. I'll need to fix some bugs no matter what; I'd rather fix fewer, easier bugs than more, harder bugs! The same thing applies to longer time horizons too. When you have more time you have more slack to deal with bad code, but that doesn't mean it makes any more sense to write it! And, of course, once you get in the right habits, writing solid quality code becomes basically free... but, even if it really did meaningfully slow you down, chances are it would still be worth doing in expectation.
- jimbokun 1y agoI agree. I think it's a misconception that writing good code must take longer than writing bad code. At least if you want it to vaguely satisfy some requirements.
- raxxorraxor 1y agoWell, you probably would disregard some fancy asset loader and instead just statically include some files instead. Or if you need to do some pathing and your quickest solution is some breadth first search. Perhaps it isn't "bad code", but still a bad solution that could quickly be implemented and be solved by a lot of computing power. Of course you may use ready-to-use modules that provide such features as well..., but it may be prohibited by competion rules, I don't know...
- softwaredoug 1y agoIsn't the current layoff-heavy tech world the biggest threat to software quality and engineer productivity? The perpetual looming threat of layoffs, the need to deliver wins ASAP, stifles creativity, punishes experimentation, and pushes people to burnout. It forces people into groupthink about topics like AI. Nobody can say the emperor has no clothes (emperor being leadership or the topic du-jour) Forget LLM coding, solve this problem...
- andygogogo 1y agoI agree with you
- alphazard 1y agoThe biggest threat to software quality, has always been and will always be that consumers don't pay for quality. Consumers that have good taste (or at least perceive differences in quality) are not numerous enough to support new products that differentiate themselves only with quality. And they (the consumers) are not successful enough in their own enterprises to pay extra for better quality products. It's easier to find examples where people do pay for quality outside of software. Look at the spectrum in quality available for vehicles or household appliances.
- AlwaysRock 1y agoYup. As engineers, we MIGHT care about code quality. The end user just cares if something works in the way they want/expect it to. A lot of large successful companies have rough code quality.
- bit1993 1y agoThe biggest threat is vendor-lockin at the programming level, far more destructive than SAAS lockin. We already have monopolies in hardware now we are about to have monopolies in software by the same companies who monopolized the hardware. Giving them so much power that there will no longer be computer programmers, there will only be LLM prompters.
- 65 1y agoBuilding software quickly seems to mostly come from having enough examples of code you've already built that you can pull from. I recently re-made my web based notes app. Before working on this project I made a web based S3 file manager (e.g. CRUD operations in my own UI). Instead of trying to store notes in a database or something, I just yoinked the S3 file manager code and store my notes in S3. Just a few tweaks to the UI and a few more features and now I have a notes app.
- eschneider 1y agoJust one thing I'd like to throw out here after far too long in the industry: It's very hard to tell ahead of time just how users will put computers/software to use. Lots of generic, off-the-shelf HW and SW get used in ways that are ultimately 'life critical' to someone. Something to keep in mind for design/development/testing.
- RaftPeople 1y agoMy 2 cents: I prefer to emphasize quality over scope, meaning relentlessly adopt habits that reduce bugs to rare events. Don't take on extra scope unless you can deliver a working system, wait until next iteration. Reason (my context: small team(s) but in a somewhat complex and integrated environment): Many times, bugs in production cost the company (IT and business areas) much much more to identify/correct/resolve then making sure the stuff works in the first place. Incorrect transactions flowing between different systems and different areas of the business and possibly out to customers and other external partners are time consuming to correct, or require costly manual labor to work around.
- gorjusborg 1y agoFunctions and immutable data. Yessir, that is the way to speed. You're composing and climbing to higher levels of abstraction while the competition is trying to synchronize their accidental state machine network.
- deterministic 1y agoI write (mostly) bug free production code fast by doing the following: 1. I use a custom code generator to generate 90%+ of the code I need from a declarative spec. 2. The remaining hand written code is mostly biz logic and it is exhaustively auto tested at the server API level. 3. I maintain and "bring along" a large library of software tools "tested in combat" I can reuse on new projects. 4. I have settled on an architecture that is simple but works and scales well for the small to large biz applications I work on. 5. I constantly work on removing complexity from the code, making it as easy to understand and modify as possible.
- hu3 1y agoI too like code generators. Keeps code standard and reduces human error. What programming language you like for that?
- theletterf 1y agoWrote the docs equivalent :) https://news.ycombinator.com/item?id=44635184 https://news.ycombinator.com/item?id=44635184