Transcription
FSD Design - the best front-end architecture. You don't need FSD. Why FSD hype? So-called videos by various web development authors. Hello, my name is Kostya, and I would like to figure out if FSD Slide Design is really that good for designing front-end projects. I watched more than fifteen videos about FSD, read a bunch of articles, designed several applications myself using FSD, and I want to make a brief summary of all this. What are the disadvantages of FSD? What are the big pluses and advantages? And is it worth using this approach at all when designing architecture. Besides analyzing this approach, I will also try to design an application using this approach on a real project, on a real mockup. The mockup will look something like this. We will consider how all this will be designed, and with the design on a real project, we will write some code at the end. I want to say right away that FSD is not the best and not the worst front-end architecture. I wouldn't think in such categories, but I would say that FSD is just a cool standard that has a certain set of rules for designing our front-end applications. In general, the main reason why everyone is discussing FSD is the lack of competition. There are no other architectural standards on the front-end anymore, which is why it is being discussed. But at the same time, if we look at the backend side, there are already a certain number of standards that everyone uses to this day. MVC, DDD patterns, they have been used for a couple of decades, and on the front-end, there is only one. Why is that? Let's figure it out and dive into history. When we talk about front-end and back-end architecture design standards, these things are completely different. Back-end development originated in the nineties and grew from simple scripts to complex microservice applications. In back-end development, there are dozens of methodologies, some development patterns, and best practices. And if we talk about the front-end, then, conditionally, 10 years ago, no one even thought about how to properly design an application. The front-end was just emerging then, the first frameworks had just been released. Everyone at that time wrote on jQuery. To write not complicated animations or validate a form, nothing complicated was required. No one thought about complex code organization. But over time, of course, everything changed. Complex applications appeared. with routing, with a large number of dynamic pages, global state was added, SAP integration, SSR, and a lot, a lot more. Accordingly, if in the backend some architectural patterns appeared in the zeros, in the mid-zeros, then on the front-end they are just starting to appear. Let's figure out at what stage the front-end is, and at what stage the back-end is. The back-end originated in the nineties, and at that time the standard was a monolith. In the early zeros, architectural patterns like MVC, Model View Controller, and DDD Domain-Driven Design appeared. This is a special set of principles for designing an application. And it appeared back in 2004, meaning in 2004 an approach that would later become a standard was already introduced. In the mid-zeros to tens, the widespread adoption of web APIs, layered architectures, and the architectural approach became very well-known. In the mid-tens, the microservice approach appeared. It is used by large companies. It turns out that by the mid-tens, when the first front-end frameworks were just starting to appear, the back-end was already a developed industry. It had its own standards and its own principles. Let's now briefly review the history of the front-end. In 2006, such a well-known library as jQuery appeared. It is used in many applications, and even now it remains very popular. In 2010, the first JavaScript libraries began to appear that help to correctly design and structure code, such as Backbone, Angular, and Knockout JS. They all had different approaches to architecture. Backbone used Model-View-View models, something between MVC and MVM, and Knockout used Model-View-ViewModel. In 2013, the first version of the well-known React appeared. In 2014, the first version of Vue.js appeared. React introduced the concept of Virtual DOM. In the future, this will become the main concept in React and Vue.js. In 2015, Redux appeared, written by Dan Abramov. It uses the flux architecture approach there. In 2017-2019, the front-end began to become more complex. Routing was added, SSR was added, the concept of micro-frontends was added, and everyone began to think about how to properly design an application. Concepts like modular architecture, atomic architecture flashed by. I still remember there was such an approach as DAX. And in 2021, the Feature-Sliced Design feature appeared, the website was launched, and the main documentation. FSD Design is inspired by DDD and tries to solve problems in scaling applications. This was the first serious bid for a front-end application design standard. Has it ever happened that you start writing a feature, and after an hour you realize the code is falling apart, the whole structure is breaking, and it's no longer clear where the business logic is and where the UI is? In fact, this is the case for most developers. Many developers don't know how to design a specific task. I myself have experienced this pain on all my projects, of which there were more than thirty. And only after years have I developed a system that helps to quickly and correctly design an application. Now my path can be completed not in 8 years, but in just 3 hours. I recorded my intensive course, in which you can design your features, understand where to put business logic and where to put UI, and you will understand the architecture better than 80% of developers. In the intensive course, you will master the theoretical basis of FSD to better understand the architecture. You will practice feature design in practice and also receive homework on a real project with code to hone your skills. Sign up right now. The first 20 spots will be at a discount. And there is also a free introductory lesson. Come and learn. Comparison with modular architecture. In general, on my projects until 2023, I always used modular architecture. What do I mean by modular? I mean that I had some technical layers isolated and there was a main folder like Company Features or something similar. That is, in the Companies folder, all these business features, business context were stored. And over time, it naturally became a dump. And technical layers were something like a common folder, where common components were stored, where common utilities were stored. Plus a separate layer for working with the API, a separate layer for working with the store. This approach has its obvious disadvantages and its obvious advantages. The obvious advantage, I would say, is that the entry threshold is quite simple, but when scaling the application, obvious problems begin. The Company folder with business features simply becomes a mess. You can't figure out what's going on there at all. FSD is designed precisely to solve this problem. Let's break down the essence of this approach. What is it at all? Why all these divisions by meaning, by some layers, what kind of approach is Feature-Sliced Design? Feature-Sliced Design is an approach to front-end application design that helps to structure code competently. The main thing it says is that it structures code by meaning, not by technical layers. In classic projects, we often see divisions like components, pages, as I mentioned earlier. This approach seems logical, but only until the application starts to scale. When the project is small, everything is fine with it. When the project grows, problems begin. It's unclear where to find the necessary logic. Components often start to be duplicated. FSD proposes to structure the project by features, that is, by meaningful parts of the interface that the user actually uses. That is why this architecture uses the Feature-Slice approach. That is, we don't create one large folder where we will store all our components. We look at our product and say: "Here we have the functionality for adding to the cart, we have authorization, we have viewing user profiles or viewing orders." Each such element is precisely a feature, i.e., a semantic module. And in it, we store all the logic, our UI, our API work, our utilities, perhaps. That is, the user himself does not think in terms of our components or hooks. The user thinks in terms of, I don't know, the add to cart feature, the view order feature, the authorization feature. FSD focuses the developer's attention on business needs, not on technical details. Let's break down the key layers that FSD divides into. These are Shared, Entities, Feature, Widgets, Pages, and the Application itself. In general, these layers have basic rules. The first is that you cannot import from top to bottom. That is, if you are in your Entities, then you cannot import anything from Features or Widgets. But, for example, the Shared layer can be used everywhere at every level, because it is at the very bottom. And the second rule is that slices cannot import each other. By slices, we mean a small piece of functionality that has its own UI, its own logic, its own state. Mostly slices are located in Entities. Let's go through the layers in more detail. For example, what is Shared? What can we put there? Shared usually consists of small functional blocks, small building blocks. Well, it's often something like a kit, i.e., a dumb reusable component, or some utilities that we will use everywhere in our application. In Entities, we put some models and some logic of our business entities. In Features, we put some finished piece of functionality that can already solve something, a specific user task. Widgets are already large functional modules used for pages. Pages, well, I think it's clear here, these are pages that are used as part of routing. And in Application, we put all the application configuration, some stores, and similar things. Let's go into more detail about each layer and look at examples of what they can be. The Shared layer is the very bottom layer. Everything that can be reused, that we can use anywhere in the application, is put here. And that which has no business meaning. These can be some basic UI components, well, some buttons, inputs, modals that we use very often. Utilities, well, for example, format date or validate email. Constants that will be used often, well, for example, it's some basic API URL, yes, also some TypeScript types, maybe some other wrappers, I don't know, some grid layout, conditionally, yes, or some card, but it's important to ensure that they are without business logic. Well, and some styles or some design tokens. Entities is a higher level. Business entities that describe the subject area are located here. It's important to understand that this is not UI and not a business feature, i.e., these are some data models, their visualization, and the logic around them. That is, they do not have any specific user scenario. For example, it could be a User, i.e., displaying their profile, their model, their types, or a Product. That is, it's some product card that we see, i.e., the schema of this product and the data loading itself. But the point is that the User entity can be used in ten different places. That's why it should be independent of a specific scenario. Entities include the description of the model, UI, API work, some utilities. So, the structure of the Entities folder will look something like this. Models store types and slices. That is, in the model folder, we will have some state and logic. That is, approximately there will be some types, selectors, slices, some validation. UI, accordingly, will be in visual components. That is, it's a visualization of the entity, but without any actions. That is, there will be no business logic. In UI, we can only use the Shared folder and the Model folder. In API, accordingly, requests to the server, yes, i.e., requests related only to this entity. Well, and of course, it's best to wrap API work in some adapters, not just like that. or something similar. That is, to write some adapter when working with the API. In Utils, accordingly, some utilities that are specifically related only to this entity will be placed. Well, for example, I don't know, there will be getUserDisplayName, yes, it will take a user and display the necessary information. Let's move on to the Features layer. Features is the central layer of FSD, where business logic resides. Each feature is a complete piece of functionality that solves a specific user task. That is, for example, it will be some authorization, a news feed, a user card. What makes a Feature a feature? First, it must be self-sufficient. That is, it contains everything it needs to work within itself. This will be UI, logic, API work. Second, it will be isolated, i.e., minimally dependent on other parts of the application. And third, it is user-oriented, i.e., it solves a specific problem. That is, for example, it's some product purchase. Features should not know how and where they will be used in the interface. They simply represent functionality that can then be built into any part of the application. Examples of features, how we can use them, for example, adding a product to the cart. We will use product/toCart or user settings profile/settings. The next layer is Widgets. Widgets are a large template that combines the interface from several features and adds additional UI elements. What do widgets do and where can we see them? Widgets combine features. For example, on the user page, we can see quite a large number of features. That is, we will see a list of friends, some settings, profile editing. Widgets add layouts, i.e., common styles, common grids, common indents. They also handle interaction scenarios. That is, for example, some lazy loading will be added in widgets. Examples of widgets, for example, Profile Widget is a profile page that will include features for posts, subscribers. Checkout Widget will be an order processing block that combines the cart, selection of specific delivery, and payment. And the last layer, App. App is the shell of our application. Everything related to configuration, initialization, and some global application integration goes here. Routing, store setup, some providers, for example, ThemeProvider or Internationalization provider, global styles, rendering, and similar things often go here. What is the difference between App and Widgets or Features? App should not know anything about business logic. It only connects pages, widgets, and ensures their operation. Also, App does not contain any UI, it is purely a wrapper. Well, and App itself should be super minimal. That is, if we can move something out, to widgets, it's better to move it there. Let's talk about the pros of FSD. Where is it really good and where can we use it. The first advantage I would highlight is standardization. This is the main advantage. FSD has no alternatives at all. That is, no single front-end architecture standard has been invented yet. And FSD is the first bid for a standard. No modular architectures, no atomic design can be described as a standard. Why is it a standard? Because it dictates clear rules: business logic is in features, interface composition is in widgets, and global routing settings are in the application layer. That is, this means that if a developer already knows how the FSD architecture is structured, they will come to a project and immediately understand how everything works. That is, they will come to a project, they will be given some task with fixing authorization or something like that, and they will immediately understand that they need to go to Features. The second advantage of FSD is scalability. When a project grows and becomes large and extensive, it is very important that new features do not break old features and do not interfere with each other. FSD in this regard provides a clear structure, a clear hierarchy of layers, and this structure helps to avoid chaos and misunderstanding. If we used the standard approach where everything is in the Components folder, we would spend a very long time searching and not understanding where to put anything. The third advantage of FSD is that it is based on the principles of loose coupling and high modularity. That is, what does this mean? Let's talk about it. Each feature is maximally isolated. That is, it will have its own UI, its own logic, its own styles. That is, it does not depend directly on the rest of the project. This will be very useful if the project is very large and is being developed by several teams at once, for example. That is, each team will contribute to the project without interfering with other teams. The fourth advantage of FSD, I have actually mentioned it already - it is the rejection of the huge Components folder. When you don't have a dump of components in this folder, it will be much easier and clearer for you to design an application. Instead of a components folder, features will be used. Components are not lying around somewhere. They are located specifically in our features and implement specific functionality. Well, that is, a feature is a complete, finished piece of functionality. Let's talk about the disadvantages of FSD or where FSD would be incorrect to use. As the first point, I would highlight that FSD is not suitable for small projects at all. That is, for a large project, it will be great for a scalable one. But if the project will last for a month or two, then I don't think there's any point in dragging it there. If you want to quickly write a project, sketch something out, look at it, make a quick API, then FSD, I think, is not suitable here. That is, while you are setting everything up according to this structure, understanding what goes where, more time will be spent on this than on creating some features. The second disadvantage of FSD. I would say that each developer understands FSD in their own way. I had an example when I came to a project, there were already the beginnings of FSD, and the other developer and I had misunderstandings, i.e., which folder is better to put something in. He thought it should be put in Features, I thought it should be put in Entities. We had a misunderstanding, we didn't understand each other, how it's actually correct according to the standard. This can lead to arguments at code reviews and real misunderstandings about where to put something, in which folder. The third disadvantage I would highlight is the scattering of logic throughout the application. This point follows from the previous one, but it's slightly different. That is, the scattering of logic itself is not always clear. For example, for me to understand how a feature works, I need to go through all the folders, understand where everything is located, in Widgets, Features, in Entities, and only then will I be able to understand what's happening there. In general, according to the FSD concept, all logic should be stored in Features. But in practice, when you actually start doing something, working, some part of the logic, so to speak, drifts into Widgets. And the last point I would like to note, as both a plus and a minus, is the entry threshold. That is, the entry threshold is quite high. If you come to a project and you don't know what FSD is, you will naturally have to go and read the documentation and understand what's happening, look at some examples, watch some videos. That is, any developer who has not yet had experience with FSD, but worked according to the standard architecture, will have to study all this, they will have to spend time on it. But on the other hand, if a developer already has experience, they will quickly get into the current project and be able to quickly design something and develop features. Let's summarize everything. FSD Design is a cool approach to design. It's a standard, but it's important to understand that it's not a magic bullet that all projects need. That is, you need to approach it with understanding, whether you really need this approach for your project. If your application is potentially very large and will grow, it will be developed for years, then, of course, it can be used. But if you have a small project, then there is no point in it. Let's break down the FSD layers with a real example. I have a mockup prepared by a designer. She drew me a certain number of pages on which we can see a large amount of functionality. Let's try to break down all these layers by FSD using the example of this page. First, I will break down the main layers and then look at others. First, I suggest breaking down the Shared layer. These are reusable components, reusable utilities. In this example, in Shared, I will put a UI folder and in it I will put specific components. What do I see, what components can be reused here? This is, for example, a button, which will most likely be used very often. This is an avatar component. As we can see, it is in the upper right corner. And also in the quick transfer block. Such a component will also be used often, as in the example with the button. Card component. Well, accordingly, if it's a banking application, the card component will be used very often. Of course, these components will be designed in such a way that they are maximally reusable. That is, this card component can have various stylings and various texts. For example, here we see that on the card number we have asterisks, i.e., they hide the current number, but there can be a situation where we will show these numbers, as in the example with the avatar. That is, the avatar in the upper right corner has no inscription, but in quick transfers, as you can see, there are inscriptions below. And we can also see a large number of charts here. I would also allocate a separate component for this in Shared. I would call it Chart. Well, here, as we can see, there are several charts. We have a pie chart, we have a simple line chart. Therefore, these will also be components that we will use very often. Next. Next folder. I would create Lib. Well, these are our so-called utilities. That is, these are functions that we will use very often. For example, I will add formatMoney here. That is, values can come to us from the backend, and we definitely need to format them. As we can see here in the card, for example, there is a comma, in quick transfers, a dot, and in transactions, we also see a comma. Therefore, Lib in Shared are utilities that we will use in every part of our application. Next, I would separately highlight constants and some assets, yes, i.e., some icons that we will use very often. That is, here, for example, icons in transactions. We see here an icon of a card, an icon of money, or in the cards themselves, we see that there are certain icons. For example, Visa, Mastercard, and similar. Let's move on to the next important logical layer. This will be Features. Why we are not considering Entities first is because, in my opinion, Features is a more important layer than Entities. That is, Features is the main functional layer with which we will often interact, especially when talking about business logic, business context. I would highlight a Cards folder here and highlight the Select Card functionality. That is, we have a My Cards block here, and we can select a card and see its number, its expenses, its balance. Next, I would highlight the Send Money feature. That is, we have a quick transfer block. And we can enter an amount and send it to the desired person. That is, the functionality sounds like we can quickly transfer money to a user, yes, that's why I call the feature SendMoney. The next block can be called View Transactions, i.e., we have transactions, we see some deposit or some withdrawal, some money came to us, yes. The next feature is balance history, for example, where we have a large chart. And another feature is expense statistics, yes, we see how much went to what: 30% for entertainment, 15% for some expenses, and 20% for investments. That is, on this page, we can immediately track how much went to what. Therefore, I highlight such separate features. Let's consider Entities. Entities are entities that will be included in Features. Accordingly, what entities would I highlight here? First, I would highlight the User entity. Second, I would highlight the Card entity itself, which we will use often. Then the Transaction entity and the Balance with Expenses entity, respectively, because I have them on this page. In Widgets, I see the division as follows. The first widget I would highlight is My Cards. That is, this panel with cards, yes, we can see all of them here. We can click on a current card and see its balance. This widget will potentially be reused on other pages, so I would put it in a separate Cards Panel and use it on other pages as well. Next, the next widget. Here we can highlight the Transactions widget, yes? That is, we see transactions, we have some debits for them, and this block will also potentially be used somewhere, reused on other pages, so we put it in a separate Transactions Panel widget. The next widget is the quick transfer widget, yes? That is, we have certain functionality where we can choose to quickly transfer money to someone. And we have certain contacts here to whom we often transfer money. We can choose, enter an amount, and send. This block can also potentially be reused often somewhere, so we put it in such a Quick Transfer widget. And, accordingly, widgets with our charts, i.e., the expense statistics widget and the balance history widget. We see that we have such blocks, which are potentially also widgets. I also put them in separate blocks. As the next layer, I suggest considering Pages. That is, we have a certain number of pages, and we can divide them. The first page will be our Main Page, the main page where we can see our balance, our transactions. The second page will be the Transaction Page, because we have a transaction page. We can see recent transactions here, what happened and why. The next page I would highlight is Account, because we have an account page where we can see our balance, our income, expenses, some transactions, and similar. And the next page I would highlight is Invest Page, because I have an investment page where we can see income, where we can see balance and profit margin, what stocks are available now. There are, of course, many more pages that the designer drew for me, but I will highlight these four main ones. Now let's look at our last layer. This is the App layer, the Application layer, where we usually put some of our settings. We usually write some of our providers, routing, and similar things there. Here I would highlight the main thing - the Layout, which we will often reuse. Accordingly, here, as you can see, on each page, we have a certain layout with a sidebar. We have a certain header that is used on each page. Then come the styles. Well, styles, I think it's clear, these are styles that will be global and should be included at the application level. Then comes the router setup. In fact, this is very important, and now almost any SPA will be built with routing. Then the Providers folder. Well, there can actually be a huge number of providers. Here I have highlighted typical providers that exist. First is the Theme Provider. Well, it's clear, some theming, for example, a dark color scheme or something similar. Then comes the provider that we can use for internationalization. If the application, for example, is used not only in Russia but also in Europe, then it can be translated. Then I highlight the Redux Store Provider, but in fact, it can be any store provider. That is, I indicated, for example, you can use Zustand, MobX, anything. That is, this is a provider that will be responsible for our state manager. Well, and the Router Provider itself, which will be responsible for the router. All this, naturally, will be written in App.js. That is, on such an example, we have considered how this can be divided by FSD. Such an application, such an internet bank, how it can be divided. Watch the free lesson on FSD and also come to the Intensive, the link will be in the description. In it, you will gain practical and theoretical skills and also be able to better understand how to design your applications. Thank you very much for watching. Like and subscribe to the channel. Good luck to everyone.