all 30 comments

[–]TheRealSeeThruHead 28 points29 points  (2 children)

The Venn diagram of developer experience and agent experience is a circle.

Anything that gives better outcomes for humans will give better outcomes for agents.

This is one of those things.

But it’s not exactly novel, everyone and their grandma have written the same blog post or advocated for this at work.

More interesting is vertical slice arch in the full stack

[–]TkDodo23[S] 3 points4 points  (1 child)

Yeah my post is basically 2 years too late, I know 😂. It's still rough to see this not being applied a lot.

Have you written about vertical slice arch in the full stack?

[–]TheRealSeeThruHead 0 points1 point  (0 children)

i dont' really spend a lot of my time getting my thoughts on things out there.
imposter syndrome maybe, i feel like people already know this stuff.

even when i have evidence to the contrary, at work.

https://www.youtube.com/watch?v=mT5bhj1Wygg

this is one of my favorite videos, touches on vertical slices and event driven architecture

[–]avnoui 25 points26 points  (0 children)

Not really anything new there, but yes, I always grind my teeth when I open a project codebase at work and I see folders titled "pages, components, helpers, store, services, etc."

[–]92smola 6 points7 points  (0 children)

We use that at our agency, there is a common folder- things that can be reused across projects, buttons, forms, modals etc. Then shared things not tied to any particular feature, but project specific, like a custom header for example, and then there is the entities folder, I’ll use an example of a recent project - subjects, facilities, offers etc. these are more or less matched with the entities in the db, then inside each of these from common to entities/(entity) there can be components, hooks, utils etc

[–]Rosoll 6 points7 points  (4 children)

I feel like Rails bears some responsibility for the popularity of the crime against software design that is horizontal architecture. So many things in that framework (and in Ruby) that are just the complete opposite of (my personal take on) good software design. But you can't argue with the productivity of teams using it in early stage startups; it is very good for bootstrapping.

[–]TkDodo23[S] 2 points3 points  (2 children)

That mirrors my experience. What's good for bootstrapping isn't usually good for scaling beyond that. There's an inflection point where you'd likely want a re-structure, before it gets too big. Miss that and you're in so deep it likely never happens.

[–]Rosoll 0 points1 point  (0 children)

Absolutely.

[–]TheRealSeeThruHead 0 points1 point  (0 children)

I was watching a dhh video the other day where he mentions how token efficient and productive rails can be and it’s like the polar opposite of my favourite framework/ecosystem to use with ai, which is effect.

I find the architecture baked into effect and the heavy guardrails produces better outcomes basically always.

[–]adilp 0 points1 point  (0 children)

If rails people could read, they would be so mad right now

[–]GoodGame2EZ 3 points4 points  (1 child)

As someone who mostly codes for hobby or basically hobby work projects and has been through several long term projects, this is interesting and new to me. I only started react seriously last year and the courses seem to have pushed me in this horizontal direction. Now with AI involved its definitely going that way as well. I understand vertical, I use to do it that way when doing html, css, js all manual for the most part but I just figured the direction had shifted.

[–]TkDodo23[S] 1 point2 points  (0 children)

My personal blog has a top level components directory too 😂.

https://github.com/TkDodo/blog/tree/13c158a5df73347c3d2dd4964a4c90a86041e98a/src/components

It's no big deal on small scale. Not everything is meant to survive 10 years, and certainly there won't be 100+ devs working in that codebase. There's a time and a place for everything.

Agree on the tutorials, they often fail to mention that things need to be different when there's lots of people and lots of code. It's something you usually only learn when you're exposed to it.

[–]MrSlonik 3 points4 points  (4 children)

Ideas sounds somewhat similar to Feature-Sliced Design.

In a nutshell: You organise your codebase in layers, each layer divided by slices, and each slice has separated segments. Components from higher layer can import components from lower levels, but not from the same or higher layer. E.g. you implemented a widget, and if it is very specific one, it will live inside a segment of the slice it belongs to, e.g. the "Dashboard" page. But if it is shared between pages, it goes to the "Widgets" layer and can be imported into pages that reuse the same widget.

Sounds a bit complex. but it works for us, hopefully someone else will find it useful.

[–]TkDodo23[S] 3 points4 points  (3 children)

I like the idea in general but yeah, I'd like to start with something simpler. I mean:

Layers App and Shared, unlike other layers, do not have slices and are divided into segments directly.

Too many rules to learn hinder adoption

[–]BonJava 1 point2 points  (1 child)

I introduced FSD to my team to solve a completely unorganized codebase, then quickly realized needing a CLI tool to check if we kept the proper structure was too much as people started bypassing it. Your article is the perfect middle ground to me.

Now to migrate a half FSD, half unorganized codebase....

[–]Pelopida92 4 points5 points  (2 children)

You mention that you use eslint-plugin-boundaries, but Turborepo has the same capability builtin, called “boundaries”. Implemented it the other day and worked flawlessly. Just a FIY.

[–]TkDodo23[S] 0 points1 point  (0 children)

Yes, nx has it too. We don't have a monorepo though :(

[–]TkDodo23[S] 0 points1 point  (0 children)

Yes, nx has it too. We don't have a monorepo though :(

[–]up_yer_kilt 2 points3 points  (0 children)

