10 ms·
Code the shortest path first
- hkon 3y agoFor sideprojects, definitely, there is simply not enough time otherwise.
- maverwa 3y agoFor me, its not just time, but also motivation. I cannot count how many site projects died in the early days, just because I came up with this impossible perfect thing it should be, having all the things. Then implementing it becoumes a chore. The amount of code/time I'd have to invest to make this imagination a reality becomes a mountain I cannot climb. Either because a lack of skill/knowledge, time, motivation, dedication, or just all of them. Usually this ends in me giving up the whole thing for good, ending most of these hobby project before they even began. Starting with a "MVP", something that can be implemented quickly (relative to "the perfect thing") and provides some immediate benefit or feedback, pretty much always works better for me. Its something I still stuggle a lot with. Its hard for me to get things done, because whatever I build never holds up to what I want it to be. But I think, I am getting better of accepting that, and just getting _something_ done.
- imtringued 3y agoWell kept secret: If you want to get things done, keep the scope within something you can actually do. If you are unhappy with the fact that you planned to do more, then congratulations, you can just get things done again!
- baseballpuck 3y agoThis is a balancing act. Spending the time later to undo all of the technical debt accumulated can take even longer.
- evanlh 3y agoYeah 100%. I'm not suggesting land technical debt, it's more about the approach to solving the problem in the early stages while you're still seeking a solution-- don't get bogged down by perfectly conforming to a bunch of intermediary abstractions on your way towards the goal.
- jaggederest 3y agoAnd my cynical response is that, if you demonstrate something working too quickly in certain organizations, you will be voluntold to work on a new project before it has been factored at all.
- sumanthvepa 3y agoThis is excellent advice. I would only modify it to say that one should first focus on getting something working, not necessarily the shortest path Then you can refactor and improve the code before you actually deploy it to production.
- 000ooo000 3y agotl;dr: long form version of "make it work, then make it pretty"
- Cthulhu_ 3y agoWhich in itself is a short form of "make it work, make it pretty, make it fast, in that order", which tackles both over-engineering on an architectural and a performance level. For the vast majority of any task that requires writing code, performance is the least of your concerns; your code is fast enough, your compiler and runtime is fast enough, the hardware is fast enough. Use decent algorithms / don't do anything stupid (e.g. n+1 if you use an ORM), but don't fret too much whether it's fast enough either. If your code is working and pretty, nine times out of ten it's fast enough. For the last 10%, measure before you make assumptions.
- Pannoniae 3y agoThis approach of "things being fast enough" leads to everything being slightly slow - we literally had better usability and latency on our devices in the 90s than we have now. It all adds up.
- Shaanie 3y agoAnother way to think about it is that software that focus on performance loses market share to software that focuses on other things.
- Pannoniae 3y agoAnd that's a perverse incentive, and we must evaluate why that is the case. It doesn't have to be that way.
- evandale 3y agoIt probably has to do with the fact that a lot of people are patient enough to wait 10 seconds for something to finish if a) they understand it and b) it does the job. The average person will put up with a lot of friction to use something they're familiar with and needs a lot of incentive to change. If your thumbnails fail to load every 10000 times or every 100000th profile picture upload fails most people will just retry and hope it works the second time, not find a different service or app to use.
- xiphias2 3y agoThis is great, one modification that I would make is to add CI/CD and testing when there's a regression that was not expected, or when it makes development simpler. That way I don't have to think about the ,,right time'' to introduce these.
- jruz 3y agoYou’re mixing product decisions with code decisions. Product should make sure to create an MVP aka the fastest solution for A-B. Code should be done right no matter what, you’re being paid as an expert to do that, if they would want whatever crappy code gets it done they would do it themselves with some nocode solution and test the hypothesis.
- mschuster91 3y ago> Code should be done right no matter what, you’re being paid as an expert to do that As I've written in a recent thread... that may be the case in the academic world, but certainly not in the business world, where time-to-market and profitability always trump code quality if not explicitly required / audited by client contracts.
- defrost 3y agoSomewhere twixt the two is another domain; the hard equation engineering world. Computations along novel curved beam configurations have to be correct, 400 m deep billion dollar / annum mine stope angles need to be both aggressive and safe, et al. Often there's not as much competition as might be in other domains, and while profitability pays the bills the real onus is on the production of provably correct software (to the greatest degree practical).
- pyrale 3y ago> where time-to-market and profitability always trump code quality What actually happens is more like : "deliver as fast a possible, no matter what" ... "The poc was delivered in a week, why are new features so slow? And can you explain what this refactoring item adds to the bottom line?"
- mejutoco 3y agoThat seems like a failure of management.
- 3y ago
- i-use-nixos-btw 3y agoAn alternative: Build a PoC first. The reason coding the shortest path first feels better is that you hit milestones early. However, it is a major generator of technical debt, and fleshing out the project is the hard part that takes longer and introduces breaking changes. Taking time to plan, getting the API planned in advance, generalising the code (obviously not TOO much), and so on might feel less rewarding at first, because the early milestones are the hard part. But do it right and you end up seeing everything fall into place in quick succession, according to plan - and that’s a much greater sense of achievement IMO. It is often also a quicker way of seeing large projects to completion, though it doesn’t always feel like it at the time. Building a Proof of Concept allows you to get the best of both worlds. It allows you to be naive, it allows you to write the bare minimum, and it gets something working that others can try out and give feedback on. As a bonus, it doesn’t generate technical debt, because you don’t build on the PoC - you use it as a reference while building the actual thing.
- JonChesterfield 3y ago> because you don’t build on the PoC Ah yes, I remember that idea. Naturally we shipped the proof of concept. Also "it is known" that rewrites from scratch are bad things, so it got iterated on instead of replaced. Based on the internal architecture of other software I've seen I think this is a relatively popular development strategy.
- pyrale 3y ago> I think this is a relatively popular development strategy. ...And this is why PoCs should be small-scale but technically sound things, rather than a shortcut competition. People are rarely going to complain about a PoC delivered a week late, but they are definitely going to complain later on, after they ship the PoC against your opinion and development slows down.
- mejutoco 3y agoPeople can complain about anything. That does not mean they are right. If a PoC is later extended, it will of course have limitations. We do not need to change the meaning of PoC to full product to preemptively solve that. Instead, when a PoC is done everybody involved needs to understand the implications. If people insist on misinterpreting them, that is on them. Those are political problems, not technical ones. They can be solved by aligning incentives. TLDR. A PoC is a PoC, not a full product.
- t43562 3y agoUsually one understands a project poorly at the start and much better at the end. So to agree with the article I think it's unwise to make all your decisions at the point where you know the least. By getting something working you improve your understanding and then you can choose optimisations and abstractions in a judicious manner - no point in optimising things that end up having no impact and no point in introducing abstractions that in practice never will be used. There are those who imagine that you can completely plan work before lifting a finger and it's a problem to struggle with them sometimes. Another one is when some aspect of the outcome is big in people's minds. I was once on a project where we thought we'd be charging people based on their usage of the product. This made the reporting system very critical because if we messed anything up we'd be cheating our customers or giving them freebies. In the end we realised nobody wanted to pay that way so this huge design consideration which made everything much more complicated was gone. This sort of pattern happens often and it was a mistake to start that way. But that was a requirements mistake rather than a programming one and this is why your requirements are so critical. A single sentence in a document can double the cost of a project and your customers often don't realise that.
- corry 3y ago"Usually one understands a project poorly at the start and much better at the end" <--- this is 100% it, totally agree. It also happens at the product level - building features too early or too deeply for a poorly understood workflow; abstracting things that don't need to be abstracted for probably YEARS; over-engineering for major scale despite having no users; knowing that ONE DAY you'll need, say, multi-language support, so on Day 1 you over-complicate everything by insisting on a language framework etc. Beginners lack the foresight of 'what this will look like at scale' or maybe better said 'why this won't work at scale', but that's ironically why they are better early on - speed matters a lot more than anticipating potential scale issues years later.
- OkayPhysicist 3y ago> There are those who imagine that you can completely plan work before lifting a finger My response to these types is always to point out that we already have tools that translate a complete plan of a project into software: They're called compilers, and that plan is source code.
- kqr 3y agoThere's a fine line between shortest path first and most certain path first. It's tempting to jump in and do the things you know for sure how they will work – these are the things with the lowest need for exploration. Early-stage, you should focus on the things that are most uncertain, the things that have a chance of dooming the entire project if you don't understand them better. You can still take the shortest path while focusing on the most uncertain first, but it is another concern that needs to be prioritised.
- evanlh 3y agoYes, totally agree with this-- I perhaps should have emphasized that my point is to code the shortest path thru the hardest problem. If somehow you just code around the hard part & keep deferring that til later you haven't learned anything.
- tuukkah 3y agoI think the shortest/fastest path can have value even if you didn't learn much yet, because it can provide an end-to-end platform for learning: something to show and discuss with stakeholders and potential users. After you have that platform, the next target can be the biggest uncertainty / hardest problem that you need to solve to achieve an MVP. "We have X, can we get to an MVP?" (After you have an MVP, the hardest problems may still await you but you can prioritize based on what increases value.)
- tuukkah 3y agoI notice they link to The Pragmatic Programmer here: > If it’s a true greenfield project you are “prototyping”, if it’s part of an existing project you are making a “tracer bullet”. In the C2 wiki, someone paraphrases it like this: > In PragmaticProgrammer, they talk about TracerBullets in the context of building an ArchitecturalPrototype - a bare-bones skeleton of your system that is complete enough to hang future pieces of functionality on. It's exploratory, but it's not really a prototype because you are not planning to throw it away - it will become the foundation of your real system. https://wiki.c2.com/?TracerBullets https://wiki.c2.com/?TracerBullets Wikipedia has a description in the context of Scrum here: https://en.wikipedia.org/wiki/Scrum_(software_development)#Tracer_bullet https://en.wikipedia.org/wiki/Scrum_(software_development)#T... Does anyone remember more about what Pragmatic Programmer says about this topic?
- evanlh 3y agoHi! Yes I couldn't find a better source, here's excerpting from the book-- "We once undertook a complex client-server database marketing project. Part of its requirement was the ability to specify and execute temporal queries. The servers were a range of relational and specialized databases. The client GUI, written in Object Pascal, used a set of C libraries to provide an interface to the servers. The user's query was stored on the server in a Lisp-like notation before being converted to optimized SQL just prior to execution. There were many unknowns and many different environments, and no one was too sure how the GUI should behave. This was a great opportunity to use tracer code. We developed the framework for the front end, libraries for representing the queries, and a structure for converting a stored query into a database-specific query. Then we put it all together and checked that it worked. For that initial build, all we could do was submit a query that listed all the rows in a table, but it proved that the UI could talk to the libraries, the libraries could serialize and unserialize a query, and the server could generate SQL from the result. Over the following months we gradually fleshed out this basic structure, adding new functionality by augmenting each component of the tracer code in parallel. When the UI added a new query type, the library grew and the SQL generation was made more sophisticated. Tracer code is not disposable: you write it for keeps. It contains all the error checking, structuring, documentation, and self-checking that any piece of production code has. It simply is not fully functional. However, once you have achieved an end-to-end connection among the components of your system, you can check how close to the target you are, adjusting if necessary. Once you're on target, adding functionality is easy." They later list some of the advantages of this approach-- - Users get to see something working early - Developers build a structure to work in. And differentiate it from prototyping-- "The tracer code approach addresses a different problem. You need to know how the application as a whole hangs together. You want to show your users how the interactions will work in practice, and you want to give your developers an architectural skeleton on which to hang code. In this case, you might construct a tracer consisting of a trivial implementation of the container packing algorithm (maybe something like first-come, first-served) and a simple but working user interface. Once you have all the components in the application plumbed together, you have a framework to show your users and your developers. Over time, you add to this framework with new functionality, completing stubbed routines. But the framework stays intact, and you know the system will continue to behave the way it did when your first tracer code was completed." It's still a great book 20 years later, I highly recommend picking up a copy.
- sktrdie 3y agoLike with everything in life, I'll answer this article with a strikingly "it depends". What are your business requirements? How much budget do you have? Deadlines? Do you already have a clearly defined audience? If you're a company like Figma then dedicating resources to crafting the hell out of the product & pushing the envelope in terms of maintainability, tests, performance & software craftmanship is a must. Probably going directly from A -> B is not scalable. If you're a company with 200 costumers and 3 developers then I feel it's the opposite. Dedicating time & resources into all those premature optimizations might kill your company. I remember seeing something along the lines of "Over-engineering cited as major cause of product failure. Because it never ships."
- uraura 3y agoRecently I ask ChatGPT to do that. I become the one to improve it.
- lhnz 3y agoMaybe I'm not senior enough, but I think this misses the point. If I'm not prototyping, I don't try to "code the shortest path first", I try to code using the most popular libraries, and the most concrete, broad-strokes, fundamental abstractions, towards a goal of improving understandability. At the end of the day, most code is deleted anyway. But even then people still need to understand it. I am attempting to write in the "lingua franca" and to make it clear to myself and others what I understand about the problem.
- nickelpro 3y agoIt's contextual, and the author is presenting it as universal. If you don't know how to build the thing, the author's advice is on the right track. If you're unfamiliar with the problem space, just bang away at it. Write that god object, that 500 line function, hardcode all the things. You wouldn't be able to come up with useful abstractions so don't bother trying. Get your stupid terrible code to work, the tiny demo operational, and then take a step back and understand your creation and refactor. If you do know how to build the thing, if this is your 5th time writing a task scheduler and you know what the ground work for a new one should look like, trust your instincts.
- lhnz 3y ago> If you're unfamiliar with the problem space, just bang away at it. > Write that god object, that 500 line function, hardcode all the things. > You wouldn't be able to come up with useful abstractions so don't > bother trying. I take your point about this applying to the context of prototyping. But speaking universally, I'm trying to explain a third way in which you don't try to pick abstractions or apply hyped patterns or find code that you can make DRY, but instead try to write your code conservatively as if it were to be featured in a programming tutorial for newbie engineers. You try to make it easy to understand but you don't make choices about the solution that would require more understanding than you currently have. In this case, it's not about applying "object-oriented design & algorithms & design patterns & frameworks & abstractions & higher-order functions & monoids & whatever else you found on Hacker News". It could be writing a god object or 500 line function, but only if these are easy to understand. Basically, I think we should write programs as communication to ourselves and others and as a form of "theory-building". I think our artifacts should fit into this objective and communicate understanding. (I am heavily Naur-pilled, e.g. https://pages.cs.wisc.edu/~remzi/Naur.pdf https://pages.cs.wisc.edu/~remzi/Naur.pdf)
- nickelpro 3y agoI agree with the sentiment but not the examples: > spend days setting up a CI/CD pipeline This should/does take minutes. It's like 15 lines of YAML for most CI providers. Ideally it's a part of the template you use for new code. > use a cool new library they just found Integrating a useful lib that makes the code simpler should be done from day 1. Don't code your own platform lib and switch to SDL halfway through development. Don't code your "tracer bullet" on Win32 API calls when you're going to be using libuv. And like CI/CD, integrating libraries into the build should be painless > if it’s software that’s going to ship, it needs tests Oftentimes the tests are the only way you know if the code is even minimum viable, even manages to be the "tracer bullet". Ok you implemented a new feature, what says the code even runs and doesn't segfault immediately if there's not a test to build the new code into and run? Not comprehensive tests, but something
- heisenbit 3y ago>> spend days setting up a CI/CD pipeline > This should/does take minutes Should if you discount tool selection, learning tools, managing access control, deal with technical and organization imposed constraints, documentation and alignment across the team.
- nickelpro 3y agoAll of those things are easy. If they're not easy you have organizational problems that are slowing down development unnecessarily. Your team has a CI system of choice, plugging a new thing into that CI system should be trivial, if it's not you're doing CI very poorly. Hard-to-use is a bug.
- tru1ock 3y agoMake it work, make it right, make it fast. https://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast https://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast
- deleted 3y ago[deleted]
- heisenbit 3y agoIt reminds me of Go (not the language). Beginners play straight lines, then one learns fancy moves and complicates everything while high ranked players patterns again exhibit straighter simpler forms.
- shireboy 3y agoI get what he’s saying, but definitely several gotchas. The main project I work on these days has code that definitely isn’t the shortest path already checked in to main and running in prod. I’m that guy- set up ci/cd, apm, upgraded frameworks, and am working on major refactor. I tell management we can move faster on features and bugfixes if we can reduce the complexity of existing code. But I do struggle with how far to take that. I worry I’m getting too deep and need to focus on features.
- Tade0 3y agoI think this advice is a little vague and therefore easy to get wrong. My approach converged to something that can be understood as a form of progressive enhancement, so basically providing the simplest usable version of a given feature, bearing in mind that eventually you'll have to expand it to what was originally requested - but that's all in separate tickets. Some examples: Six different payment processors? Start with one or two. SPA frontend? Start with server-rendered. The tech is there to smoothly transition from one to the other, but it's possible that this will never be required. That colour picker shaped like a peacock, following the mouse with its gaze? Just use a regular colour picker, but make it easily swappable. Where's that in the requirements anyway? What's interesting is that more often than not enhancements lose priority in favour of new features. Meanwhile some universal techniques like preferring pure functions where reasonable, using immutable data structures and actually having an architecture take as much time as doing sloppy work and go a long way into ensuring maintainability.
- remon 3y agoYour examples are very reasonable, and somewhat at odds if what the author is advising I think. As you say the advice is vague but I suspect it's also just fundamentally flawed. There are very few real world scenarios where "just make it work" is a good approach to tackle engineering problems that require senior developers (read; developers with extensive experience in the related problem domain) in the first place. My approach, which is I suspect it similar to what you're describing, is to define functional contracts first. Making them work is actually pretty low on the priority list, since that's consistently also the easiest thing to get right. The hard part is correctly defining expected behaviour, interfaces and so on. In your example the hard part is constructing an interface/API for a payment processor that satisfies your business needs on the consuming side and is reasonably implementable for the relevant major payment providers. Actually implementing one, the making it work bit, is just not where the senior expertise adds value. Unless, of course, you enjoy shipping glorified POCs to your customers because your stakeholders "saw it work" and blissfully ignored the metric tons of tech debts you just introduced, not to mention a skewed perception of the amount of effort needed for a that deliverable.
- 3y ago
- a_c 3y agoWant to add that the shortest path is only obvious from hindsight. And someone's shortest path maybe shorter than yours. Incremental iteration seems all the rage nowadays, but it didn't take one's taste and experience into account. If one's shortest path is long and winded, no amount of iteration will bring you to any sorts of local optima. The ultimate judgement is whether the things you built is getting use. If a tree falls in a forest and no one heard it, it didn't make a sound. It doesn't matter your code is good or bad. Build a mental map that leads you to building things useful
- nirui 3y agoBased on the context provided through the article, I think what the author actually wanted was a Minimum Viable Product, that is, instead of coding the shortest path first, you remove the need for unnecessary paths (and without cutting corners). This should create a reasonably correct product that is safe to use and easy to build on top of. But I do agree about the CI/CD part. In my case however, it's because many of these CI/CD services uses their own propriety config formats which are unfriendly for local testing. I can't remember how much time I've spent on hot-trying Travis CI just to get the build process right. I imagine things could feel a lot different if the services supports NixOS or just Dockerfile based script, because I can at least try the script locally before invoking the online service.
- ankaAr 3y agoWhile reading I was thinking of Dan Harmon's about writing. It is the same. Just write/code then, when the thing is done, start the reviewing stage. Anyway, you never know everything about your project when you start it.
- gjvc 3y agoA by-product of coding up a working solution is one of better understanding the problem. Unfortunately, this valuable result is invisible to many, and its existence seldom acknowledged. Documentation can serve as a proxy for it, to make it somewhat tangible.
- YuukiRey 3y agoI 100% agree with this. Whenever I force myself to really, really do the simplest and dumbest thing first it leads to a better outcome. I get to a working version of the feature quicker. From that, I get more insights. Sometimes I even realize that the simple and dumb version is good enough already. I would say that this is the single most efficient rule/heuristic I have for making sure my productivity stays high.
- dt3ft 3y agoI built FlingUp following the quickest path and compared to what we build at work.. FlingUp is lightyears ahead. Not held down by mindless patterns, very easy and quick to extend and build upon. Adding 1 new db field at work requires half a day of work until it is available for use on the frontend. The applications at work are so ridiculously overengineered that I sometimes feel we had too much money and time to throw at the codebase, engineers were experimenting and playing with pattern of the month. Maintainability is pretty much gone.
- cosmiccatnap 3y agoThere are so many articles that float through here that can be summed up as "do this, unless you should do that" with a title equivalent to "why you should always do this" Does this article present findings from other projects? Does it have a personal code story? Does it use any data or even antidotal evidence to support it's claims. The answer to all of these is NO it does not...it's just a half hearted article talking about a fundamental problem in modern programming with no real solutions other that an axe to grind that they can't even really elaborate on the origins of.
- Kalanos 3y agobe agile? haha. I refer to this as punching a hole all the way through and then pull the rest through. punch + pull.
- agentultra 3y agoPrototyping is a wonderful thing we should do more of. However, in my experience, when you take this approach the majority of organizations will make the prototype the product. You will never throw out that code. It will simply be added on to, papered over, and mixed up with everything else. What started off as a fine prototype becomes a error-ridden ball-of-mud that nobody understands anymore. Where working on that code takes longer and longer and carries a higher risk of introducing even more errors. The key thing with prototypes is that you have to mercilessly rip that code out before people start extending it and relying on it otherwise it's going to stick around.
- moffkalast 3y agoRecently left a company that mostly just wanted random stuff to be glued onto an early prototype for years now. It just gets progressively more and more infuriating as it almost becomes obvious that a full rewrite would take less time than adding the stupid <thing of the week> that the management wants. Doubly so with AI acceleration for new projects. After a while it becomes impossible to convince anyone to ditch the prototype because of all the testing hours that have been poured into it, making for a very strong sunk cost fallacy.
- sodapopcan 3y agoI worked at an org that did prototyping and it was fantastic. It was especially great for validating if a customer actually wanted the feature they were asking for (they often didn't). We _always_ threw away the work and started fresh if they did want it. What really helped keep us honest here was that we TDD and pair programmed. We also prioritized getting the prototype finished as quickly as possible. This meant writing really horrible code, calling variables and functions things like `foo`, and breaking other features if necessary.
- pksebben 3y ago> The key thing with prototypes is that you have to mercilessly rip that code out before people start extending it and relying on it otherwise it's going to stick around. A way to avoid this is to start with a clearly defined data model between components, and then _within the context of each of those_ hit the gas towards an MVP, flesh that out, refactor, etc etc etc. Not always a possibility, I'll grant, but a ton of headache can be saved by being religious about API-ifying those services which can be made into APIs. Stable I/O, chaotic move-fast-break-stuff for internals.
- joshdata 3y agoThis is a similar idea to how I understand the Elephant Carpaccio exercise by Henrik Kniberg & Alistair Cockburn (2013), from what I've been able to Google. The key idea is that work should be broken down into "vertical slices" where vertical means that the entire user story is captured, or as it's described at https://uploads-ssl.webflow.com/5e3bed81529ab12a517031ab/5ece238ef1473a6416860f46_Elephant_Carpaccio_exercise.pdf https://uploads-ssl.webflow.com/5e3bed81529ab12a517031ab/5ec..., "very thin slices, each one still elephant-shaped." The first vertical slice might be a mockup or very-low-fidelity prototype of the complete project and subsequent slices are enhancements following user stories. Horizontal slices might be, say, system components or other subtasks that leave you without something prototype-looking until all of the slices are complete. At least, this is how I've interpreted what I've read about it.
- joshdata 3y agoSelf-replying... I found the comments really helpful so I wrote up some thoughts on different approaches to tackling projects. Hope this might be helpful to others. https://joshuatauberer.medium.com/bullet-time-and-elephant-hearts-where-to-start-on-engineering-projects-with-unknowns-227ab7072c78 https://joshuatauberer.medium.com/bullet-time-and-elephant-h...
- zrkrlc 3y agoMind giving a concrete example? I read through the entire thing but couldn't make heads or tails of it. Is the point that your user stories should touch upon every aspect of your app, while still being incremental?
- joshdata 3y agoI think the idea is that for a slice of an elephant to be "elephant shaped," it has a bit of all of the key parts of an elephant - a bit of the trunk, a bit of a heart, stubs for four legs, whatever else makes an elephant an elephant. But what do the elephant's organs map to? I agree that the information on Elephant Carpaccio that I've been able to find doesn't really answer this. My best guess is the idea is that it maps to aspects of a user story like "get input from the user," "do some business logic," "show output to user." So even the first slice is a working prototype in some superficial sense. The elephant organs might be app components (UI, database, etc.), but in the first slice you don't have a complete UI (maybe you have text input) and you don't have a production database (maybe you just have an in-memory dictionary) and you don't have robust business logic. You have the whole stack, but each part of the stack is incomplete. That's what I think makes it a vertical slice. A horizontal slice (what not to do) would be one complete elephant organ. Maybe that's a production transactional database. So in the first slice you have a complete database or you've written the final business logic, but none of the other things that you would need in a mockup/prototype/MVP or an integration test. Anyway, this is my best guess.
- koromak 3y agoThe problem for me is that the shortest path often has nothing to do with the "best" path. Committing to it means you're never actually going to get it working right. You're going to get a knot in your stomach a year later when edits come down to your crappy MVP feature that feels like shit to work on.
- herval11 3y agoOnce you become super senior you actually realize what the author said here is not completely correct. This guy has experience, but he hasn't reached nirvana. There is a singular high level design pattern/abstraction that you can use in actuality to start off your projects. There is no name for this pattern but it is essentially this: Segregate io and mutations away from pure functions. Write your code in modular components such that all your logic is in pure functions and all your io and mutations are in other modules. Why does this style of organization work? Because delineation and organization of every form of application you can think of benefits from breaking out your program organization along this pattern. Your pure functions will be the most modular, reusable, and testable. You will rarely need to rearchitect logic in pure functions... Instead typically you write new modules and rearrange core functions and recompose them in different ways with newly added pure functions to get from A to B. The errors and organizational mistakes will happen at the io layer. Those functions likely need to be replaced/overhauled. It's inevitable. Exactly like the author says this section of your program is the most experimental because you are exploring a new technological space. But the thing is you segregated this away from all your pure logic. So then you're good. You can modify this section of your project and it remains entirely separate from your pure logic. This pattern has several side effects. One side effect is it automatically makes your code highly unit testable. All pure functions are easily unit tested. The second side effect is that it maximizes the modularity of your program. This sort of programming nirvana where you search for the right abstraction such that all your code reaches maximum reusability and refractors simply involve moving around and recomposing core logic modules is reached with pure functions as your core abstraction primitive. You're not going to find this pattern listed in a blog post or anything like that. It's not well known. A software engineer gains this knowledge through experience and luck. You have to stumble on this pattern in order to know it. Senior engineers as a result can spend years following the hack first philosophy in the blog post without ever knowing about a heavy abstraction that can be reused in every single context. If you don't believe me. Try it. Try some project that segregates logic away from IO. You will indeed find that most of your edits and reorganization of the logic happens with things that touch io. Your pure logic remains untouched and can even be reused in completely different projects as well!
- jstimpfle 3y ago
- m3kw9 3y agoYeah the over optimize before getting the proof of concept/getting it working minimally should always be recognized as gambling, as the n you may lose all that optimization if the stuff doesn’t work with it down the line
- roflyear 3y agoI like "throw away your first solution" or "be prepared to throw away your first solution." And the difference between a senior dev and a junior dev is knowing when to stop.
- gcanyon 3y agoI fell deep into this trap just yesterday, solving a Project Euler problem in Python. It involved a 2-million+ digit number. I'm just starting with Python, and while I know it transparently handles large integers, out of an abundance of caution I spent an hour optimizing to avoid dealing with greater-than-64-bit values, since the result needed is modulo a <64 bit value. My code ran in about 4 seconds. Then I thought I'd try a slightly larger optimization that involved ~128 bit values. That ran in a second, so obviously the switch to large integers either doesn't happen at 64 bits, or Python just handles it really well. Then I thought to just do the math and let Python sort the results. One line of Python. Took ~20 seconds to write. Calculated the 2-million digit number and then did the modulo. Ran in a small fraction of a second. <sigh>