Skip to main content

Webinar recording

Finding your service boundaries: a practical guide

We know it’s useful to split up complex systems. We’ve seen the benefits of modular deployment of microservices. Dealing with only one piece of code at a time eases our cognitive load.

But how do we know where to draw the service boundaries?

🔗Avoid the re-write

In complex business domains, it’s often difficult to know where to start. When we get our boundaries wrong, the clocks starts ticking. Before long, we hear ourselves say “it would be easier to re-write it”.

Join distributed systems expert Adam Ralph for practical advice on discovering the hidden boundaries in your systems. Help tease out the natural separation of concerns in a sample business domain. During 20 years of developing complex systems, Adam has had plenty of time to get things wrong. Learn to avoid the common pitfalls that can lead us down the path to “the big re-write”.

🔗In this webinar you’ll learn about:

  • What happens when the boundaries are wrong
  • Techniques for getting them right
  • The most common pitfalls
  • Where microservices fit into all this

🔗Transcription

00:00:00 Mauro Servienti
Hello again, everyone, and thanks for joining us for another Particular live webinar. This is Mauro Servienti. Today I'm joined by my colleague and distributed system geek, Adam Ralph, who is going to talk about discovering the hidden boundaries in your systems. Adam, welcome.
00:00:20 Adam Ralph
Thank you very much, Mauro, and thank you to everyone who's joined us today. Really appreciate you spending the next hour listening to me talk about service boundaries. I've been looking forward to this, and I hope you're going to find it enjoyable and useful.
00:00:35 Adam Ralph
For those of you who don't know me, my name's Adam, and I'm originally from the UK. These days I live in Switzerland, up in the mountains, and I've worked for Particular Software for about four years now. Well, I guess you're at least somewhat familiar with the Particular Software and who we are and what we do. We make a product called NServiceBus. I'm not going to talk much about that today, but what I will say is that our company mission is to help organizations get better at delivering complex software systems.
00:01:16 Adam Ralph
Now, in doing that, we tend to talk to a lot of people. We talk to customers, we talk to people at conferences, we have support cases, and we have a lot of interesting conversations, and a lot of those tend to center around problems with systems and specifically around shuffling data around versioning components, deploying things together. It's very often in those conversations that we find ourselves thinking, you know what, if the service boundaries were slightly different, we may not even have to have this conversation. The problem that we're talking about may not even exist.
00:02:03 Adam Ralph
That's the reason I think it's really important to talk about finding the right service boundaries, because for me it's one of those things that sometimes is at the root of many problems. If you think of this problem, if you get the wrong service boundaries, that can cause other problems, may cause other problems, and so forth. It's somewhere near the kind of root cause of a lot of the problems we see.
00:02:27 Adam Ralph
Now, today I'm probably, and I intend to take some of the typical things that we've learned in the software industry, some of the things we're familiar with and things we may have learned in computer science degrees and various literature that we've read, and I will kind of take that apart and tear them up and kind of turn things upside down. If any of you have heard me talk before, you know that's something I like to do. I am expecting that to raise questions. As Mauro said, please do use the Q&A to ask me anything you like about this as we go along.
00:03:11 Adam Ralph
Let's start off by looking at a system. Now this is really any system. It doesn't really matter what it is. It doesn't really matter what these boxes are bigger either. They could be classes, they could be functions, procedures. It doesn't really matter. But we do tend to structure our systems in this kind of way. We don't tend to write program.main and then just put everything in that main method; at least I hope you don't do that, and that's something that I used to do back in the '80s when I taught myself programming.
00:03:42 Adam Ralph
But these days things have moved on a bit. We do tend to structure our programs so that we have certain areas of responsibility. You could look at this, and let's just assume that these are classes, for argument's sake. You might think, well, there's an area up here in the system which clearly has some kind of air of responsibility and this group of classes doing something. This smaller group of classes down here is doing something as well. This actually looks quite nice, okay. You can see that certain components depend on other components and things are kind of structured fairly nicely. You can follow things along from this kind of diagram and find out where responsibilities belong.
00:04:29 Adam Ralph
Now that's all well and good, but the problem is that businesses have this nasty habit. They have this nasty habit of coming along with new requirements. You might come to work one day and one of the partners or someone might come into your area of the company and just say, "Look, I've had this fantastic new idea. I was out playing golf with my buddies this weekend, and we think we've got this great new thing that we can do, and we think we can make a ton of money out of this" and explain it to you. You're saying, "Well, I think we can do this. Yeah, I know how we can do this."
00:05:07 Adam Ralph
But you realize that what you actually need is in some component up here, let's say this class up here, you need some data that's in a class down here. You take a look at the diagram and you think, "Well, how are we going to do this? Do we need to change the diagram around? Do we redraw the lines and juggle things around? Or do we just make the call from this class to this class?" Now remember, at this point, we may be dealing with, say, an object-oriented program. These might be CSharp classes.
00:05:41 Adam Ralph
Ultimately, this is what CSharp classes and classes in other languages are designed to do. They have a nicely defined interface, they're encapsulating some behavior, and they're access-constraint, because object-oriented programming is telling us that this is a valid call. Even though it doesn't really quite fit in with the diagram right now, you say, "Well, let's just try this on for size. Let's do this. Let's make this change," and you roll out into production and things tend to work. The business is happy because they are making more money as a result of their new feature, and you get your praise and it's a job well done.
00:06:21 Adam Ralph
Sooner or later the business might come along to you again and they might say, "Well, I was out jet-skiing last weekend at my summer house and I had this fantastic new idea. We're going to make a ton of new money. But what we actually need is some data up here, which is contained in the class down here." You think back to the last time you did that. They say, "Well, that thing we did a couple of weeks ago, that worked out pretty well, right? It's working in production, hasn't caused any bugs. The feature is working as intended." You think, "Well, let's just do the same thing again, then. Let's just respect our object-orientation, respect our class interfaces, and let's make another call again. You roll out into production and things go smoothly again.
00:07:04 Adam Ralph
Sooner or later you end up doing the same thing. You end up making a call from some other class to some other class. You realize you need to basically follow the same pattern and it has been working out quite well for you, so you go for it again. Now I guess you can see kind of where I might be heading with this now. The thing is that no one really sets out to make a mess, but given enough time, and it could be a large amount of time. It could be a few months, it could be six months, it could be a year or even more. You may slowly start to end up with something which looks a little bit more this.
00:07:43 Adam Ralph
Now the problem here is that this diagram starts to lose its usefulness because you might turn around to your colleague and say, "Oh yeah, you know that new feature we rolled out last week, did you use a system diagram for that?" They'll say to you, "What? You mean that thing with all the red lines all over it? No, that's pretty useless. I haven't used that for weeks." What that's telling you is that these lines have lost their meaning, because you can't really use this diagram in any meaningful way. You might as well just take the lines away and just have a bunch of boxes.
00:08:19 Adam Ralph
Now at this point, these things are still classes. They still have their interfaces, there's some level of encapsulation. But the only way to really make changes to the system is to try it and see. Some people call this an edit and pray method of making changes. You go into one class, you make some changes you think are required, then you find out that part is used by other classes, so sometimes it can feel like you're going a bit down the rabbit hole, or you're going on a code Safari where you're discovering as you go along what you might break and what you might not break. In the end, what that means is that you can't really use this diagram very meaningfully, either, because you can't look at one box in this diagram and say, "Oh yeah, that's the thing we need to change. That the thing which encapsulates that behavior. In order to deliver this new feature, we're going to change that class."
00:09:18 Adam Ralph
What that says then is the individual boxes aren't much use either because you always have to just go exploring anyway, so you may as well just draw one big box. Now at this point, this is what some people recognize as something which we sometimes call the big ball of mud. Now, judging by your poll answers at the beginning of the webinar, I saw that many of you have seen systems which are tending towards this throughout your careers. I think the most common answer for average systems over your career was something around the two mark on the one to five scale. I guess you're all reasonably familiar with the big ball of mud architecture.
00:10:05 Adam Ralph
During my career, I think it is probably the most common system architecture that I've seen, which is a sad thing to say, but it's the unfortunate truth. The thing is, we know that we can do better than this. We read about things like service-oriented architecture and microservices. I'll come to microservices specifically a little bit later. We read that it's better to split our system up into some kind of notion of independent services or some components.
00:10:40 Adam Ralph
What we really want to do with services is we want to have thin lines of communication between them. I'll come to more on this in a minute, but we want is loose coupling between these services. Now that all looks fine, but what tends to happen is that business will come along with a new requirement or say, "I was out jogging this morning. I had a great idea for this new feature and we can make a lot of money." You take a look at your services, and you think, "Okay. Yes, I think we can do this. But what we need is some data from the service in the top left and the service in the top right."
00:11:23 Adam Ralph
This might be something really innocuous. It might be something like a price. Widget X costs $100. How much harm can that do? It's just a number going across the wire. You think, "Okay. Well, we're going to adjust the interface between those two services slightly, and we're going to introduce this notion of the price. That's still a low amount of coupling. It seems like its not going to do much harm." You make that change. You roll it out to production and everyone's happy, again, and you're making more money, and you've delivered the feature.
00:12:02 Adam Ralph
Sooner or later, the business will come in again with this great new feature, and I was out, I don't know, snowboarding last weekend and I had this great new idea, and you realize you need to do the similar thing again and you just share some data between two more services again. Again, it might be something really innocuous. There might be something like quantity of items in stock, so 100 widgets. An integer number going across the wire, we alter our service interface to provide this new integer. We roll out that change and everything is fine again.
00:12:35 Adam Ralph
But you can guess where I'm going with this again. Given enough time, and it might be a long period of time. It might be a month, six months, a year, 18 months. You may start to end up with something which looks a little bit more this. Again, no one sets out to do this. The problem is that things can atrophy to this kind of state, and we can end up in a very bad situation again where we've already seen that we may as well get rid of the boxes, we may as well get rid of the lines, and we're back to a big ball of mud situation.
00:13:11 Adam Ralph
Only this time it's a big ball of mud with a slight difference because you've split this up into four nominally called services, and you've rolled those out into four different machines. Now those machines are talking to each other over the network, and even if that's localhost, it's a lot more expensive than in memory class to calls. You may have to roll out two, three, or even all four at the same time, because they're tightly coupled. Remember the lines back here. It's very difficult to imagine this scenario. We can roll out one service independent of the other. Because of it they're relying on data from each other so much.
00:13:54 Adam Ralph
What's happened is you've reached for an architectural approach that was supposed to help and make things better, and you can in fact end up in a much worse situation than you started off with. This is what sometimes people refer to as the distributed ball of mud. It tends to be services. It's really just another big ball of mud, with some extra complications thrown in with this deployment to different machines and talking over the network.
00:14:24 Adam Ralph
How can we avoid this? What I'm going to do now is I want to take a use case. I'm actually going to take a real use case of what we're going to do with the system and examine how we can work towards doing this and avoid getting to this situation. Now, if you've heard me talk before, you may have seen that I to use the example of Amazon. Amazon's a good example because Amazon is a very service-oriented company. In fact, it's probably one of the most service-oriented companies in the world. There's this famous thing about Jeff Bezos, the CEO, who sent out a internal memo. He basically instructed everyone in the company to build everything around a service-oriented architecture. He said that, "Anyone found not doing so will be fired." That actually happened.
00:15:18 Adam Ralph
As a result of that, Amazon has become a very service-oriented company. There is certainly not one terabyte [Amazon.exe 00:15:26] which gets deployed. Now Amazon is also a good choice, because I'm sure most of us are familiar with buying something on Amazon or similar sites. Amazon's not available in every country. But when you buy something on Amazon, what you do is you enter into a workflow. Once you've gone through the product catalog and you've decided what lovely, shiny things you want to buy, you put them in your basket, you then say, "Right. I'm going to go ahead and buy now. I'm going to go and spend the money."
00:15:59 Adam Ralph
You click, Proceed to Checkout and that in itself starts a certain workflow. The first step in that workflow might be to enter a delivery address, the second step might be to enter my payment methods, and then there are other things around shipping options and other things. When we get to the end of that workflow, we click Buy Now, and that effectively completes the workflow.
00:16:26 Adam Ralph
Now let's take a look behind the scenes and this is a, let's say, slightly simplified version of the Amazon back end. I'm not going to describe exactly how that works. But we can imagine that we might have services split up into the notions of sales, finance, and shipping. Now when we got to the end of our workflow, we click Place Order. At that point, we might send the message to sales to say, "Place order." Then sales does whatever processing it needs to do. Things like, "Are we still selling this product? Are we allowed to sell it to this country? If we have none left, can we get more from the supplier? Have we got in the inventory left." That salesy type stuff. If all of that satisfied, it says, "Right. All is good to go." We're going to send the message to finance and to shipping to say the order's been placed, right. My work is done. Now it's over to you.
00:17:33 Adam Ralph
Finance might say, "Okay. Well, I need to go and do my stuff now. I need to go and do my financey stuff like billing the customer is the obvious one. This might be charging their credit card or some other method of payment. Finance will then say, "Okay, I'm all done. I've taken the money," and it sends an Order Billed message to shipping and says, "Over to you."
00:17:58 Adam Ralph
Now, because shipping has received the message from sales saying, "The order's been placed," and it's received a message from finance to say that the order is being billed, it knows that it can do its stuff. It does shippingy kind of stuff. It says, "Where am I going to ship this order? Which courier am I going to call, or which Postal Service?" and it actually gets the thing out of the door on its way to the customer. At that point, it might send the message which says, "Order shipped to some other service which does something else, like, I don't know, aggregate some marketing information or send the customer an email or whatever.
00:18:35 Adam Ralph
Now the question is what should each of these messages contain? When we send this message called order placed from sales to shipping, we can say that's an event to say that the order's been placed. This event has happened. Now should that event contain all the information that shipping needs in order to ship the order, should it contain the address and all the rest of it and all the shipping options? Should that order place event contain all the information that finance needs in order to billed the customer. In other words, should it contain the credit card details and all the rest of it?
00:19:20 Adam Ralph
Now that would work, okay. There's no reason that wouldn't work. But there's an inherent problem with that. The problem is that if we want to change something in the system, we're going to have to change it in more than one place. For example, what if we wanted to introduce Bitcoin payment? We'll have to make a whole bunch of changes in finance to charge in Bitcoin, and we'd have to have a whole bunch of changes in sales so that it understood what information they needed to gather to put on the event to send the finance.
00:19:58 Adam Ralph
Very similar with shipping. What if we wanted to ship e-books? You don't ship an e-book to a physical address. You could on a USB key or something, but that'd just be weird. What you tend to do is you send an email with a download link or you just give a download link in the browser or something like that. The shipping of an e-book is very different. Again, we don't want to make a whole bunch of changes in shipping and a whole bunch of changes in sales, because we're then introducing that tie coupling. We're sharing a whole bunch of data from one service to another.
00:20:34 Adam Ralph
If you think about how that event would look, it would start to get quite complicated. It would have to have all kinds of strange nullability rules around it. If the address is null, then the e-book shipping address must not be null. If the Bitcoin wallet address is not null, then the credit card details must be null and you get into this nullability soup. This is a very simple example. You can imagine more complex examples and, let's say, the real world Amazon, for instance. This is a lot more complicated, and you find yourself on that road to saying, at some point, it would just be easier to rewrite this whole thing because it becomes so complex.
00:21:22 Adam Ralph
Now the thing is what we've done so far is we've assumed that the order is created when we place the order, and what that means is that the order ID is created when we place the order. But the thing is, we can use another technique. What I've just described are fat events, right. They are events with lots and lots of data on them. What we want to do is we want to slim those down to be thin events. What if each of these events contain nothing but an ID. When sales publishes order placed, it just says, "The order's been placed and the ID is 123." When finance says order has been billed, it just says, "The order has been billed and the ID is 123." Finance can then say, "Well, I know how to bill for order 123 and goes and there's a billing." Shipping just says, "Ah, well, I know the order's been placed, order 123, the order's been billed, order 123. I know how to go and ship it."
00:22:33 Adam Ralph
We've got a chicken and egg scenario, though, because if our assumption that the ID is created when we place the order is correct, then how can finance know about the order before it gets the message and how can shipping know about the order before it gets its messages. Well, let's turn that upside down. Instead of creating the ID at the end of the workflow when we place the order, what about if we create it at the beginning? What about if we create the ID when we click, Proceed To Checkout?
00:23:07 Adam Ralph
What we can then do is when we select a shipping address, we can actually send that shipping address to the shipping service at that moment with that ID. When we enter our credit card details, we can send the credit card details to the finance service with the ID forth, and so forth and so forth and so forth until when you hit Buy Now, you send your message to sales, and because we've done this work upfront, sending these details to the shipping service and the finance service, when we place that order and sales does its work, all it has to do is publish an event to say, "The order's been placed and here's the order ID." Because remember we've already told finance and shipping what the details that they need during the workflow.
00:24:06 Adam Ralph
Now what we can do is they can do their work, as they did before, but if we want to introduce a Bitcoin payment, we make a bunch of changes in finance, and because it's only receiving an ID from sales, it can say, "Ah, order 123, I know where to charge that, I know where to charge that in Bitcoin or via credit card." Shipping can say, "Ah, order 123, I know whether to ship that to a physical address or I'm going to send an email for it." Now the one thing that I'm glossing over here is the UI aspect, because it's fine to say that we can just make changes in finance to say we're going to now charge by Bitcoin, but back in our UI, we've got something here which is collecting that information. It's either collecting credit card details or it might be collecting a Bitcoin wallet ID.
00:25:06 Adam Ralph
I'm not going to go into that in this talk at all. I'm going to leave that to Mauro. If you're not already aware, Mauro has a follow-up webinar after this one on November 13th, and he's going to delve into how we do that. What you've seen now here is that by using this one special trick of creating the ID at the beginning of the workflow instead of at the end we can actually thin out and slim out our events to be thin events just containing IDs. Now those of you here who have worked with databases might be asking a question now. You might be saying, "Well, what happens if I start that workflow, I proceed to checkout, I enter my credit card details, I enter my address, and then my partner walks through the door. I suddenly get a feeling of guilt and I think, ah, they're not actually going to be too happy if I spend this money and you abort the transaction. You don't click Buy Now."
00:26:08 Adam Ralph
We're going to have a bunch of redundant data. We're going to have a bunch of redundant data and shipping for addresses, which we don't actually need, and a bunch of redundant payment details, which we actually don't need. Now shouldn't something come along clear that stuff up that redundant mess? But you also have to ask yourself, is that data actually redundant. Is the business interested to know which orders are being completed and which are not. Now is this interesting business analytics? Sometimes it could be. The business might say, "Ah, I've spotted a pattern here. I think we could do an A/B test to make sure that more people feel compelled to actually go through and complete the order. It can actually be really valuable data.
00:26:54 Adam Ralph
The thing is that ultimately if these are rows in the database, storage is one of those things where we can generally say, it is relatively cheap these days, and it's not even necessarily always data in the database. We have to be a bit more careful about retaining credit card details. They might just be in session state. The browser closes, the session times out, and it disappears in memory. Not necessarily redundant data and not necessarily difficult to keep when we have to either.
00:27:30 Adam Ralph
Now why is it that we ended up in the big ball of mud when we tried to introduce service-oriented architecture? Well, the clue is in that initial sharing of data, that one little red innocuous arrow that went between two different services, started us off on that path which coalesced back to the big ball of mud eventually. I think this is a good time to start to define what a service is and what a service is not.
00:28:00 Adam Ralph
First of all, what a service is not. Something that only has functionality, a calculation of something or validating something. That in itself is not a service. That is the definition of what a function is. It's like given these inputs, give me some outputs; that's function. Something with only data is just a database. If you're doing create, read, update, delete on entities that really just is a database and that is not a service. One really important point here is that just because you sprinkle an HTTP layer or back in the SOAP days [whistle 00:28:37] layer on top of a database. It doesn't actually suddenly make it a service. A HTTP API over a database is not service magic dust. It's still just a database. All you've done is you've changed the technical access point from a connection string to a URL.
00:29:02 Adam Ralph
A service is the technical authority for specific business capability. Really importantly, all data and business rules reside within the service. You can think of this as a special case of a bounded context. If any of you have read DDD by Eric Evans, he talks about bounded context there. He's a little bit looser with his definition of what a bounded context is. The definition of a service is a little bit more crisp. It's specifically the technical authority for a specific business capability. But you can think of it as a special case of a bounded context if DDD is something that you're into.
00:29:45 Adam Ralph
Nothing is left over after identifying services. Everything must be in some service. Now if you think about it, this makes sense and follows from what we've said, because the code that we write must have some business capability. We are paid to write code for some business impact. That's sometimes a bit different if your project is completely failing and you decide to go and learn RUST or something, and I've been in that situation myself. But if things are going well and you are delivering business capability, then all the code you're writing has some business purpose. If a service is the technical authority for a business capability, it then follows that all code must belong within some kind of service.
00:30:38 Adam Ralph
Now what this really comes down to is encapsulation. Technical authority gives us encapsulation and business capability gives us business alignment. Now it's quite interesting to look at something like object-oriented programming, because object-oriented programming was actually never really about inheritance and polymorphism, things like that. If you've ever read anything by people like Alan Kay who first wrote about object orientation. What they described was classes encapsulating data and logic inside them, getting messages in, doing some processing, and sending the messages out. That in a nutshell was the original idea of object orientation.
00:31:28 Adam Ralph
Now I guess most of us have worked with some OO programming model before, and we soon discovered that objects aren't really big enough. You can't really do anything too interesting with an OO system without sharing some data between objects, whether it's with properties or whether it's arguments and method calls, you do tend to have to send to share some data around between them. Then we can step up to components. In the .NET world you might think of that as an assembly or a new get package or something that. They're better. You can get a higher level of encapsulation between them, but ultimately you still end up having to share some data between different assemblies, for example, again via method calls or object properties and that kind of thing.
00:32:21 Adam Ralph
If we then step up to services, there's a fundamental difference, because services are business aligned. Services are logical concerns around business alignment, whereas classes and assemblies are technical concerns with physical boundaries. What that allows us to do is to separate the physical from the logical with services and that's well exemplified if we look at the difference between systems and services. For example, you may have a mobile app, a back-end app, and a java portal. Now it's very tempting to draw service boundaries along these lines.
00:33:08 Adam Ralph
Now I'm sure I'm not the only one here who's heard the term back end service before, or sometimes front-end service. The thing is that services tend to cut along these lines. What that means is that service S1 here may have a component which goes into a mobile app, it may have a component which goes into a back-end app, and this portal at the bottom. That means that one service could consist of various different technologies. It could be shipping a component which goes into an Objective C app or into .NET app or into a Java app. It means one specific system, let's take the mobile app, may consist of components from different services, a component from S1 and S2 and S3.
00:34:03 Adam Ralph
It's a many-to-many relationship. I often make the analogy to Lego. If you've ever played with Lego, you tend to start off with that green board and you have piles of bricks. I used to organize my bricks into large bricks, medium bricks, and small bricks or blue bricks, yellow bricks, and white bricks. Then I take bricks from each pile and put them onto the green board and I build a system. That's what it's like to build a system in service-oriented architecture.
00:34:36 Adam Ralph
Services are logical design time concerns with business-aligned boundaries. Systems are physical runtime concerns aligned along technical boundaries. If there's one thing I'd you to take from this webinar it's actually this point. It is the separation of the physical and logical. Services are logical, systems are physical. I think that is even one of those things that's even further down in the root of problems than finding your service boundaries. If you can make this separation, if you can make this decoupling between physical and logical that allows you to find the right service boundaries. If you don't make that separation, it gets in the way of doing that.
00:35:25 Adam Ralph
Now let's have a look at an actual sample domain. This is something which you may find yourself drawing, let's say, on a whiteboard. You might have a conversation with your business stakeholders, and they might say, "Well, we've got customers and we've got products." The first thing you do is you get to your whiteboard and you draw a box for customer and you draw a box for products. Then they tell you the customer has a first name and a last name and a status and a product has a name and description and the price.
00:35:55 Adam Ralph
But the thing is if you start to look at the detail of what's in these boxes, a very different model can emerge. Now I like to use a technique which I call anti-requirements, and this is a technique where you can ask some very dumb questions. The thing about businesses is that they often don't know what they want, but they very often do know what they don't want and you can take advantage of that. You can ask really dumb questions like if a customer's first name begins with S, does that affect their status. At that point, you might get a strange look, and they'll say something lie, "Well, that's just so dumb. Not only would we ever do something like that. I don't think anyone in the industry would do something that. Just doesn't make any sense."
00:36:46 Adam Ralph
Now when you hear something like that, you've actually struck gold, because what the business have just told you is a stable business rule. They've told you that the last name or the first name has nothing to do with the status. I would then put those things into two different boxes, because they don't affect each other, and at this stage of modeling, this is what you're trying to do. You're trying to break things down and you're trying to make piles of different things. You're trying to make piles of related things.
00:37:24 Adam Ralph
Now customer status there looks a little bit lonely on its own. You think, "Well, okay. Well, what is customer status?" You ask your business, what is customer status. They say, "Well, we'll use that to work out the price. If they're a gold customer, we'll give them a discount. If they're a silver customer, we give them a little bit less discount, and otherwise, we give them no discount at all. You know that there's some relationship between customer status and price. You say, "Well, I'm going to put those in the same box. I don't know exactly what the relationship is yet, but you've told me they're related." Then you might look at the product and say, "Well, what's left"? We've got the name and description. Description tends to embellish the name, because if it's a Duluxe something or a Luxury X, we tend to use a description to describe why and why you need it. We're going to put them in the box down here.
00:38:16 Adam Ralph
Now this is again a very simple example. As you can imagine in a more complex example, the model that pops out at the bottom after looking at these specific use cases is very different to the model which we have at the top, which we initially drew on our whiteboard, and this is what modeling is about. It's not about nouns. It's not about tangible identifiable things like a customer and a product. Even though our eyes and our brains are wired to do that, and that's the thing we like to do. We like to draw a box on the board and get a 30,000 foot view and drill into detail later.
00:38:59 Adam Ralph
But modeling is actually about those behaviors, it's about those scenarios, it's about drilling into the field and not the entity, it's about asking how these things relate to each other. One thing that you should really look out for is when the business says to you something customer has a first name. If you spot that bit in the middle that's a very, very good sign that you're going down a noun-based, entity-based model, instead of a behavior and scenario-type modeling exercise.
00:39:38 Adam Ralph
I'll even go and say I'll say entities are bad. Now if you've read some of the literature by Eric Evans in DDD and that thing, you might be surprised to hear that. But even Eric said after he wrote the book, he said, "Well, I wish I'd put that stuff in the second half of the book," because if you were like me, you read the book, and you got all excited about [inaudible 00:40:03] and things like that and entities and you ran to work and you started writing them, and I read the second half of the book about six months later.
00:40:12 Adam Ralph
Eric said that he wished he put that in the second half of the book instead of the first half of the book. Later on he actually said he wished he'd just put it in the appendix, and later still he actually just said he wished he left it out all together, because it wasn't the important message that he wanted to send. I think to some degree we've become a little bit distorted in our approaches, and as an industry, you're thinking that entity modeling is a thing to use at this stage, and I don't believe it is. It's about behaviors and scenarios rather than entities and nouns.
00:40:45 Adam Ralph
Another thing that I'd really recommend at this stage is not to name these things too early. I actually tend to name them very late or even never name them properly at all or properly. I would use dumb names like red, green and yellow or names of planets or names of animals, doesn't really matter. The problem is if you name these things too early, there can be one of two things. It can actually prevent you from putting something into a pile, because you can look at a piece of data and you can say, "Oh no, that's billing. It can't belong in billing." Or it might lead you to put it in the wrong pile. You might think, "Oh, well, that's clearly inventory. It's got to be inventory."
00:41:29 Adam Ralph
Especially when you work with more abstract domains that you're not used to day-to-day, it can be easier to not name them earlier. If you're working with more familiar domains, it can be more tempting to give names earlier, but try and resist that temptation. Try and just use meaningless names until the point where you find your modeling has moved on much further.
00:41:59 Adam Ralph
Let's take another example, insurance. Insurance is interesting because what often happens is insurance tends to get split up between a front office and a back office. The front office tends to be about fear and I actually gave a talk once in Russia about insurance, and they told me that the word in Russian for insurance actually has the word fear in it. I think there's a degree of truth to that. It's about making you afraid enough of bad things happening that you're going to buy insurance. The back office is very different. The back office is all about paying out as little money as possible when a claim is made. Now even that sounds a little cutthroat, it's really just a model of any business. It's maximum money in and minimum money out, and then you have a successful business.
00:42:48 Adam Ralph
Now a colleague of mine was actually called in to an insurance company to have a look at their service boundaries and to give them some advice as to whether they got them right or got them wrong, and I showed them this. I showed him a policy service and a claims service, which is very much modeled around the front office and the back office, where the front office sells policies and the back office deals with claims.
00:43:11 Adam Ralph
Now I don't know a lot about running insurance company, but I do know that this is probably wrong, and I can say that pretty much straight away. The reason for that is think about a typical use case. I make a claim, right. I crash my car and I make a claim. What's the first thing that the claim service is going to do? It's going to inspect the policy to find out how little we can get away with paying. That's a whole load of data sharing between the two services. It doesn't really matter when it's done; it doesn't matter if you publish that policy early on or the claim service requests it from the policy service, there's a whole bunch of data sharing. These things again are very tightly coupled. You can end up with lots of red lines going between these two services.
00:44:01 Adam Ralph
It's all well and good saying they're wrong, but then you've got to come up with a suggestion for what is right. I've got to tell you, this is difficult. Finding the right service boundaries is a tough thing when you're presented with a domain, and time can go past where you're bumbling around and it feels sometimes you're walking around the dock and bumping into things. You don't really have any idea of where you're going and you don't feel like you're making progress, and the business is saying to you, "Four days have gone past now. You haven't given us any better ideas yet. What's going on?" You give them a typical consultant's answer. "I think I'm getting somewhere, and that meeting we had the other day, that was really valuable," et cetera, et cetera.
00:44:45 Adam Ralph
What tends to happen is sooner or later you might get an insight, you might get a breakthrough, and you might realize that, you know what, when we've talked about home insurance, we've never really talked about travel insurance at the same time. You never told me things like when the dog chews up the sofa, you show them your canceled plane ticket, or you crash the car, and you show them your broken TV. I haven't seen any crossover in those use cases. You think well maybe we should be thinking about home insurance and travel insurance and car insurance. You think, right, I think I've got it here.
00:45:24 Adam Ralph
It gets to the Friday, the week's almost up, but you think you're on to something. You book the biggest meeting room in the building, and you call all the big stakeholders together, and you announce a massive enormous, revelation that you've had. You say home insurance has got nothing to do with travel insurance and neither of those got anything to do with car insurance. Now, at that point, you might get another strange look. The visitors might look at you and say, "Well, how much have we just paid you to come in for this entire week and set up all those meetings to tell us something that we've known our entire careers and the entire industry has known for, I don't know, the last 100 years?" Now, again, if you hear that, you may have just struck gold, because if the business say, "Well, that's obvious," it's a very, very strong sign that you've got things right.
00:46:18 Adam Ralph
Now you might ask, "Well, why didn't we just ask them in the first place? Why did we go through all that fact-finding and drinking all that coffee and getting stressed? Why didn't we just say it in the first place how is your business organized?" The thing is that these three boxes on the bottom are obvious, but the two boxes on the top are also obvious. It depends who you ask. It depends on their aspirations. It depends on their position in the company. It depends on their perspective of the company. You might get lucky and they might say "We've got home insurance, travel insurance, car insurance," or they might say, "We've got our policy service and the claims service," or they might say, "We've got products and customers," or they might say something else.
00:47:02 Adam Ralph
It's another illustration of the fact that modeling is not a top-down exercise. It is a bottom-up exercise, and people often ask me, "Well, do I really need to go into all that detail? Do I really need to look at the actual use cases and the behaviors and the scenarios?" and the answer is yes, and this is not a cheap exercise. But that's what service-oriented modeling is. It's a bottom-up exercise looking at the behaviors and not a top-down thing.
00:47:30 Adam Ralph
Now the whole front office, back off split in the case of insurance it's just one example of an organizational boundary. This might be a really nice shortcut. It'd be nice to go into a company, and they say, "Oh, we've got sales and marketing and billing," and you go, "All right, well, those are your service boundaries. Off you go." Now I think that may have worked at one time. If you think about the days before we automated, before we brought computers into the business, before we put databases and desktops on everyone's desks, companies used to hold data on paper. Data access was actually relatively expensive.
00:48:16 Adam Ralph
If you had filing cabinets in different sides of the building, you wouldn't want to walk from one side of the building to the other to access the data that you needed for your job. That would be very expensive. You tended to be organized with your data. You'd be surrounded by the filing cabinets you needed. When you pull a piece of paper out of your filing cabinet, write something on it, maybe send a message to someone else in your outbox, you get a message back in your inbox. Businesses were almost forced to be service oriented because of the cost of data access.
00:48:50 Adam Ralph
Now what we did was we came along with our fancy databases and our fancy computers, and we put one of these things on everyone's desk, and all of a sudden, data access became very cheap. Anyone could really access data from anywhere, just enter the right security flag set, whatever, and sometimes you just needed to know right person. What's happened as a result of that in many of the organizations I've been in is I've noticed that the modern department, the modern organizational unit is more like a mini kingdom than anything else. It's more a representation of a manager's skill in empire building, building the number of boxes under them in the org chart. One manager leaves, other managers fight over the scraps and claim parts of the business for themselves and say, well, we're going to provide that role, and we're going to provide that role.
00:49:46 Adam Ralph
It's not really any longer representative of business capabilities. These things change very often. One of the companies I've worked with not too recently, my organizational unit changed seven, eight times in a year as managers decided to split up things and carve out the responsibilities differently. It's a real shame, but for those reasons I really recommend to be aware of the organizational boundary. It's often not a good thing to use for our service modeling. It's a shame because it would be a nice shortcut.
00:50:28 Adam Ralph
Now I did promise to talk a bit more about microservices. I think a lot of great things have come out of microservices. I do have one big concern, which I'll try and outline to you. Now microservices are another weapon in our battle against this big ball of mud. You might read about microservices and think, okay, well, I'm going to split out our system into five microservices and then you read some more literature. It says, well, five microservices are not really enough. You need to have at least 10 so you split things up a little bit more.
00:51:06 Adam Ralph
Then you might read some more literature which says you need to optimize the deletion. You should be able to delete one microservices and rewrite it within the week that kind of thing. You decide well this isn't really enough. We need to split things up a little bit more. This looks quite nice. I'm sure you'll recognize this diagram. It looks a bit, well in fact very similar to the one we saw at the beginning of the presentation. It looks quite nice.
00:51:33 Adam Ralph
But as we've seen, the businesses have this habit of coming along with new requirements and say, "Well, you know, I was doing something last weekend. I had a great new idea," and you realize that well we need to make a call from this microservice to this microservice, and again, importantly, is our architectural constraint, our microservices architectural constraint doesn't say that we shouldn't do this. Each microservice has a defined interface and it encapsulates some behavior and this is what they're designed for. They're designed for one microservice to be able to use another microservice in some collaboration. You make the call and everything works. Sooner or later they come with another requirement and you find yourself doing the same thing again, and you've seen this picture before. No one intends to make a mess. But given enough time, months, years, whatever, you may find yourself going back towards this kind of situation where you've got arrows going between all different microservices.
00:52:35 Adam Ralph
Now we've seen that we managed to take the lines away. We've seen that we managed to take boxes away, but unfortunately, we're back to this big ball of mud scenario. Only this time, again, it's a big ball of mud with a difference. You've rolled this out onto 100 docker containers. They're all tokens scattered over the network. You've spent the last six months writing this incredible Kubernetes-based deployment system, which can roll out 10, 20 or even all of these things at the same time because you've found that you've had to do that quite often. What you've ended up with is a big ball of mud microservices edition. Again, that's a shame because we've reached for something which was supposed to help, and we've ended up in a much worse situation than we started with.
00:53:29 Adam Ralph
What we want to have is logical services with business-aligned boundaries, and we want them to be very loosely coupled, ideally as we've seen, with just ID, it's going across the wire. Now within these things, we have physical components. As we've seen, we might pick out a component from here, a component from here, a component from here, and put it on our Lego board to build a system. Within one of these services, we might have components for different reasons.
00:54:00 Adam Ralph
Now let's say that this service has something to do with bank accounts. One of the things it has to do is produce bank statements; another thing it has to do is lock bank accounts for fraud. Now producing bank statements doesn't really have such a tight SLA. It should go out on this day of the month. If the worst comes to the absolute worst, it goes out the next day. It's not the end of the world. You create a component for statements and you might put that on two machines for high availability. In case one goes down, the other one picks up should be enough. Whereas fraud has a very different SLA. If you detect fraud in the account, you pretty much want to lock that account instantly, because you're going to be liable for the money at the end. Our fraud component we might roll out onto, I don't know, 10 docker containers. We might have elastic scaling. We might use Kubernetes. We might use all that nice stuff we've read about in microservices literature.
00:55:04 Adam Ralph
If you want to call these things microservices, I won't be too upset. Now I don't really the word microservice for two reasons: micro implies that size is an important thing; and service, it's another overloading of the term service. I prefer to call them autonomous components, but you could think of these as microservices, because they very much fit what you may have read in the microservices architecture.
00:55:34 Adam Ralph
My big concern with microservices is that they get in the way of us finding these bigger boundaries, these logical service boundaries. Not much you'll read in the microservices architecture tells you about that. It tends to conflate the physical with logical. A microservice is a process, is a repo, is a thing that you roll out on its own, and that is a service. In service-oriented architecture, a service is a logical boundary. It is a business-aligned boundary. The components themselves, they are physical things. They are technical concerns.
00:56:11 Adam Ralph
Now you may think that in this box down here are we not building a mini ball of mud. Now I'm not going to say that's impossible right using any architectural technique with enough determination, you can create a mess in any way, in whatever technique you use. But I will say that it's less likely because as we've seen, we split things up within these logical boundaries for other reasons. We split them up for SLA concerns, we split them up in order to ship them into separate physical systems because the physical is different to the logical.
00:56:50 Adam Ralph
If you look at the box on the top right, you can see that there's actually only one component there. The service is the same as a physical component. They are one and the same thing, but it's just by coincidence, it's just by architectural coincidence that it made sense for that service. It's not an architectural constraint to say that one service must be one physical component. It's just by coincidence for that particular service.
00:57:18 Adam Ralph
That brings me towards the end. As I've said, Mauro is going to be running the next webinar on November the 13th, and he's going to dive much further into a specific example, and he's going to talk much more about the actual messaging that goes between the services. He's going to talk a lot more about the composite UI that we very briefly touched on earlier. I didn't go into that at all, but you can think of that Amazon UI as a composite of different services, and Mauro is going to go into that in a lot of detail in his webinar. That's the main unanswered question I've left in this webinar and that webinar is actually going to attempt to answer that for you.
00:58:08 Adam Ralph
Look out for an invitation in your inbox tomorrow. We'll be sending it out with today's recording. That brings us to the end. One last thing I'd like to say is that service-oriented architecture and service boundaries, like all the other things that you hear about in software development, it's no silver bullet, it's no golden hammer. It's not applicable for absolutely every situation. One good example is if you're working in a startup, startups don't really know what their businesses are. They find a few years finding that out. For instance, it took Facebook a number of years to find out that it's actually just a media company. It puts eyeballs in front of media and sells those eyeballs to advertisers. It's a typical media company model, with the advantage that they don't actually create any media. It's very lucrative.
00:59:03 Adam Ralph
But in the startup, even if you were to go down the service-oriented route from the start or you were to go down the more build whatever route from the start, when you find out what your business is, you're going to have to rewrite either way. As I said earlier, service-oriented architecture and finding service boundaries is not an inexpensive exercise. It's an investment which does pay off at the right time, but you have to be using stable business rules and you have to be in a business which is able to identify itself as what it is as a business in order for this to work.
00:59:41 Adam Ralph
That brings me to the end. I hope you've found that enjoyable. I've really enjoyed talking to you. Now I'm going to hand over back to Mauro, and we're going to have a look at some questions.
00:59:53 Mauro Servienti
Thanks, Adam. We have a few questions that came in before the webinar through email and a few that were asked live during the webinar itself. I'll start with one that came in earlier from Steve and the question is, after attending Udi's ADSD course, I'm of the opinion that correct service boundaries promote great performance, isolation, and maintainability, but there's always a cost. In other words, there's no such thing as free lunch.
01:00:25 Mauro Servienti
On one of the downsides, it appears to me, is that creating UIs become more complicated and correct SLA is predicated on being able to do a UI mashup of data from different services. The example given on the course was that the Amazon homepage, the same you used probably. My question is, am I correct that the SLA mandates a UI mashup? Secondly, what is a service in real terms? In particular, if it contains the UI, must the UI component be kept with all the rest of the services source code in the same solution, or is it to service logical construct. We are free to have the UI component wherever suits?
01:01:15 Adam Ralph
Right. First of all, thanks, Steve. That's a really good couple of questions there. With regard to the first point, you're absolutely correct that service-oriented architecture is not a free lunch. As I've said a couple times, it can be quite an expensive exercise. It is a time investment that requires one of the important things is to have access to the people who can actually tell you about the business and their time is expensive as well. It is an investment which needs to be considered and you need to consider when it's the right time.
01:01:49 Adam Ralph
Now with regard to your points about the UI, that ties into some of the things I've said in this talk and, again, you are absolutely correct that you do require what you refer to as a UI mashup, which we usually refer to as a composite UI. This is where each service contributes something towards that UI, so that you can make changes across the whole vertical stack. If you're introducing something like Bitcoin payment, you introduce it across the whole stack in one single service and you take advantage of the fact that physical is decoupled from logical and that you build a component from finance which gets shipped into the UI to give the UI part of that. Now as I said, I glossed over that in this webinar, but that is pretty much exactly what Mauro is going to cover in his webinar. To get deeper into that, I thoroughly recommend coming onto Mauro's webinar in November.
01:02:57 Adam Ralph
The last point about source control, again, because services are logical constructs, because they're logical things, not physical things, it frees you up to do what makes sense for that service. Now I would say that if you're seeing components from two different services in the same repo, that's a SML, because they shouldn't have any coupling between them if those are true service boundaries, which means you've got basically two things with zero cohesion between them in the same repo. I don't know if there's a reason to ever do that. I would say that naturally you would expect components from different services never to share a repo.
01:03:40 Adam Ralph
As for a specific service goes, you can do what makes sense for that service. You could decide to put the entire service to one repo, you could decide to put the front-end component in its own repo and some back-end components in their repos. It really just depends what makes sense for that service. I think once you've found your logical service boundaries, it actually gives you a little bit more freedom in that respect. But looking out for that smell of two services having their hands in the same repo because that doesn't seem right. I hope that answers the question. As with all the questions I'm answering here, I am going to follow up offline anyway. You'll get a chance to ask me more.
01:04:26 Mauro Servienti
Thanks, Adam. There's a very interesting question coming in through the Q&A panel. How do you organize development teams with services and systems? Who owns which part and how are new features to a system prioritized by each service?
01:04:50 Adam Ralph
Right. That's an interesting question. Thanks for that. This is something that is actually an important aspect. In fact, we sometimes run a workshop, a two-day workshop where we do go into this as well as something to augment what we're saying here about service boundaries. I think that what you can do in an organization is you can have separate service teams, and those service teams, for instance, you might have, say, a billing team who work on the billing service. Because of the physical and logical separation between the actual technical components in the service what that implies is that you may have to have, I don't know, a front-end developer, a back-end developer or developers and people with different skills with front-end development skills and knowledge of Objective C or whatever Xamarin or whatever is used these days and .NET people, so just a cross-skill team, and they must be able to deliver each component which that service needs to ship.
01:06:07 Adam Ralph
Now in a smaller organization that can become more a case of wearing the right hat at the right time, because you may not be big enough to say, "Well, you four people are the billing team and you four people are the sales team and you six people are the finance team or shipping or whatever." It may be a case of recognizing that we have these different services and I have to wear a different hat depending on which service I'm working on. The challenge with that then is to avoid the temptation to sometimes just start coupling things together, because if you've got hands in two places.
01:06:46 Adam Ralph
Now in terms of prioritizing features to a new system, I don't want to go into this too deeply now because it's another hour or two hours on its own, but we also have this notion of an ITOps service, which takes care of more technical concerns, either logging infrastructure, things like that. What is often useful then is to have an ITOps team as the gateway for features. They're the place where features arrive, and they prioritize them and decide where these things belong, and they might say well that's an entirely a sales thing. They liaise with the sales service and say, "Well, sales service is going to deliver that feature in its entirety." Or sometimes they can have responsibility of coordinating things between two services. Those things would not be technically coupled, but they might have some other reason to be delivered at roughly the same time. That's some kind of marketing launch or something like that.
01:07:50 Adam Ralph
Now I've introduced a few times ITOps, which I'm not really going to explain. If you want to know more about that, please follow up with me afterwards. I can actually get a couple of videos together for you from Udi's Advanced Distributed System Design course, which can help you out with that and explain that further. Back to you, Mauro.
01:08:16 Mauro Servienti
Thanks, Adam. There's another question from Andreas. How would you combine the different services parts into the system parts? Don't you need some sort of framework which combines the different service parts?
01:08:33 Adam Ralph
That's also really great question. I think the most obvious example of combining a system from components from different services is actually the UI. This is the part where ultimately you have a thing that looks like one thing to the user and it might be a web UI, it might be a mobile app, whatever it is. Now clearly then you do need some way of combining those components. In fact, this is something that we're playing around with now, Particular Software, we have some labs products to do this, and this is something again that Mauro is going to cover in his webinar in November. If you want to see a really good solid example of that, again, I would really recommend coming onto that next webinar because that will actually show you a concrete example of something that actually helps you to do this. Back to you, Mauro.
01:09:37 Mauro Servienti
Thanks again. One question from [Christian Jagger 01:09:41]. I would be interested particularly in the perspective of trying to move a legacy application to more modern patterns and practices. It's awesome to start with a greenfield project, but often folks don't have that luxury.
01:09:59 Adam Ralph
Right. That's also a very good question, the one that comes up quite often. Now, first of all, I'd to just address that point, that term greenfield. This is often used when we talk about patterns practice approaches frameworks. It's all very good in greenfield. What about legacy? Now one thing I've come to learn over my career is that greenfield is a myth. There's not really such a thing as greenfield. It's like a mirage that we create for ourselves on the horizon that we'd one day like to work on, but we never actually find it.
01:10:39 Adam Ralph
If you think about it, it makes sense because when is it that you come into a business and they know exactly what they want, they have nothing. They just want you to build it. That doesn't tend to exist. Well, I've already talked a bit about startup example. Startups don't know what their businesses are. They invariably create some level of big ball of mud and only when they realize what their business actually is, do they have a chance to start rewriting and start to make things better. Elsewhere, you might be asked to write a new system. Virtually every new system you write with will have to interact with legacy systems somehow. I would never call those things completely greenfield either. You can have a bunch of legacy to deal with from the start no matter how you start.
01:11:26 Adam Ralph
What that means is that we're always dealing with legacy systems. What I'm talking about right now is something to apply to a legacy system. This can be tough. I'm not going to say this is ever an easy thing. What it sometimes means is that you sometimes have to take your legacy system and you have to carve off bits of it. One thing we like to talk about quite often in Particular Software is the strangler pattern, which is where you take this nasty old thing, you gradually carve a bit off into something new and nice, and you carve another bit off, another bit off, and in the end that nasty bit in the middle gets strangled away into nothing.
01:12:10 Adam Ralph
What that means is that you can actually end up with a very awkward situation while that's happening. I sometimes use the analogy of you're trying to take a bus and you're trying to take this like a school bus or something and trying to make it into a plane. For a while you're going to have this school bus traveling down the road with one wing hanging off the end of it and it's going to look awkward and it's going to maybe look worse than it looked before, but the point is you're taking steps towards carving off those things and introducing nice things around the edges until you get rid of the thing in the middle. Someday your bus will cease to look like a bus and it will actually take off and fly.
01:12:54 Adam Ralph
Again, it's something I could go into in a lot more detail and it's something you could almost do a workshop on for a day. But again, I'd be very interested to follow up on that and I may be able to find some useful results from that, maybe one of these videos which can talk about that in more detail. Back to you, Mauro.
01:13:15 Mauro Servienti
Thanks, Adam. We have a few unanswered questions, but I think we're over time. We'll follow up with all the questions that we haven't been able to answer via email in the coming days. I'd like to remember you all that my colleagues and myself will be speaking at a number of conferences in the next few months in Zurich, Rotterdam, Berlin, Warsaw, Malmo and even Regina in Canada. Go to particular.net/events and find a conference near you. That's all we have time for today. On behalf of Adam Ralph, this is Mauro Servienti saying goodbye for now and see you all on the next Particular live webinar.

About Adam Ralph

Adam is a distributed systems enthusiast and digital nomad. He works for Particular Software, the makers of NServiceBus. Adam has designed and maintained complex software systems at several companies in the finance industry. He's seen both the good and the bad that can come from applying techniques like SOA, DDD, and microservices. He also likes to speak, maintain open source projects, and fix white space rule violations.

Additional resources