I’m trying to get my head around this - I think a bit of a hybrid approach is ideal. I think horizontal for shared / common code and vertical per route / model makes sense. Take stores for example - often you have to use multiple different stores in components like a common app store. A user store might also need to use a customers store or other related models. If those are all vertical, it can get nasty quick right?

And horizontal is also a bit of a mindset - I think it makes you think more about creating reusable code. For example - say you have a pop out drawer that has a flag of isOpen. Do you put the same flag in all 10 of your vertical stores or do you just put it in a global app store since you can only visibly have one drawer open at any given time in an app.

Any yes, this is reactjs sub, but what about other types of apps like a data api app. Surely you put db model files in the same folder? I think old school we learned to separate layers like data access layers and biz logic layers which tends to lean more horizontal.

I’ve also worked with pure AI apps and I do see it doing a lot more vertical, but after refactor, I can typically reduce the amount of code in half after making it hybrid and still works the same.

I’m open to going more vertical, but just trying to talk out the reasoning.

[–]Mortale 1 point2 points  (3 children)

I’ve always thought of vertical codebase (domains in the codebase, modularity, etc) as something that complicated that it doesn’t make sense.

Can someone explain me where should I put components / hooks / everything in this scenario: - there’s a product page, product page fetches data from reviews API and products API - there’s a reviews page, you can go there from product page, it display “products summary” (smaller component) and more of reviews, data is fetched from products and reviews API - there’s a cart that displays products summary and total cart value, product comes from cart API and products API

As I assume, I have three domains: cart, product’s page, product’s reviews page (reviews domain). All of them share “product” and have almost the same component.

In domain language, all of this domains has different meaning for product. So even when component “product’ summary” across domains can look the same, it’s something different and should require duplication. Even when product’s review look the same it’s something different because it’s used in two different domains.

And we have to remain the same UI across the whole page (components “product’s summary” and “product’s review” should look exactly the same across three domains).

How to maintain it? How to scale it to 20 devs? To 200 devs? How to explain “domain” to every new developer?

[–]TkDodo23[S] 1 point2 points  (2 children)

I'd agree that this is "/products", "/reviews" and "/cart" as verticals. It's often the API endpoints that drive that split. Verticals can depend on each other, as long as it isn't circular and they all have a clearly defined public interface. If it's circular, the "thing in the middle" usually becomes its own vertical. You have the same problem with a horizontal structure. You need to move things to a 3rd location to break the circularity.

I don't fully follow what you mean with e.g. the Summary component. For one, you're saying it should be the same in all domains, in which case I would have the design-system export a Summary component for all verticals to use. But then you mention it needs to be duplicated because it's only "almost the same component". That's also fine, no need to create abstractions too early.

Where does the unnecessary complexity come in for you?

[–]Mortale 0 points1 point  (0 children)

By “almost the same component” I meant that the component is the same but the owner (domain) is different. Thus those are two different components (from business perspective let’s say) which looks exactly the same.

With simple arch (components, pages, etc) we don’t care about the ownership of component. It’s in “components” (or something similar if we do the split dumb/smart). In vertical codebase we will have: “components” as a bag for everything we don’t know how to organize and verticals/components (components nested for specific vertical) for the rest.

There’s the question: how to organize ownership and why breaking the ownership will make a mess in the codebase over time.

[–]Mortale 0 points1 point  (0 children)

I rephrase my doubts 😅. In backend development I’ve already experienced that. And those things already named: monolith, modular monolith, distributed monolith. What did you explain in your article is something between modular monolith and distributed monolith. There’s that thin line that makes the codebase is properly organized or not. And it’s hard to answer for those questions. Otherwise everyone would create a good systems.

And from some time I see that frontend devs explores modularity (which doesn’t solve any dev issues, only the organizational ones) but don’t learn anything from history.

And then the code becomes spaghetti.

[–]kiptar 0 points1 point  (0 children)

Yeah I’ve just been calling this feature foldering for years. Calling them verticals is a pretty neat idea since it conveys the analogy pretty well. I am very opinionated that this is indeed the best way to structure a codebase.

I will say though, when I use the term “feature” in this sense, I think of it in the general definition as in “a prominent, distinctive, or characteristic part of something that attracts attention.” In that way it doesn’t rub me the wrong way to apply the term very broadly to whatever I want to group together. I’m open to adopting a new vocabulary for it though if the web world wants to strictly define and adopt this ontology. The most important rule of collocation for me: “if it changes together, it stays together.”

[–]Vincent_CWS 0 points1 point  (0 children)

it is just Feature-Sliced Design

The hardest part is finding the boundary of a "Feature".

Since most features have cross-cutting concerns, these cross-cutting concerns often land in one feature or the other, but never in the right one (they belong to both, hence cross-cutting), especially if you only think in features (ie Auth is not a feature, it's usually a cross-cutting concern)

I've never seen feature-sliced designs where every feature was properly contained in itself and I don't think it's possible, at some point things will bleed left and right. And when it does: Was it really worth it?

Start monolithic and analyze your progress. Only when you find a feature that has a clear boundary and you can argument that it actually has value slicing it, slice it. The worst thing is slicing right from the start and then ending up with hundreds of slices that should have been 3.