Designing a UI for Microservices
About this video
How do we design a UI when the back-end system consists of dozens (or more) microservices? We have separation and autonomy on the back end, but on the front end this all needs to come back together. How do we stop it from turning into a mess of spaghetti code? How do we prevent simple actions from causing an inefficient torrent of web requests? Join Mauro in building a .NET Core composite UI for microservices from scratch. Walk away with a clear understanding of UI composition and how to architect a microservices-ready front end.
🔗Transcription
- 00:01 Mauro Servienti
- So welcome again. And welcome to Designing a UI for Microservices. As said, my name is Mauro Servienti. So I'm a remote worker. So I'm fully working remotely for an international company. Well, by the way, we are all remote workers. The interesting thing of the company I work for is that there's no one living and working in the same city as anyone else in the world.
- 00:29 Mauro Servienti
- So we're all remote. In fact, we, we call each other a kind of dispersed company instead of distributed one. And the problem I have is that the flat where we live in with my family is too small. So it's even too small for three people. So it's basically impossible to find a place for myself to work with.
- 00:53 Mauro Servienti
- So what I did is that I decided to rent a small office that is roughly a kilometer apart. And what I do is basically I bike ride there every single time I have to work. And right now, I am in my office. So one of the problems is that I also like bananas to have as a snack. And if you ever had an experience of bike riding while carrying a banana with you, the interesting problem is that your banana is not really happy at the end of the bike ride. So that means that the backpack basically eats your banana.
- 01:31 Mauro Servienti
- And that's the thing that once you experience it a couple of times you really want to fix. So what I did is that I headed to my favorite online store and decided to buy something to solve the problem, to begin with. And I found this, a banana protector. By the way, there's tons of them. So there is a list of possible choices that is endless.
- 01:55 Mauro Servienti
- And as soon as I was looking at this page and the first thing that came to my mind as the solution architect that always lives in the back of my mind started asking, "But hold on a second, does a page like that really exist?" Think about let's try to imagine the Amazon codebase. If it was an MVC .NET application. Does a product controller class exists in the codebase?
- 02:32 Mauro Servienti
- Does a product details view exists in the codebase? And that's an interesting question. Because if we have a deeper look at what the banana protector details page is, we can start saying that a page like that doesn't really exist. We have a bunch of information living in the page that are probably coming from different sources.
- 03:00 Mauro Servienti
- So if we try to identify them, we can immediately say, well, hold on, there's probably things coming from something we can call a catalog. For example, the product name, or the product images, or even the customer reviews, and the product stars. And then we have the price that's probably coming from something we can call sales, that someone else that is different from the catalog, making decisions on about the price we want to sell the item for.
- 03:31 Mauro Servienti
- And then there's a warehouse that has information about how many items are left in stock. And then finally, there's something like shipping, for example, that tells to the user in this case me well this item is ineligible for free shipping. So there isn't really a single place where all these information are stored in order to be retrieved and then displayed on the page.
- 03:58 Mauro Servienti
- And by the way, warehouse is usually a liar. So there isn't really nine items left in stock. That's by psychology to try to convince you to buy the item. But that's another story. So what are we watching here? We're basically observing something we can call domain model decomposition.
- 04:22 Mauro Servienti
- So what we have is really the single responsibility principle applied to data. So we have services or microservices, if you will, or aggregates bounded context, subdomains call them as you will. It doesn't really matter the name you give them. I like to call them services, but that's my preference.
- 04:45 Mauro Servienti
- So we have services owning their own piece of information. Each one owns a subset of the information that is then displayed to user on what the user perceives like a single page. And at this point if that's true, the next question should be, how can we design something like that?
- 05:12 Mauro Servienti
- So think about it, that we have information coming in, stored in different places, that needs to be aggregated in some way onto a single page to display users something because we cannot expect users to navigate from page to page, seeing on page one, hey, here is a banner protect for you. Go to the next page, there is a price, and then go to the next page to see if it's available, and then go to the next page to see how does it cost to ship it or if it's free, whatever.
- 05:45 Mauro Servienti
- And the first reaction to such a question, how can we design something like that is the temptation. So it's very tempting to come up with a technical solution towards a non-technical problem. So we have these four services, each one owning a piece of the information and it's very easy to say, well, what about we do something very easy?
- 06:10 Mauro Servienti
- We extract data from this services into what you can call a denormalized API storage think to it like elastic search whatever a relational database. It doesn't really matter. So we group data related to each other into what we call a product into a denormalized storage that is then consumed by a client. And we call what's exchanged between the denormalized storage and the client a view model. Someone called them read models.
- 06:53 Mauro Servienti
- So the sad truth if you think about it, is that that's cache. So we're basically extracting information from what they are stored and owned, that's the most important thing into something that doesn't own anything. And then we'll start having all the problems that all the caches have. So what happens if the price change? Now we need to update the cache.
- 07:24 Mauro Servienti
- What happens if where the items stored in the warehouse, so the stock availability changes? We have to update the cache. What happens if the description that is probably unlikely to change that quickly changes? We have to update the cache. And what happens if we stored into the cache that thing as a single document?
- 07:49 Mauro Servienti
- So let's imagine that we grab data from multiple places, we compose a nice-looking JSON document, and we store that into the cache because obviously, we want something that is schema-less probably. So we have a single document. Now someone comes along and says, well, you know what the price changed? And what do we have to do? Drop the document and create it again.
- 08:15 Mauro Servienti
- So basically, now we are doing putting stress on to services just because one of them decided to change one of the information contained into the document. And by the way, we have a problem that not everything can be cached. So I intentionally took the screenshot from the US website, where most of the things cannot be shipped where I live.
- 08:45 Mauro Servienti
- So these items if both in the USA, it's not really $10 in free shipping, but it's $10 in free shipping if you live in the US. But if you live outside the USA, it cannot be shipped. And that kind of information cannot be cached at all. Well, it can be cached. If you think about it, you can cache the entire possible combinations of users and locations and products and cache all of them. And then immediately tell whatever meaning of immediately we want to use now that that kind of stuff cannot be shipped to Italy if Mauro is locked in. But it's not feasible at all.
- 09:31 Mauro Servienti
- So what do we want to do now is step back for a second and go back to a drawing board and try to understand what's the problem we're trying to solve? And the problem we're trying to solve is not a caching problem. It's a reporting problem. Yeah, I know. It sounds weird.
- 09:53 Mauro Servienti
- So the thing is that displaying data regardless of the fact that it's an HTML page or paper, it's always a reporting and integration issue. We're crossing a boundary. So data flow out of each service to the user. Data stored in catalog are flowing out going to the user machine. The price is going to the user machine, and so on.
- 10:23 Mauro Servienti
- So given that the users are already pulling things on demand, why shouldn't we benefit of that? So what's different between building a PDF on the fly to send it to users via email or building an HTML page on the fly and sending that to a browser via HTTP? It's the same problem, basically.
- 10:50 Mauro Servienti
- So we can start thinking about it as a thing that we call View Model Composition. Let's start from the user now. So the user wants to... Well, the user can be anything a machine, a browser on a user machine wants to display something that is identified by a URL. Well, a URL is a URI that is a unique key in the end. So we have something that is slash products slash one. And that's on the client, whatever client means in this scenario, and we have something that we can identify as a primary key.
- 11:28 Mauro Servienti
- And then we have these four services, each one containing a piece of the information that we want to retrieve. If they were to share the same primary key. So everyone store their own piece of information using one as the primary key for the part of the information related to the product one, then what we can do is basically pull that information out of each service on the fly, and compose the view model on the client itself.
- 12:03 Mauro Servienti
- And there's an important thing you have to take into account. Client doesn't really mean the user device. So client is whatever composes the information that is then sent to the user device. So it can be the browser on the user device. But it can be something sitting in the middle like a reverse proxy, or it can be the webserver.
- 12:34 Mauro Servienti
- So at any stage, everything can be seen as a client. So if we want to dive a little bit deeper into this, we can see these four services laid out on the right, and then we have an incoming HTTP request to try to get information related to slash product slash one.
- 12:57 Mauro Servienti
- And this information goes to something that we can start calling a composition gateway. That composition gateway is the logical thing that compose information, as we said, it can live on the client-side. So in the browser, it can live sitting in the middle like on a reverse proxy or it can be on the webserver, the final webserver.
- 13:18 Mauro Servienti
- So the first thing that the composition gateway does is it creates an empty view model. Something that will be returned in some way to the requester. And then it does a thing called request matching that is basically asking to services is there any one of you interested in this URL slash product slash one? And in our sample, all of them will say yes. Yes, we are all interested in this request.
- 13:54 Mauro Servienti
- And then fine, the third step is the composition step. So what happens at the composition step is that each one of them go back to their own backend or to their own storage, retrieve the information they need to retrieve based on the incoming URL. So the slash product slash one, get it back into the composition gateway, and fills the view model that was created empty by the composition gateway.
- 14:26 Mauro Servienti
- And finally, the composed view model is returned to the client. We can dive deeper even more and try to look at it from the coding perspective. So code samples will be in .NET but it can be applied to any language, basically. They're very simple. So let's imagine that we have someone that is trying to display a product like the banana protector.
- 14:58 Mauro Servienti
- One of this handler that has displayed on this image can be the product details handler from the catalog, for example. And it can be a class like this one. So product details get handler that implements an interface called I Composition Request Handler. So the I Composition Request Handler forces you to implement a method called handle that receives an HTTP request and returns a task because it's asynchronous.
- 15:34 Mauro Servienti
- So we said the first thing that we need to do is something called request matching. So always interested in handling a specific request. And we're using the same syntax that MVC used us to use that is attributes. So we can decorate this class, well, this meter specifically with an HTTP GET with a template, saying, hey, if there's an incoming request that matches this template, I'm interested in handling it. And that's the case.
- 16:07 Mauro Servienti
- So the incoming request is slash product slash one. So that matches. There's HTTP GET attributes template. So that means that our handle method is then invoked when the composition process starts. And when the composition process starts, the first thing that we do is we retrieve from the HTTP context the values that we are interested in, in this specific case just the ID.
- 16:34 Mauro Servienti
- And then we go back to our backend. In this case, it's warehouse saying, hey, warehouse backend, can you please give me back what's the inventory status of the product identified by the ID one? And for simplicity, we're using dynamic objects here just for the sake of the demo. And then we retrieve from the request, the composed request model that was originally created empty by the composition gateway. And we fill in our own information.
- 17:09 Mauro Servienti
- So we append to that dynamic VM. Like if it was a dictionary. If you're familiar with JavaScript think to it like a JSON object really. So it comes in empty and everyone can fill in data from... They retrieve from their own source. And basically, what happens is that now, this handler coming from warehouse is composing data into that dynamic VM.
- 17:39 Mauro Servienti
- And you can imagine that the same happens for sales, the same happens for catalog, the same happens for shipping. At the end of the process, well, these handlers are invoked in parallel. When all of them are done, what happens is that the dynamic view model that was created empty is filled with data that can be returned to the caller or to the UI if that's the case.
- 18:07 Mauro Servienti
- The important bit here is that each handler can retrieve data from wherever they want. So in the sample, I'm using HTTP to retrieve data again, but that's not really required. So given that the handler is logically owned by the same service that owns the data, there's nothing wrong inside the handler code to reach out directly to the service database. Because they belong to the same logical service.
- 18:40 Mauro Servienti
- There's no need to keep them decoupled. They change together because they belong to the same service. And once the composition process is complete, basically the output looks like this. So we have a JSON that contains a product name, the banana holder, the product description, banana protector search box. We have a product price, shipping options in current inventory, and if it's out of stock or not.
- 19:08 Mauro Servienti
- And you can see the ownership here. So each box represents data filled in by different services. At this point, the question is all what glitters is gold? So are we done essentially? Is that enough? And the answer is, unfortunately, no. Because we have a problem. Grids. It's always nice to have fun problem to deal with. So what's the problem with grids or lists is that each item in the list is composed.
- 19:50 Mauro Servienti
- So if each item in the list is composed, you can immediately spot the problem. Think about it. It's basically a select M plus one over HTTP because if we apply the same logic we just applied to this list that we applied to a single item to this list, what happens is that when we need to compose the first item four HTTP requests or four database calls will go out for the first product.
- 20:20 Mauro Servienti
- And then four more for the second product, and then four more for the third product. So basically, we end up with a number of requests, that is the number of services times the number of products we're trying to display. And if that's one, that's acceptable. If they are 20, that's not acceptable anymore, especially because if you think that to a real production system, there will probably be more services involved. And you don't want to end up with the flood of HTTP requests that are going to kill all the backends just because you're displaying a list.
- 21:00 Mauro Servienti
- So let's try to see how to handle grids in this case. Let's imagine something like homepage, where we're trying to display a list of available products. And I'm using this scenario because it's exactly the one that's contained in the demo that I'm going to share with you at the end of the talk.
- 21:19 Mauro Servienti
- So we're trying to hit a route that is slash available slash products that should give us back the list of available products in the store. And we want to give back to the UI a view model that is basically an array of products composed with information coming from different services. Now, who owns that? That's the first question we should be able to answer. Catalog is the one that makes decision if a product is available or not.
- 21:53 Mauro Servienti
- And what catalog does when this request comes in is that it loads the list of available products, where the list of available products is essentially, a list of IDs or primary keys, whatever kind of primary key you're using in your system. So catalog gets back a list of primary keys.
- 22:19 Mauro Servienti
- And what it does is that it publishes an event saying, hey, I loaded available products. Is there anyone interested in available products? And in this case, there is sales and someone else let's imagine warehouse saying yes. And by saying yes, it's because they are registered themselves to the available products loaded event. So what they're doing is that they are receiving the event, they are going back to their own backends, they are retrieving data based on the product keys published in the events.
- 22:59 Mauro Servienti
- And finally, each one of them is composing data into the view model. So what happens is that if you look at it from the coding perspective, we have an API that looks familiar because it's essentially the same as before. So we have an available products GET handler saying, hey, I am a composition requests handler and my implementation looks like this. I remove the attribute for clarity, mostly for space on slides.
- 23:33 Mauro Servienti
- And what happens is that the first thing that they do is that's the one coming from catalog. Yeah, from the product catalog. The first thing that I'm doing is I'm going to the product catalog backend asking for the list of available products. What comes back, in this case, is a list of integers. So it's the list of primary keys that should be displayed on the homepage that's converted into a dictionary, where the dictionary key is the primary key and the dictionary value is the empty view model.
- 24:15 Mauro Servienti
- So in that dictionary after that conversion, there will be as many items as many available products, where all the primary keys are used as dictionary keys and for each one of the key, there will be an empty view model created available and ready to be filled. And then I'm raising an event. So I'm saying, hey, view model, can you please raise an event saying available products loaded? And that's it.
- 24:48 Mauro Servienti
- What a subscriber looks like. I'm an available products' subscriber. And what I'm doing is saying hey, whenever there's an incoming request, I'd like to subscribe to the available products loaded event. And even in this case, I removed from the slides the HTTP GET attributes template so that I can filter out subscribers based on the incoming URL.
- 25:21 Mauro Servienti
- And whenever the event is filed, the subscriber receives the event that contains that property available products view model that is the dictionary created by the other one. It's retrieving all the keys, it's going to be its own backend. And once it's retrieved all the product prices in this case, so this one is coming from sales. It's for reaching over them and filling in the product price for each one of the view model.
- 25:54 Mauro Servienti
- And the same happens for warehouse shipping and all the other services interested in participating into composing the homepage. And finally, we go back to the composition process because we awaited the previous event. So when the raised event completes, all the subscribers have received the event, they've done their job, and they've filled in the available products.
- 26:23 Mauro Servienti
- And finally, we're pushing to the view model, the available products extracting that from the list of values into the dictionary. So as you can see, the handler that's coming from catalog knows nothing about what's going on into the products. The output is very similar to what we had before.
- 26:47 Mauro Servienti
- So it's a JSON object containing a list of available products, where each item in the list is basically composed by data coming from different services, in this case, three out of four. So shipping is not participating in this composition process for the homepage.
- 27:08 Mauro Servienti
- One important bit is that the composition process actors. So in this case, the catalog handler, the sales handler, the shipping handler, and the warehouse handler, they belong to the same service as their own services. So the catalog handler belongs to catalog and the sales handler belongs to sales. The shipping handler belongs to shipping and the warehouse handler beyond to warehouse, regardless of where they are deployed.
- 27:45 Mauro Servienti
- So if they are deployed into the webserver, they belong to their own services, even if they are deployed into the composition gateway or as JavaScript component into the browser, they still belong to their own logical service. This means that during the request matching and composition process, they are allowed to access their own data.
- 28:12 Mauro Servienti
- That's why I said before, you don't really need to use HTTP to do this. The demo uses HTTP. But each handler can access. They directly talk to their own backend and they can even directly talk to their own database because they're basically in the same logical service. What do we have now?
- 28:37 Mauro Servienti
- So if we have each piece of information that is owned by each service and this piece of information can be composed on the fly, and then shipped ones composed to the UI, what we have is a thing that we can call vertical ownership. So still using our own for services, we can expand them and say you know what if you look at them, and look inside, we have catalog that can be, for example, something like a document database that has HTTP support.
- 29:18 Mauro Servienti
- And then we just have a web proxy in front of it. And then we can have sales that is a regular database with a backend because we have a lot of processing and a lot of business logic into sales, and then API in front of it. And then we have shipping and we do nothing for shipping. So it's just a REST interface to a third-party API.
- 29:42 Mauro Servienti
- And then we have a warehouse that is very similar to sales where we have a backend, an API, and the database and in front of it, we have a user interface. We haven't talked about the user interface yet. We just talked about data so far. The interesting thing is that we can finally cache stuff.
- 30:04 Mauro Servienti
- So if we have full vertical ownership over data, now each service can define a cache policy for its own data. So catalog, for example, can say I'm going to cache description the names and images for the month. Who cares? Even forever. So if something goes badly and there's a typo, and someone didn't cache that while previewing the product, we're going to manually wipe that item from the cache and rebuild the cache.
- 30:37 Mauro Servienti
- And sales can cache stuff for 10 minutes because that's the most important things. We don't want to allow users to buy stuff where the price changed too easily. And shipping, we don't own it. So we're caching nothing. The third-party might cache stuff. And then we have warehouse where we said before warehouse always lies. So they have 24 hours cache.
- 31:03 Mauro Servienti
- They're telling us there are nine items in stock, but the last update of that information was 20 hours ago. So we might end up buying something that doesn't exist. But that's not a technical problem we are here to solve. That's a business problem. So the composition gateway sits in front of all of this. And each service deploys into the composition gateway their own handler.
- 31:32 Mauro Servienti
- And as we said before, handlers belong to the service. So they are part of that vertical slice. What's remaining here because the title of the talk was Designing the UI for Microservices? Yes, the user interface is the elephant in the room. And my main goal tonight is to... Well, tonight, for me it's night but it's my main goal today is to convince you that the user interface is the last of your problems.
- 32:09 Mauro Servienti
- If we have the ability to compose data on the fly in a transparent way to services and ship that data to a UI, whatever UI means in this context, we're basically done. Think about it. We can now change each service independently from all the others because they have full ownership over the data they own. And that's more than enough.
- 32:40 Mauro Servienti
- But let's try to dive into what's the user interface problem we're trying to solve. There are two main approaches to solve user interface-related problems when it comes to distributed systems. One that is called branding. Branding basically is a fifth service in our scenario.
- 33:08 Mauro Servienti
- So we have catalog, shipping, sales, warehouse, and branding. Branding owns the UI schema, as warehouse owns the schema in which the schema used to store the product inventory and sales on the schema to store prices, branding owns the UI. So branding is the one that dictates this. Branding is the one that says I'm going to design a UI like this one.
- 33:44 Mauro Servienti
- And in this case, this is ASP.NET Core MVC, but it can be Angular, React, whatever you want. So what branding is saying is, I'm going to show this. These are the information that I need, I need a product description, I need a product price, I need a product shipping options, I need product inventory.
- 34:06 Mauro Servienti
- And all these information are coming from the dynamic view model that are torn from the gateway. So that at model thing that is the default model provided by the ASP.NET Core MVC framework is filled in by the composition gateway at runtime with information coming from different services. And branding couples them together to display them on a UI, and I intentionally use the word couples. Because that's what branding does. Branding is a source of coupling.
- 34:42 Mauro Servienti
- So branding is the technical authority owning the UI contract. So whenever we have a contractor, sharing that across services, we have a source of coupling. In this case, branding sits in front of everyone dictating you want to display something, here is the contract you must respect. Get over it.
- 35:06 Mauro Servienti
- So each service must implement that contract or the part of the contract they own. In this case, shipping owns the shipping options only. And UI structured is defined as a monolith. So branding is the simplest way to implement UIs on top of distributed systems because they are monolithic. They're just a source of coupling sitting in front of everyone.
- 35:36 Mauro Servienti
- And they solve a very simple problem, someone is giving us data that needs to be displayed to a user in order to simplify as much as we can their buying process if we're trying to sell them something like in this case. Is that the solution to every single use case? Not really. So most of the times branding is super handy where you have B2C kind of environments.
- 36:04 Mauro Servienti
- So where you want to have fine full control over the way data are displayed and information are displayed. And if you have small teams, or even if you have a large team that is doing only one thing that is the UI. But not all the products and not all the companies are like this way. So on the opposite side of the spectrum, where everything I like to call UI composition magic or black magic, if you will.
- 36:39 Mauro Servienti
- So let's use the same sample HTML fragment coming from ASP.NET Core MVC. What we have here is that we have a very similar HTML fragment, where instead of having something defined by branding, we have basically, someone in this case who owns the product details page, catalog, for example.
- 37:09 Mauro Servienti
- So catalog is saying, I'm putting the product description where I want. And then I'm saying, hey, in this space, I know that they need to put the product details, product shipping options, and then inventory and price. So what I'm simply doing is delegating to someone else the act of showing data.
- 37:31 Mauro Servienti
- And again, you can see this as MVC components like in this example, or they can be Angular one directives, or Angular whatever version it is now components, or REACT components. It doesn't really matter the technology stack you're using at UI level. The important thing is that each component is owned by a different service.
- 37:58 Mauro Servienti
- And in this case, what catalog is doing is simply like if it was creating holes or I usually call them regions into the page, where all these regions have to be filled by a different service. And this case, the only thing that catalog is doing is saying, hey, I know that I'm calling that region product details price, product details shipping options. And there will be someone that at runtime fills in the required information where the required information now is not only data, but it's a schema and data.
- 38:39 Mauro Servienti
- So if we look at this from what's the difference between branding and UI composition at this point, UI defines only the high-level structure. So we have a very high-level structure defined by the logical owner of that specific page in this case catalog saying, I know very little of this page. So I'm putting what I know onto the page and then everything else is filled in by someone else.
- 39:07 Mauro Servienti
- It's unfortunately highly coupled with the presentation technology. So the way you do it is different depending on different UI technology stack. Branding is way less important in this case. And the more magic, the less branding. So the more you move to one side of the spectrum or to the other, so the more the dependent on swings to the left or to the right, you need less of the other part of the spectrum.
- 39:37 Mauro Servienti
- And now what happens is that services they own the entire vertical slice with UI composition. And if we go back to the picture that we saw before we can say now that UI the user interface grid segment can be displayed like this where we have each service deploys into something that we can now start calling a client shell components that are dependent on the technology choice on the client-side. And they know how to display data coming from different services.
- 40:21 Mauro Servienti
- Why should we do this? Well, one of the question that we need to be able to answer is how fast do we need to react to changes coming from services? Because in the branding scenario, where branding is monolithic, if something changes into a service, the only thing we have control over is one of the handlers into the composition gateway.
- 40:50 Mauro Servienti
- So what happens is that if, for example, sales wants to start using different currencies. So they need to start differentiating the concept of a price that is not maybe let's say, it's not the Euros anymore only, but it can be Euros, US dollars, and all the currencies that comes to your mind. So they need to have an additional field that is the currency selected.
- 41:20 Mauro Servienti
- So in order to display data, they need to change nothing because they can have multiple fields now into their own storage is representing the value of the price and the currency. But when data are composed to display on the UI, in the handler, what they can do is that they're just returning a string to the UI.
- 41:43 Mauro Servienti
- So what it can do is that they can join the price and the currency information to return a string like it was before. It's not UI anymore, but it's always a string. But there are changes that might affect the UI as well, in which case, branding is a limiting factor.
- 42:04 Mauro Servienti
- So if changes like this are not coming from branding, then the fact that branding is monolithic limits the ability of services to a certain degree to change as they want. That might be a good reason to move to full vertical ownership saying, hey, I want to have full control over UI composition process as well and components deployed into the client shell. So to be able to adapt to that rate of change way much faster.
- 42:39 Mauro Servienti
- What's the problem then? Obviously, complexity is one of the problems. The thing is that if you think about it, it becomes more and more complex to deploy components. It becomes more and more complex to test the UI. It becomes more and more complex to guarantee consistency because now, styles are split into services. JavaScript that runs in the UI is split into services.
- 43:08 Mauro Servienti
- And now it's easier that something goes badly at deploy time because we are overriding each other styles. And so the complexity increases. And there have to be good reasons to handle that complexity. The slides are already available online at the second link.
- 43:30 Mauro Servienti
- And four demos composing one single product, composing a list of products, demoing how to use branding, and how to use UI composition are available at the first link. So before looking at some sort of conclusions, is it worth the effort? My answer is generally, no.
- 44:00 Mauro Servienti
- So complexity increases, it's already complex. And it gets even more complex as black magic kicks in. So if we want to move from composing data, what we call view model. So from view model composition to UI composition, that it means even more complexity into the system. So all this complexity has to be justified by something. And that's usually the dimension of the process. The project sorry, the expected life cycle of the project, dimension of the teams, the rate of evolution.
- 44:48 Mauro Servienti
- All factors that are not really technical-related, are much more business-related. They need to be factored in before making the decision. Do we want to go down this path or shall we say monolithic because it's simpler to break a monolith later than doing the other way around.
- 45:10 Mauro Servienti
- So it's better to build the monolith first and then break it apart once we have understood all the caveats of the domain we're designing instead of building a distributed system first and then trying to fix all the distributed monoliths problems that we're causing because we have no real clue of the domain we're building. So try to avoid complexity as much as you can.
- 45:39 Mauro Servienti
- Take takeaways. So the most important thing I'd like you to take away from this short presentation is that boundaries are the most important part. So finding and defining service boundaries or bounded contexts, if you prefer the domain-driven design lingo, is the most important thing to do before starting to design anything, anything.
- 46:11 Mauro Servienti
- And one interesting signal that we might have found the wrong boundaries is the need of technology. So as soon as we start saying, oh, we need more technology here, we need a cache here like in the example that we use that says probably.
- 46:32 Mauro Servienti
- So use that as a signal to hold on a second step back, go back to our board and verify why you need that additional complexity to maybe solve a problem that is not a technical problem, it's more of a business problem or over a design problem. What can lead you to that direction is what I call the user mental model.
- 46:57 Mauro Servienti
- The user mental model is always used usually used sorry, not always usually used as a leading design factor. That's a very interesting way of designing software's with translating the user mental model into the software. The problem is that when it comes to distributed systems, the mental model can easily influence the design in a bad way.
- 47:27 Mauro Servienti
- Because the problem is that users, they tend to think to data in terms of data presentation, they talk about products. And what we do as engineers is that as soon as someone says product, we picture out in our mind, public class product description, public string description that get set.
- 47:55 Mauro Servienti
- And now we created the service design as in the service boundaries following the user mental model, and not the way data are really distributed into the system. And finally, you can use view model composition to present the data. So there is no need for complex projections and read models. Because if we ever split the data correctly into services, the only thing we need to do is to extract this data at runtime and show them. We can do that on the fly.
- 48:32 Mauro Servienti
- And if we really need to cache for performance reasons, we can do that at each service level. We don't need to do that into a land of nowhere cache. I said before, my name is Mauro Servienti. I'm a solution architect for a particular software. And I was very happy to present to you today and thank you very much.