9 ms·
Repeating yourself thrice doesn’t turn you into a 3x developer
- sznio 3y agoor just use Django: * Update your BlogPostModel, to add a ManyToMany(CategoryModel) field * Update your .html template with a for loop over blog_post.categories. * `django-admin makemigrations && django-admin migrate` Your life can be so simple. All you need to do is to reject Javascript.
- notmypenguin 3y agoWell, this sort of problem is typically handled by stuff like what is know as “scaffolding” in the Ruby on Rails world, and doubtless has other names. It’s about generating a “resource” and its CRUD stuff according to some agreed upon standards one can define, etc
- vvaibhav_desai 3y agoit turns you into a recursion XD
- anonuser123456 3y agoLoop unwinding is a compilers job.
- sch00lb0y 3y agoFor frontend people shipping application is easy because of tools like firebase
- failuser 3y agoI don’t work with 3-tier applications so I was surprised by the solutions, I was expecting a single origin for the schema at least to eliminate the need to triplicate some code. Is that a deprecated approach?
- beesnotincluded 3y agoI don't know how to react to this. It seems like the author trivializes the task to prove a point. It is never just a 'category'. Wrapped up in that is a whole bunch of functionality and expectations that always differ between projects. For example users want to search by, edit, manage and delete categories. Who should have permission to change them and edit them? How should they be shown in the UI, are they clickable, do they have perma-links? What category should old posts be given. How do you want to represent "no-category" state. Do we need to support multiple categories? What other side-effects happen when a category changes. Unless all product managers get in a room and define the canonical implementation of all web app features i think we are destined to do a lot more plumbing for a long time to come.
- lovasoa 3y agoThat is a good point. And that's why developing a new feature in, say, facebook, will always take a lot of efforts. But when you are a team of 3 with a startup to launch, for instance, you don't really care about permissions to edit categories and the no-category state. You just want that line of text at the top of the post that says which category it belongs to. And you want to do it in a way that will allow you to later easily come back to it and start thinking about the "no-category" state and multiple categories for a single post.
- fragmede 3y agoProblem is, even if you could get every single product manager in a room to hash it all out, three years down the line, when half of them have changed companies, and there is a whole new batch of them; when the business needs have evolved so that there are now two types of wholly orthogonal "categories" tags for every post that have their own separate management systems, and the product managers can't even agree on their functionality and expectations, what then? Job security for one, but it's hard to say in the abstract which coding style will be better.
- smrtinsert 3y agoSpring boot is pretty close to compressing the effort involved but the ui remains an issue
- jackblemming 3y agoYes it's tedious to write plumbing code, but it's also dead simple. Just write the damn code. Don't try to create some weird beast that "automagically" does the n different things. Just. Write. The. Code. Yes it does suck. You know what sucks worse? Zero separation of concerns and the tar pit you get from it.
- erik_seaberg 3y agoThis is sort of an argument for assembly over higher-level languages. Where do you draw the line for plumbing too tedious to write? I view abstraction as the single best way to make each other permanently more productive.
- jackblemming 3y agoGreat question. A good abstraction can offer an order of magnitude improvement in some dimension, whether that be clarity, speed, or the like. A bad abstraction trades a lot of one dimension for a little of another. In this case, I'll happily take an order of magnitude improvement in understandability, debuggability, extensibility, and a lower learning curve over a crappy ORM or DSL that saves me the effort of writing ~30 LOC; heck even ~5k LOC. If we get farther than that, we can talk. And even then, the solution is probably not going to be an ORM or a DSL.
- lovasoa 3y agoIt's not just writing the code. Writing the code is easy. It's maintaining it. And then debugging it. There is a limit to how many lines of code a single person can maintain.
- PNWChris 3y agoI'm of two minds on this, I both agree and disagree. Once a code base is a certain size, explicit but bigger can be a boon. Magic dynamic dispatch systems and other tools that simplify plumbing make onboarding and routine, drive-by maintenance way harder IME. I find that once you understand systems that have a dash of "magic", though, it is easier to add features and stuff. Single points of maintenance and all that. It's a continuum, with each side having different benefits.
- h4l 3y agoI've not used it myself, but https://htmx.org/ https://htmx.org/ combined with a traditional web framework like Django or Rails seems like it should greatly reduce the need to triplicate logic. At least for apps where the UI needs to be good enough rather than as good as possible.
- mock-possum 3y agoIs 3-tier architecture just MVC pattern? (Or I guess vice versa?)
- khaledh 3y agoNot necessarily. Three tier architecture means separating the client, the server, and the database into 3 different tries. MVC can be all in the server (e.g. for server rendered views) or separated between the server (model and controller) and the client (view).
- slondr 3y agoNo - 3-tier is an infrastructural pattern, not a software design pattern. It means you have a front-end, back-end, and database.
- cjfd 3y agoIt is an interesting question. If there really is nothing besides the same sets of fields repeated three times one could have some metadata that is used to generate what is necessary in all three layers. But... very often something special must happen in one of the layers. In the GUI it may be that the layout is not uniform, e.g., some fields appear below each other and some next to each other. Perhaps one field should not appear when some other field has particular value. In the between front end and back end there may be something special when one of the fields happens to be readonly and comes from some different source. In the database there may be something special because the legacy part of the code base also needs to read some fields and it has some special needs. And so on, and so on. It then becomes difficult to have anything besides three layers that mostly repeat fields.
- lovasoa 3y agoHey Ophir here, I'm the co-author of the post. What you say is on-point, and we should have mentioned it in the post. The way I see it is: at the beginning, everything is repeated three times on the three layers. Then, as time advances, complexity grows, and you start having much more specific requirements that will need one of the layers to differ slightly. The common approach is to just duplicate everything three times at the beginning to be ready for the moment when something needs to diverge. What SQLPage [1] is saying, is: when you start, just think about the database. Make it the single source of truth, and iterate quickly to find out what form the data you work on will need to have. You won't get it right the first time, so it's crucial you don't find yourself having to do the work three times for every change. And then, when you need some frontend-specific feature, make just a react component for it and integrate it in the application. Then, as the app grows, you will progressively write a full frontend for it, and an external backend, but you will never have to re-do the work you have done in the beginning. This has allowed me to make some applications that I wouldn't even have thought I would have the courage to start before. [1] https://sql.ophir.dev https://sql.ophir.dev
- holmesworcester 3y agoThe folks at Braid (braid.org) and Ink & Switch (inkandswitch.org) think part of the answer (at least for team collaboration applications) is to use CRDTs to mirror frontend state between devices collaborating on a dataset, making the backend mostly just one more device, maybe using encryption to keep users' data private from the backend. For something like a kanban board or a collaborative document editing app I think this could work really well, though I'm not sure how it generalizes. People from those communities say it's a relief building this way, though they're building simple proofs of concept still and it's not clear to me how well the approach holds up in fully fleshed out products. But it does seem to make a lot of sense in situations where a lot of the work involves keeping a bunch of devices in sync with each other.
- Zetice 3y agoOr you could autogenerate large swaths of this just from your schema. Is this entire article basically forgetting that as an option?
- nerdchum 3y agoYeah lol I was thinking the exact same thing. Autogeneration is a thing.
- t1mmen 3y agoThat’s my thinking, too. I’ve recently been using ts-rest.com for a relatively small project at work (<20 API endpoints, NextJS frontend, Postgres). Its been such a joy writing the “source of truth” as API “contracts”, and having everything else just work. With zero added effort, I get fetch/react-query clients 100% typesafe. Request & response validation on the API layer (which can easily be moved from eg NextJS API routes to Express or another framework). OpenAPI spec. Typescript and Zod types. All of that for free, without repeating myself. I like it a lot.
- lorenzotenti 3y agoAre we repeating history though? I've worked for a company that used Oracle plsql for everything (shall we return html snippets from the database as a reactive frontend, why not!, the whole business logic is in huge stored procedures anyway) and it was clearly an utter mess. Now, new tools may make this better, but every time I see too much business logic getting close to SQL I get suspicious. Supabase is another example of doing everything with postgres. Sounds cool, but is it maintainable?
- brtkdotse 3y agoTangentially, it’s curious there hasn’t emerged A Proper Way of version controlling and deploying stored procedures outside of “stick a bunch of sql scripts in a folder in the project root”
- vanviegen 3y agoIs there anything wrong with that approach? It seems pretty optimal to me, since you'll probably want to commit the stored procedures together with regular code.
- brtkdotse 3y agoNot really! It’s just weird that every places I’ve worked at basically invents it from first principles rather knowing about it.
- eddd-ddde 3y agoExactly, the reason the other alternatives feel better, is not because of how they work, but because of the tooling.
- city41 3y agoSupabase now has edge functions: https://supabase.com/edge-functions https://supabase.com/edge-functions
- lawn 3y agoUsing a magical construct to autogenerated the three instances also doesn't turn you into a 3x developer. Because they're never exactly the same, and you end up with heaps of special cases and handling and it would've been easier to write it three times from the beginning. And even if they start out as exactly the same, in any non-trivial codebase that won't hold true for long.
- mjw1007 3y agoI think Master Kaimu agrees with you: http://www.thecodelesscode.com/case/97 http://www.thecodelesscode.com/case/97
- moffkalast 3y agoYeah depending on the codebase size, it's often better to opt for some copied code and keep the ravioli encapsulation than trying to abstract everything into interfaces and layers of inheritance that just end up as a massive bowl of spaghetti as soon as requirements change ever so slightly.
- Terr_ 3y agoReally it all boils down to how accurately a seasoned developer can predict the future evolution of the product. Sometimes you want duplication because you believe the different code-copies will continue to diverge and require custom alterations. Other you believe the copies will remain structurally the same while growing in number, so you hollow them out with reusable helper functions or macros or whatever.
- adra 3y agoBusiness logic / rules are vertically integrated. You need your frontend, middleware, and databases to all align on how to store, transform and present information to meet business goals. Vertically developed software are the least efficient because you miss out on the core similarities of each vertical, so we use horizontally oriented frameworks that can reuse a lot of the boiler plate. Do you.nerd to add a cache layer later? With horizontally developed code, you can do that application wide with some annotations, properties, and library imports. If you wanted to do the same on a purely vertically developed code, you'd be changing N features with a bunch of duplication in each insertion point. One one winner with splitting tech on horizontal boundaries is that changing a feature is a largely high cohesion change. All the code bung updated in that commit are related to one another, and despite the fact that there are "many" places that the code needs updates, at least they all relate to one another. There was some effort in the java community to meet the problem half way with something called point cuts. This allowed some level of contracts which you could "insert behaviour into all instances of X" which had some success, but I haven't see it in the wild for a while, so I'm not entirely sure it survived.
- fatnoah 3y agoAh, yes, the old "look how easy building your simple CRUD app in [new tech] is" article. These always seem to work great (and do work great for some use cases) until things evolve beyond, and then one spends their day fighting the technology instead of actually building the product. Meanwhile, the n-tier dev you laughed at is still plugging away and getting some extra help because because the loose coupling between tiers made it easier to divide-and-conquer.
- lovasoa 3y agoI'm not sure what you refer to exactly, but none of the tech presented as solutions in the article really lock you into their model when things "evolve beyond". Quite the contrary, actually. Migrating from, let's say, Django, to something else requires you to basically rewrite your app from scratch. Migrating from SQLPage to Django requires you to run the standard django `python manage.py inspectdb`, then copy-paste your existing database queries, and your are ready to go.
- forgetfulness 3y agoORMs when you have to do the most basic selects and joins, with naive pagination: look at how easy it is, it's magic! Also ORMs when you have to do anything more complex, specially if they involve aggregations: welcome to my awkward undocumented APIs, you now embark on a journey through hard-to-search-through class definitions and source dives that you'll share with every programmer that will touch your code in the future.
- semicolon_storm 3y agoEvery ORM I've ever used has some raw SQL escape hatch you can use when you hit that edgecase. For the 90% of DB access that really is simple, ORMs are a pleasure. For that other 10%, if your alternative is raw SQL, just use the escape hatch and you're not worse off than if you had skipped the ORM.
- mrits 3y agoYou can also map or redirect the objects to database views
- benzible 3y agoI've found the Phoenix LiveView approach in the PETAL stack elegantly solves many of these problems. By rendering templates directly on the backend server, you can build the entire application - frontend to database - all within the same Elixir codebase. There's no need for a separate API layer or painstaking synchronization with a standalone frontend. Features that took days of work across all three tiers now take just hours in a single unified backend context.
- kosasbest 3y agoWriting plumbing and boilerplate only has to be done once. Likewise, a solid API to a database only needs to be learned once. Put in the grunt work early and you'll be flying.
- andybak 3y agoHe must be using a fairly crappy tech stack for the categories feature to be as complex as he makes out. For the sites I've worked on (Django/light js for progressive enhancement) it's a hell of a lot simpler. Either he's exaggerating or we've truly gone backwards from the halcyon days of Django/Rails
- zlwaterfield 3y agoWith the advent of AI, a substantial portion of the laborious tasks involved in the 3-tier model will likely be automated, making it less likely for most to move away from this approach. In my opinion, the 3-tier pattern was established for valid reasons, and any attempts to simplify it by removing tiers might inadvertently constrain developers, leading them to eventually revert back to the original model. Regarding solo projects, I agree that simpler stacks like BaaS or other innovations can be sufficient. However, fast-scaling companies often require the unparalleled flexibility and customizations offered by an in-house 3-tier model. This tailored approach ensures they can effectively meet the evolving demands of their growing operations.
- JHorse 3y ago[dead]
- gabereiser 3y ago3x gripe for the fully expected “How are we trying to solve this” pitch. Nice. Putting logic in your database is stored procedures all over again. Switch to a different storage engine? F#%ked.
- mkl95 3y ago> Ultimately, what is just a tiny line of text at the top of blog posts for the users becomes a daunting task, representing tens of hours of engineering work to implement. Something I have noticed about Fowler-esque / Uncle Bob-esque codebases is that usually only the guys who wrote it understand how it works. Which is either a blessing or a curse depending on whether you wrote the thing yourself or somebody else did it. And it also seems to defy the point of "making it easy to swap implementations by writing a ton of interfaces".
- wu2Fe7sp 3y agoI think the "writing tons of interfaces" part is just a lack of a sufficiently advanced type system at disposal of the languages they used at the time. If you take Clean Code, for example, the constant plumbing around *old* java deficiencies (at least in the edition I read) would simply not exist in Typescript.
- epups 3y agoThere's a value to compartmentalization, and this solution does not capture it. If you have to make one small change and it cascades through individual modules of your code, it may be true that more work is required, but you going through the work of implementing it "three times" comes with some advantages. For example, if there's a business need to change the database system, you have already taken care of most of the work to do that. Meanwhile, the proposed solutions sound like they would require a huge commitment to move all of your codebase to an obscure framework, with the presumed upside that you can sort of rely on them to properly abstract the other work for you.
- aaronbrethorst 3y ago...or you could use server side rendering and remove about half of the tasks on the bulleted list of "what you’ll probably have to do"
- Pxtl 3y agoFor a trivial case like this, something like odata and entity framework will get you 90% of the way there. The ORM provides both the webserver and data tier copies of the data. The problem I run into where I have to drop down into manual SQL is migrations. Every tool that promises free migrations fails me.
- noduerme 3y agoI just don't buy it about adding a "category" field to a blog. Add the db field to production and make it defualt to null. Did you write your query to SELECT * instead of the fields you wanted? Tisk. Okay, fix that. Add the property to your back and front end. Don't paint the html if it's null. Optionally make a 'categories' table and do a join. 30 minutes of work, max. If you're writing code where the front or back end data objects will break if you add a new db field, you're doing something wrong.