vault backup: 2024-08-10 09:01:40
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
**Review of yesterday**
|
||||
As developers, we have promoted a view of the world that is really tech-centric. This has caused recruiters to look for tech-centric skills _only_ and ignore developers that have spent 20 years in insurance, but know the business perfectly. **Exercise**
|
||||
How to convince for change back at work
|
||||
|
||||
- No appeals to authority (Udi said do this!). Usually ends up with other appealing to other authorities and you don't get anywhere.
|
||||
- No attacks on particular technologies (web api sucks!). This just ends with hurt feelings (the guy who just finished a web api project).
|
||||
- There is a LOT of business reason to stay with the way things are! It's hard to convince a business stakeholder to up-end current practices and fix problems with new technologies when fixes can just as well be put into place with known technologies and by expanding what we're already doing.
|
||||
- Keep in mind: to convince, we need to prove we've thought through the pros and cons of the messaging pattern approach and thought about the impacts on reliability, scalability, performance, etc and still need to go this route.
|
||||
- Udi doesn't recommend using messaging on a brand new product, out of the gate.
|
||||
- When making significant change to how a system works (implement messaging as a small replacement to a piece of the system), leave the old way in place and have a configurable value that switches between the two. This is a safety net for the stakeholder/decision maker to go back to the old way if anything goes wrong.
|
||||
EasyNetQ ( [https://github.com/EasyNetQ/EasyNetQ](https://github.com/EasyNetQ/EasyNetQ)) - nice little library for basic messaging on top of RabbitMQ.
|
||||
@@ -0,0 +1 @@
|
||||
How to communicate back to the organization? This is especially when the organization is already using SOA terms (like service) for other things (like REST or WCF services). You can slowly introduce SOA by using new terms (bounded context, business capability, etc) that are basically the same things that SOA talks about but are different to the organization and help get everyone thinking in a different way. If I have two things that I'm not sure about splitting up or combining together, will I be better off combining them or splitting them? When we come across a situation like this, it's often an indicator that we are slicing up the boundaries incorrectly. We need to think of everything in 3D terms, looking for the right angle to slice the pieces where the boundaries make most sense. When trying to find the boundaries, it's usually the case that we are totally confused as we look at how to split everything up (find the boundaries) until we find the right angle and then everything has a certain obviousness to it. Every industry has it's own angle of attack to decompose the elements of the business into service. If we figure it out in one industry, that same angle won't necessarily work in another industry.
|
||||
@@ -0,0 +1,5 @@
|
||||
System = unit of deployment
|
||||
Service = logical unit Mistake we've made as an industry: team, project, code base are all one. Services can be reused across systems. In the room availability service for a hotel, components could be reused in the website, guest kiosks and front desk rich clients. But, the component that searches the room availability in each system is all in the same service. _Branding Service_
|
||||
This service can have view models that collect the service components into a view to display in the chosen UI technology. Anything that's communicating the look and feel of a UI is part of the branding service. _IT/Ops Integration Service_
|
||||
Responsible for integration with third parties (credit card providers, etc). It is a technocratic component. It should do the integration, but not be responsible for "now the credit card should be charged". There is the act of charging the card and the act of deciding now is the time to charge it. This is the ONLY type of service that is allowed to ask other services for information. This type of integration service deals with the how and not the why or when. Lots of events passing data back and forth between services can be an indication that your service boundaries are wrong--especially if they are passing data that goes beyond identifiers. Finding service boundaries is all about identifying the volatility of the domain. Encapsulate things that will change into service boundaries. **IT/Ops Integration**
|
||||
Integration needs calling out to third-party systems or when third-party systems are going to be calling us. Purpose is to collect data from various services to surface that up as a query to a third-party. Recommend doing such integration without remote calls. We take DLLs from the various services and deploy them in together in the IT/Ops integration thing. IT/Ops integration is for integration with something you _don't_ control. IT/Ops integration also owns authentication, authorization, etc. Rarely does pub/sub with other services. It _could_ subscribe to something like an HR service that hires/fires employees so that it would know to add or remove a user's access. The place to make remote calls within a service boundary and NOT between service boundaries.
|
||||
@@ -0,0 +1,19 @@
|
||||
**Solutions Notes**
|
||||
|
||||
- The saga IS the domain model, so we can't make request-response calls from it of any kind (can't go get data)
|
||||
- You start the saga at account creation
|
||||
- The saga "never" ends (unless account is deleted, etc)
|
||||
- The sage completes when it receives events that end the account
|
||||
- The click messages come into the saga with a click sequence number. If the message currently being processed is not the next message (last click sequence is stored in the saga data) then we throw an exception and that message is retried later (eventually, hopefully, after the actual next message is processed).
|
||||
- Everything after that is easy
|
||||
- We have a 1 week timeout and a 2 week timeout for each purchase item command to know to decrement the 1 week running balance and 2 week running balance by the purchase amount to keep our week-based balances always up-to-date.
|
||||
|
||||
|
||||
**Buy item (in-app purchase)**
|
||||
Don't worry about mobile bit. Idea is to reward people to buy more quickly to encourage them to buy more quickly. Concern is that users are clicking really quickly. We've scaled out the handling over several machines. We used to do it with a traditional domain model. We did a select for orders over the last two weeks, then calculated the discount. Now we multi-thread it and two clicks might miss each other and a discount isn't applied. We need a model that will give users discounts that they deserve, but not give them discounts they don't deserve! Hint: saga!
|
||||
|
||||
- Multiple sagas?
|
||||
- What starts the sagas?
|
||||
- What happens when user runs out of funds?
|
||||
- What ends the saga?
|
||||
- What are the timeouts?
|
||||
@@ -0,0 +1,86 @@
|
||||
Naming things: important!
|
||||
Application - older term, a single executable running on single machine. Single source of input (user), doesn't talk to anything else.
|
||||
System - made up of multiple executable elements, running on one or more machines. Connectivity is inherit to their structure. Distributed systems come in when there are multiple machines. Multiple sources of information. Multiple users. Each executable element of a system can't be thought of as an application. Because: has to know element of connectivity. Lots of modern development aims to make connected executables look like a single application. ORMs make DB connections look like in-memory operations, for example. Truth is, we can never get away from the reality of connected components. Web apps are systems. Client talking to server. Server talking to database. So on. 8 fallacies of distributed computing
|
||||
|
||||
1. The network is reliable
|
||||
2. Latency isn't a problem
|
||||
3. Bandwidth isn't a problem
|
||||
4. The network is secure
|
||||
5. The topology won't change
|
||||
6. The administrator will know what to do
|
||||
7. Transport cost isn't a problem
|
||||
8. The network is homogeneous
|
||||
|
||||
Additional:
|
||||
|
||||
1. The system is atomic/monolithic
|
||||
2. The system is finished
|
||||
3. Business logic can and should be centralized
|
||||
Historically: applications, to applications sharing files, to applications sharing databases, to growing distributed executables. **#1 The network is reliable**
|
||||
We _know_ the network is reliable. But we still code that way. var svc = new MyService();
|
||||
var result = svc.Process(data); You get an HttpTimeoutException--how do you know what happened? Did the server get the data and the result timed out? Did the request time out? Can we ask a query API? What if it's cached and the cache doesn't know about the saved data yet? The network is unreliable. Therefore, when we write code like this, our code is fundamentally unreliable. Many times, we just log the error and move on. As if to say, it's not our responsibility to fix the problem. We are still in the mindset of application (rather than system) programming. Solutions
|
||||
|
||||
- Retry & ack, store & forward, transactions (don't roll your own, too many edge cases!)
|
||||
- Reliable messaging infrastructure (MSMQ, SQL server service broker)
|
||||
Message queuing: no request/response synchronous model. No concept of "invoke method and get response immediately". Message queuing forces the question: do we really need a remote call here? It forces the systems programming thinking to get us out of the application programming mud. Message queuing _does_ make our code more complex because of the removal of the request/response model. But leads to the forcing of making the above thinking paradigm shift. **#2 Latency isn't a problem**
|
||||
= time to cross the network is one direction Scaled latency from one CPU cycle to memory to disk access to a network request is 1 second compared to 19 years! We've been spoiled by Moore's Law (just wait until next year and we'll have twice as fast machines) which is no longer holding. Lazy-loading: the comeback of the bad old days of remote OO where every property was a remote call. Read the old books! Bad ideas seem to keep coming around with each new generation of programmers. Solutions
|
||||
|
||||
- Don't cross the network if you don't have to
|
||||
- Inter-object chit-chat shouldn't cross the network
|
||||
- If you have to cross the network, take all the data you might need with you
|
||||
**#3 Bandwidth isn't a problem**
|
||||
= width of the pipe Bandwidth keeps growing, but the size of data is growing faster. It hasn't followed Moore's Law. Often seen in ORMs eagerly fetching too much data. Bandwidth is usually poorly understood by developers. Gigabit ethernet = 128 Megabytes/s
|
||||
TCP = 40% utilization
|
||||
... => get to just 25 MB/s at the application layer Solution
|
||||
|
||||
- Move time-critical data to separate networks
|
||||
- Can't eagerly fetch everything/can't lazy load everything
|
||||
- Might need to have more than one domain model to resolve forces of bandwidth and latency
|
||||
- Separate query APIs (not time sensitive, but bandwidth heavy) from command APIs (time sensitive but not bandwidth heavy) so that we can separate the networks and allocate bandwidth appropriately
|
||||
**#4 The network is secure**
|
||||
Unless you're on a separate network that will never, ever be connection to anything else... End users are biggest sources of viruses, trojans, etc. You can't be 100% safe from everything. Solution
|
||||
|
||||
- Perform threat model analysis
|
||||
- Balance costs against risks
|
||||
- Most importantly, talk about it. Include PR and legal.
|
||||
**#5 The topology won't change**
|
||||
Unless a server goes down and is replaced, OR is moved to a different subnet, OR clients wirelessly connect and disconnect. What will happen to the system when those hard coded/config-file values change? Solution
|
||||
|
||||
- Don't hard-code addresses
|
||||
- Consider using resilient protocols (multicast)
|
||||
- Discovery mechanisms are cool, but hard to get right (what happens if you turn on the system and pieces can't find each other??)
|
||||
- Will your system be able to maintain response-time requirements when this happens?
|
||||
**#6 The admin will know what to do**
|
||||
Possible in small networks. Until...they get promoted. Their replacement probably won't know what to do. If there are multiple admins, rolling out various upgrades and patches, will everything grind to a halt? Conway's Law = software structure of a system will come to mirror the people structure (organizational) of the ones writing the system. Solutions
|
||||
|
||||
- Consider how to pinpoint problems in production (logging can helpful, too much can be harmful)
|
||||
- Build systems to allow running multiple versions in parallel
|
||||
- Enable admins to take pieces of the system down without affecting the rest of the system (queuing helps a lot)
|
||||
**#7 Transport cost isn't a problem**
|
||||
Serialization and deserialization can be an implicit cost to crossing a network, for example. Cloud environments are helpful because they actually associate a hard cost (bill at the end of the month) to your bad design decisions. On-premise installations are much harder to see these things on. Recommend cloud implementations for clients to help surface this kind of thing. Solutions
|
||||
|
||||
- Don't cross network if you don't have to
|
||||
- Don't wait until you're two weeks before going live to find this out!
|
||||
**#8 The network is homogeneous**
|
||||
It used to be easier: .NET/Java integrations were pretty good. Now we have python, ruby, PHP, node.js, etc that are tougher to get together. Networks are more heterogeneous today than in recent times (10 years ago). Semantic interoperability will always be hard, budget for it. You're probably going to get business interoperability boundaries wrong! When real users start getting into the system, you'll need to make changes. _Budget for it._ No real solutions for this one! **#9 The system is atomic**
|
||||
atomic = single, indivisible unit. No one sets out to make a big ball of mud. But, give most any system 5-6 years and it will turn into one. These aren't compiler problems--it's integration problems between pieces of the system. Reasons this happens
|
||||
|
||||
- Coupling through the database (gets worse with XML in db). Someone is going to change the schema and because no one knows you're depending on the schema, it will break everything.
|
||||
- System wasn't designed to scale out to multiple machines
|
||||
Think of a web application writing to a database and a reporting system reading from it. These two systems are tightly coupled through the database. Solutions
|
||||
|
||||
- Internal loose coupling
|
||||
- Modularize
|
||||
- Design for scaling out in advance
|
||||
**#10 The system is finished**
|
||||
The date when a system goes live is usually not when it is actually finished. Over time, organizations spend more and more on maintaining a system until they get to the point where a rewrite decision is made. The process just starts all over again. The cycle has to be broken to actually design the new system correctly from the beginning. Solution
|
||||
Software is not meant to be "finished". Unlike a building that gets done and then is maintained, software building and maintaining isn't any different. The maintenance can be just as much change as a new feature before the software is "done". Nothing rots! Maintenance is a misnomer in that sense. You never have to rebuild a wall because it's worn out. You never have to repair pipes because they rust. In software maintenance mode, the amount of code that can break only increases. The users using the system have valuable data that you have to keep. Maintenance is the harder part of code development. The myth of the rewrite: if _we_ could go back and make all the _right_ decisions, everything would be better. The division in thought of creation and maintenance is based on the myth of the system being finished. A system is only truly finished when no one needs the system anymore. The project metaphor is bad. A project is not meant to be complete. Think of it as a product instead of a project. A product is meant to be improved, released again with improvements, etc. The expectation is that the product will evolve and improve. Rewrites are not healthy. They essentially say, the last 5 years of development are going to be thrown away. Scope creep is a big problem with a rewrite project. "We'll do everything the old system did and now I want everything else I've been waiting for!" **#11 Business logic can and should be centralized**
|
||||
"First name should be less than 40 chars" - enforce in UI? BL? DB? Everywhere?
|
||||
What if the business logic changes??
|
||||
Wouldn't it be great to put it in one place and be done with it?! What is the real likelihood that a business rule with change? We see somewhat of a bell-curve of the probability that a business rule with change. The longer the system is live, the less likely it is that a rule will change. _The probability of change is different for different business rules._
|
||||
|
||||
Solution
|
||||
Logic will be physically distributed. We can still centralize in the development view (more reading: 4+1 views of software architecture). Tag source control for feature implemented. When changing a business rule, we can look at the tag and know exactly what code is related to that requirement by looking at source control. Requires us to be much more deliberate and disciplined with using source control and using it as not just a tool, but part of our architecture. The point is more that we can solve some issues like this in a different dimension (source control) than we would normally think (reorganize the code to have centralized business rule code). **Summary**
|
||||
Best practices have not caught up with best thinking.
|
||||
Technology cannot solve all problems.
|
||||
Adding hardware doesn't necessarily help.
|
||||
@@ -0,0 +1,57 @@
|
||||
CQRS does NOT change service boundaries or any other implementation or approach. You will be doing CQRS inside of a service boundary. If you have a business component, CQRS will happen entirely within a BC. **History**
|
||||
Why did it come about? Multi-user collaborative systems. Users end up seeing stale data. The problem comes when the users start using their stale data to make decisions about how to change data. In a collaborative environment, we might end up overwriting each other's changes. Collaboration is one situation that traditional architectures didn't handle really well. The assumption was optimistic concurrency. A big focus of CQRS is the data itself and it's accuracy, along with performance. How quickly can we keep the users up-to-date? **Collaborative Data**
|
||||
How much data in an average system is collaborative? Not usually too much. On an Amazon page for a book you might have:
|
||||
|
||||
- Inventory (multiple users update stock numbers by buying books, shipments increasing stock)
|
||||
- Ratings (multiple users submitting ratings)
|
||||
In a traditional layered system, you might cache data to query against and let updates/adds/deletes go all the way through to the DB. This is kinda of CQRS. But, in the end, you don't solve the contention at the database when two updates come at once or very close proximity.
|
||||
|
||||
- For a lot of data, it just fits much better to think of a single updater. Think of the price for a book, or it's title. You most likely will have one product manager updating those kinds of data one at a time.
|
||||
Whatever the simple thing is to do, do that! **CQRS Theory**
|
||||
Be up-front about data staleness
|
||||
It's important to be up-front about the staleness of your data. A bank might say "your balance is accurate as of 10 minutes ago". Many systems are not up-front like that with how stale data is. Keep queries simple
|
||||
UI -> persistent view model, query only between them.
|
||||
For each view in the UI, have a view/table in the DB (select * from my table where id = @id)
|
||||
|
||||
KEEP IT SIMPLE Be careful of data duplication. Another signal of service boundaries being off.
|
||||
Duplication => logical structure that has a great deal of overlap with another logical structure
|
||||
Replication => moving data from one physical place to another physical place. Moving data, same data in two different places, but part of the same logical structure.
|
||||
Data duplication _can_ be ok, but only with super, super stable business concepts. If you find one, you should be suspect of it. Deployment and Security
|
||||
|
||||
- Deploy persistent view model DB to the web tier (only SELECT is permitted)
|
||||
-
|
||||
- Don't have to go through firewall - faster
|
||||
- Don't use the term DB, use the word cache
|
||||
- Document DB is a good choice because you usually don't need any relationships
|
||||
- If you find yourself adding a cache on top of persistent view model, you're probably making it too complex
|
||||
- Role based security
|
||||
-
|
||||
- Roles probably map to service boundaries, so the data for a particular role probably comes from a different table
|
||||
- This will simplify role-based security
|
||||
- Just as secure as in-memory caches, if not more so
|
||||
|
||||
Use for preliminary validation
|
||||
|
||||
- When submitting commands, we need to perform validation
|
||||
- Because the persistent view model is close, it's fast for validation
|
||||
- Uniqueness: we can do a quick check in the PVM to check if a username is already taken. This wouldn't work in the rare case of a race condition: different users signing up at the same time with the same username.
|
||||
- Related entity existence: address validation, existence of street name
|
||||
- -> results in few commands being rejected
|
||||
As engineers we are often looking for the single solution that will solve all of our problems. That never happens. In solving scalability issues, we can usually follow the 80-20 rule: a solution that solves 80% of the problem. **Commands**
|
||||
Validation and business rules are often used interchangeably. What we mean with validation is:
|
||||
|
||||
- is the input potentially good?
|
||||
- structured correctly?
|
||||
- ranges, lengths, etc?
|
||||
Business rules:
|
||||
|
||||
- should we do this?
|
||||
- based on current system state
|
||||
When you have if statements in your business logic that is operating on data in your database, you can still end up with data that is invalid. For example, if someone adds a book to their shopping cart and then 2 minutes later that product is marked to no longer be sold, then the item is still in the shopping cart. Even though the business rule said we can't add products we don't sell anymore to shopping carts, the shopping cart addition action passed before the flag was set. Business rules are foiled by race conditions. **Should we do what the user asked?**
|
||||
We need the system to remain consistent, so we need to define transaction boundaries. Sometimes these transaction boundaries are hard to find. For a grid of orders that allows in-place editing, do we have a transaction for each field edited, for each row edited or for the entire edited data set as a whole? We are not capturing user-intent very well. In a traditional UI, the checkbox doesn't capture what the user wants to do. When a user checks three boxes to pick three seats next to each other at a movie theater, we are not capturing the fact that all the user wants is three seats next to each other, maybe in a certain general section. Solution: look at user intent you want to capture and model that directly. Instead of allowing a user to select the exact seats in the exact section, we gather the intent of the user to have 3 seats in a certain section and we let the system pick the best fit for the request. This then also allows the request to be asynchronous. We can tell the user the seats they got and allow them to cancel if they don't like the choice. CQRS is more of an analysis tool that can reveal this type of thing instead of just a magic tool that will solve problems. There is no longer a need to show an actual status of seating. So, the query model is simply a static image of the stadium and it's sections. The command model is then the revised version of capturing user intent, letting the system find the seats and then notifying the user about it. Do we need to preserve this idea of first-come, first serve? When it comes to collaborative systems online, the great thing is that no one knows who was first in line. **What is a good command?**
|
||||
You want to be able to structure your commands to be able to do something like:
|
||||
|
||||
- "Thank you. Your confirmation email is on its way."
|
||||
- Just fake it in the UI (amazon shopping cart example)
|
||||
You need to think about how to design away the technical contention. When you're in a collaborative environment, you will see more command-centric types of concepts that capture user intent. When not in a collaborative setting, you will see more "update entity x in such a way" level and you know you're doing CRUD. When in that situation, stick with synchronous, UI to DB setups and scale out the DB. **How to use CQRS**
|
||||
CQRS is too much complexity to apply to an ENTIRE system. It should be applied to only the components that NEED it. CRUD operations outside of a collaborative environment simply don't need the complexity that CQRS requires and, in fact, that complexity will harm the system. In a collaborative domain, you expect high contention. This might change your data model and persistence model. The types of systems were are creating today do not play well with abstractions. So, even though we are so good at abstracting as we're designing code these days, it fails when we come to try to apply it to enterprise software. We need, rather, to find the simplist solution that solves the actual problem. We shouldn't try, for example, to build a document database on top of a relational database. We shouldn't try to build a relational database in a document DB, etc. Start with data-level modeling!! CQRS is a set of questions you ask that drive the design rather than be a set of answers itself. It's an analysis methodology more than a tool to find a solution.
|
||||
@@ -0,0 +1,28 @@
|
||||
**Naming**
|
||||
Naming is challenging. When you have web1, web2 and web3 and db1, then everything's pretty easy to keep track of. When you get to bigger systems, naming becomes more important. Usually naming follows the service name. When you pull out an Autonomous Component, naming is even more important. Commonly, you use a dot notation of Service.BusinessComponent.AutonomousComponent. But how do you name the AC? Using the main message that is processes is helpful. It is also helpful to prepend the name of the company too. So, the name becomes Company.Service.BC.AC. **Monitoring Queue-Based Systems**
|
||||
Error queue notifications go to admin to signal problems. Identify bottlenecks: well-named queues tell you where the bottlenecks are. Important are:
|
||||
|
||||
- number of messages
|
||||
- throughput
|
||||
- These two numbers above give you the wait time of each message. NServiceBus calls this the CriticalTime of and endpoint.
|
||||
- The context of the critical time is essential. If we're generating PDFs, then 2 seconds is awesome. If you're running a high-frequency trading system, then 2 second wait times will run you out of business.
|
||||
**Scalability**
|
||||
Traditional competing consumer:
|
||||
|
||||
- one queue
|
||||
- more than one AC feeding off of queue
|
||||
You don't scale out an entire system, but individual ACs. You know to scale out when you see the AC continually violating or close to violating SLA. **Virtualization - Part 1**
|
||||
Almost all production environments are virtualized. We can connect our monitoring environment and our scaling processes. We can connect to our SLA--as it's reaching its limit, we can scale out an AC. **Fault Tolerance - high level**
|
||||
- Any number of active backups
|
||||
- Automatic load balancing
|
||||
- By hosting in a virtual environment, our data (database, queue storage, etc) is all stored on a SAN. The SAN has snapshots and is backed up. We have a high degree of fault tolerance **Versioning**
|
||||
Make updates backwards compatible.
|
||||
Test them.
|
||||
Start at the back of the system and gradually move forward. Update the database, then the server, then the messages, then the client. You can script rollouts.
|
||||
|
||||
- CI server builds new version
|
||||
- CI installs v2 next to v1
|
||||
- CI checks for error message in the queue
|
||||
- CI finds some and rolls back v2 and notifies developer
|
||||
|
||||
This gives developers very safe exposure to the prod environment for their new code.
|
||||
@@ -0,0 +1 @@
|
||||
What is a process? A set of activities in sequence triggered by internal and external triggers. Long-running processes are multi-trigger processes. They have state to keep. The fact that it's a "long-running process" does not mean it has to take 5 minutes or an hours or five days. The issue is more the multi-trigger effect and the need for keeping state between the two triggers. We don't know when the second trigger (or any subsequent) will come. The early work for long-running processes was done in the 80s and 90s for long-lived transactions. The answer to solving this issue was to break up the transaction into several small, short-lived transactions. The best, most reliable way to resolve race conditions is through retries. Orchestration is not a service by itself. Unit testing sagas is important. Sagas don't have to end! When a saga is not "running" it's just sitting in the database. So what?! A saga that "runs forever" is just a record in the database. Moore's Law is in our favor in the case of storage--it's increasing by leaps and bounds and getting cheaper all the time.
|
||||
@@ -0,0 +1,4 @@
|
||||
What domain models are not!
|
||||
What problem were domain models there to solve? Back in the day, we had layered architecture with a business layer. The business rules (first name shouldn't be longer than 10 characters) were spread all over the place. Patterns of Enterprise Application Architecture was written and everyone got excited about the Domain Model pattern. Domain Model pattern was contrasted against Active Record, Transaction Script, etc. Domain Model _sounded_ so great. Who wouldn't want a domain model in their system? Just like agile. Who would _not_ want to be agile?? A domain model follows the rule of component driven development. They expose properties, methods and events. There are clear boundaries to a component. Context of domain model was to be "if you have complicated and ever-changing business rules". Meaning...this pattern was not meant to be used for everything!!! Not meant to manage all of data access. Domain model is supposed to be independent of all other concerns. For example, UI concerns should not enter in. DB concerns also. Communications also! They are only simple, stand-alone components. No direct or indirect coupling. They are to made up of POCOs. Domain Models are NOT entity relationships! Domain model is supposed to handle complex and ever-changing rule. Products always have names. Orders always have products. Customers always names and phone numbers, etc. If we have those types of objects we don't have a domain model! This was its problem, the name. It made people think that just about any collection of objects is a domain model. These types of classes ended up getting all sorts of reasons to change, violating the single-responsibility principle. Unit tests became overly-familiar with the internals of the domain model and kept breaking. **When you are following the domain model appropriately...**
|
||||
You could deploy it anywhere.
|
||||
You can have more than one domain model! Nowhere does the definition say you have to have a single model that covers _everything_ in your domain! Logic in the DB can fit a specific set of problem. Specifically when you need to do operations on huge amounts of data. The DB handles that best. Why are we moving 20GB of data to a server to process 20KB of logic and then just put the 20GB back into the database? You CAN mix patterns. You may need a domain model pattern here, a transaction script pattern there and the active record pattern somewhere else.
|
||||
@@ -0,0 +1,22 @@
|
||||
Optimistic (first or last one wins)
|
||||
Pessimistic (first person locks it)
|
||||
Realistic - what we want is something that is able to lock things for the right amount of granularity. One difficulty: multi-table spanning transactions. Databases support MVCC (multi version concurrency control). If you turn this on, expect to see exceptions in your logs. This is a clue that you have some collaboration going on! You might be able to redesign your business logic to solve your collaboration issues. Therefore, traditional entity-relationship models are dangerous (you'll be operating on more than one entity at a time). How to get to realistic concurrency?
|
||||
As part of transactions, you get one single domain object. You call methods to update its state. If successful, it updates its own state. This applies to entities that can be operated on outside of a single transaction. This is a simple rule, but very difficult to follow. However, it is much easier to follow if you have split things up into good service boundaries. Some changes can be concurrent, others can't (?). Good: you change the customer's address, I update the customers credit history.
|
||||
Bad: You cancel an order, I ship an order. We have a race condition. You're in a collaborative domain. The rules of CQRS applies. Commands are almost never supposed to fail. This leads us to deeper business analysis. Fundamentally: race conditions don't actually exist in the business domain! Use cases and business processes are always expressed by business domain experts in sequential form. Most of the time, we find a race condition, it is the result of a work around. We need to dig deeper and find out what the race condition was originally trying to solve. Example, we don't want allow them to ship canceled orders and they can't cancel shipped orders. Any time it's not immediately apparent how the company is going to make money or save money, you don't understand the business model completely. Try business analysis: 5 whys. You're supposed to listen! Ask for the business process to be explained to us as if we were a five year old.
|
||||
|
||||
1. Cannot cancel shipped orders
|
||||
|
||||
1. Why? because shipping costs money
|
||||
2. So? that money would be lost if the customer canceled
|
||||
3. Why? we refund orders immediately
|
||||
4. Analyze:
|
||||
|
||||
1. when an order is canceled, does the refund need to be given immediately? => no
|
||||
2. can we give a partial refund? => yes
|
||||
5. Result: now we can get rid of the one if-statement to check if the order is shipped before we cancel
|
||||
6. Other analysis
|
||||
|
||||
1. Most orders are canceled quickly after being made => it's not equally likely that an order will be canceled at any time after the order was made
|
||||
2. So...wait until the high-probability period is past to actually begin the shipping process
|
||||
2. Cannot ship canceled orders
|
||||
One conclusion! Domain Models are SAGAS! Business people like to talk about business policies. Refund policies, insurance policies. Sags are a really good way to implement policies. They have that time component to it that allows us to model domain concepts well. "In two weeks you will qualify for this". "You can cancel for free within the first day of your order".
|
||||
@@ -0,0 +1,2 @@
|
||||
If you see yourself pushed events back and forth between service boundaries, creating a kind of data synchronization process, then you need to re-evaluate your service boundaries! **Engines**
|
||||
Engines were kind of a big deal at one time. Think of search engines or rules engines. Now we say search service or rules service. The important aspect of an engine is that there is lower-level framework-type part that is the engine itself. Then, there are bits and pieces that we plug into the engine. These bits and pieces are not necessarily coupled to each other. The engine doesn't encourage dependencies that are plugging into it. Sometimes when you have complex and ever-changing rules you actually need an engine instead of a domain model. For example, a pricing domain model might be influenced by data from many services. A domain model would then break all of your service boundaries. Pricing, risk, search are common examples of the engine pattern. Litmus test: take the name of the problem, append the word "engine" and then google it. If you can't find anything about it, it might not be a good idea. If you do find stuff, you might be able to use an engine to solve the problem. Engine code lives in IT/Ops. Engines can listen to events across service boundaries and make decisions based on the aggregation of the data of those events.
|
||||
@@ -0,0 +1,33 @@
|
||||
Jumping straight into SOA often does not work. This is related to Conway's Law that the people architecture at a company affects the code writing architecture. To get to SOA, you need to refactor the people architecture of your company as well, over time. The boundaries of progress moving toward an SOA business are note always clearly defined. Phase 0 is: big ball of mud, everything overlapping, etc. This mess has taken people at the organization a long time to create and lots of it works. Trying to replace the whole thing will probably fail. Conversation, however, about rewrites are healthy. It implies that "we need to do something different". Slowly improve things that still have business value and allow a "tax" on top of each feature to improve the structure of the system overall. **Phase 1**
|
||||
Don't go apply this to the next mission-critical system. Try something small to get your feet wet. Get the first queue in production.
|
||||
Ops: new stuff, but not very much of it (one queue)
|
||||
Dev: very low, one message handler, refactor a small system
|
||||
Org: mostly dev organization, getting them used to SOA principles. You can do lunch and learns, workshops, etc. Get developers to care, wanting good quality code, care about their craft. Once you get there, they start saying things like "it would be easier and faster to rewrite this!".
|
||||
|
||||
| | | | |
|
||||
|---|---|---|---|
|
||||
|Ops|Dev|Org|Duration|
|
||||
|Medium|Low|Lunch & Learns, Workshops, etc|6 months (small, young companies) to 12 months (bigger companies)|
|
||||
**Phase 2**
|
||||
Starting to see belief that things can actually change--there's hope! Choose to deliver functionality to the business over making unnoticeable changes--you have to keep the value apparent and the budget there. You may start risking breaking stuff here. You start at the end of each use case, to publish events. You're creating hooks, even if you don't know what they'll do yet. Doesn't HAVE to be a bus message. Could be something as ugly as writing to tables that others are looking at. You're just trying to get the concept of events a common practice. If you come across functionality that could be improved and done easier with subscribers (let's say also using signalr to update a user in their interface that gives extra business value). You're not worrying about service boundaries or data duplications...etc. You're trying to show the business that things are starting to pay off. Using the "new way" is making things faster and better. You need to keep the feeling of momentum. Most of the work is still being done in the big ball of mud to maintain it and keep it going. You want to have a good, small core of people on board with the changes to start planning things out and looking ahead. We want to do SOA! The work by this group is quiet and off to the side. A couple of hours here and there from a real domain expert. You're asking the domain expert for a few hours every-so-often to ask questions, verify your vision--starting to find the service boundaries. You're not yet sharing this with the larger organization. You're trying to get a general direction for your services--not having to know exactly what they look like yet, but being pretty sure it's in "this" direction.
|
||||
|
||||
| | | | |
|
||||
|---|---|---|---|
|
||||
|Ops|Dev|Org|Duration|
|
||||
|Med|Med|Learning and practice UI composition techniques, pub/sub patterns, decoupling. Much more explicit training efforts. You are starting to want to know what you're creating.|6 months - 18 months <br>If you don't feel you have the right momentum built up, wait--take your time.|
|
||||
**Phase 3**
|
||||
You're trying to get to the point of the business being willing to wait longer for new features. You start hacksawing the big ball of mud. You carve out a piece and add it to the subscriber where it makes the most sense. You have to be very careful with the data model. Some of this is changing things to composite UI stuff. It's difficult to be restabilizing the big ball of mud all the time--that's one of the hardest parts of this phase. The issue in the first place with the big ball of mud is that you don't know what changing any individual piece of the ball will effect. The SOA work from phase 2 is important because you need to know (at least basically) where you will be putting rewritten code. The small meetings about SOA are opening up to more executives. Your concept of the correct SOA is crystalizing. You're meeting with more domain experts and have the approval of executives to pull them into (probably) weekly meetings. You need to have good answers for all of the edge cases that business people care about (and need). That's what the big ball of mud is--the answer to a thousand edge cases identified over time. A large organization can end up stuck in phase 3. Right when you're getting to a good spot, they buy another company and now you need to integrate an entire new set of legacy systems. You can do this! You get it done in 12 months and...the CEO buys another company and you start all over again. Sometimes tech leadership leaves when they get frustrated that the vision will never happen. Momentum is important (almost at any cost) to break through to phase 4.
|
||||
|
||||
| | | | |
|
||||
|---|---|---|---|
|
||||
|Ops|Dev|Org|Duration|
|
||||
|Low|High|SOA design is being clearer and clearer. You're training on what it means to work in an SOA environment. Don't be talking about things that are too far ahead. Be talking no more than things that are about 6 months ahead.|12 months - 36 months|
|
||||
**Phase 4**
|
||||
Phase 4 is hard because you start dealing with data. You start chopping up the big, monolithic data into the service boundaries. You need to treat the data migration code as long-term code that you can run and rerun and that you will maintain just like product code. Ops effort is medium because there are new database, etc. You'll be writing code and building across multiple repositories. The big ball of mud is shrinking quicker than before. You're migrating data out and building services. You're completely out the rest of UI composition. You'll see lots of opportunities to make things better towards the tail end of phase 4. You can learn to live with it.
|
||||
|
||||
| | | | |
|
||||
|---|---|---|---|
|
||||
|Ops|Dev|Org|Duration|
|
||||
|Medium|High|At some point, it will become clear that the way that teams are structured is hurting us. You'll hear "we need a reorg". The re-org will be along service boundaries. It should be clear to everyone at this point what the service boundaries are. Reorgs are hard and so you want enough momentum at this point to make it through.|12 months - 36 months|
|
||||
**Notes**
|
||||
Having a pattern of fallback to an old way (config to switch between new and old way) is a useful practice throughout all the phases. It makes us bolder to try new things because we can always immediately switch back to the old way. This helps with your momentum. Enough failures will lead to a loss of momentum. Having the immediate fallback makes the failure less noticeable (if at all). You can be assured that things will never be _worse_ than they were before. A good metaphor is rock-climbing. Every time you make a certain distance, you hammer in an anchor. If you fall, you only fall so far. The percentage of our work that is dedicated to clean-up and refactoring should never be over 30%! OUR JOB is to deliver business value to the business. Trade-offs never stop. A healthy state of things is to always be seeing where the improvements can happen.
|
||||
@@ -0,0 +1,15 @@
|
||||
Traditional architecture was layered on top of a six-pack: two web servers, two service servers, db and failover. The DB became the bottleneck and caching was introduced. Caches are hard to scale-out and can cause even more exasperating concurrency issues. Caching didn't turn out to be a silver bullet. We moved away from in-process caching towards some more explicit caching (like Redis). One problem: the amount of data is going to grow faster than the amount of memory you have in your caching servers. So, you have cache invalidation. Caching can actually degrade performance under higher loads as the hit rate erodes and memory runs out. If you cache, pay attention to your hit rate. **Content Delivery Network**
|
||||
Great for off-loading static content. Images, JS, css, etc. Learn and leverage DNS! Don't use a smart donkey when a heavy ox is what you need. Don't make your web app smarter, when the heavy ox (the web) can be utilized to take part in your web application. HTTP output caching--IIS will cache the HTML output and serve the binary data immediately without re-rendering a page. Get information from the business on what things need to be refreshed quickly and what things don't need to be updated all that quickly. Help them realize that if _everything_ is fast, then nothing will be fast. A real cache doesn't even hit the controller. It's at the web server level. Model your site as a collection of static resources. Your navigation is Nav.xml (or html or whatever). They all just have varying times-to-live and can even be deployed to CDNs. The web was designed around the concept that storage is cheaper than bandwidth. So, caching is everywhere (browser, CDNs, output caches, etc). There's an ISP cache too.
|
||||
|
||||
- Browser
|
||||
|
||||
ISP
|
||||
CDN
|
||||
|
||||
- Output cache
|
||||
|
||||
In-memory caches
|
||||
|
||||
- Fresh request
|
||||
The "free" caching of the internet is our heavy ox. Think of this way: a user who finally arrives at your website after having traipsed across the vast desert of the internet checking cache after cache for fresh data, is dying for fresh data. Is that the right place to then serve up stale cached data?? If you are building a site that very local. Let's say for dog owners in Dallas. Then, the heavy ox of the web caching system won't help. It might hurt actually because you'll send users further away from your site to get static content. That's when you might need caching more. Communicate with your ops people that as your site is live over time, fewer and fewer web requests will hit your servers over time. Otherwise, this can be a concerning sign, "we're not getting any hits!". Explain that, with the caching of the 'net, this is normal. Of course, the helpful thing here is client-side composition. Browsers can often work better and faster with multiple requests at once (client-side composition). This is not true for mobile browsers. Battery life is more important there and so one bigger request is probably more important. **Personalization**
|
||||
Not all data is global data. Weather widgets are good examples. This is local weather for the user. Personalized information is still scalable and internet-cacheable when we do the deep analysis.
|
||||
@@ -0,0 +1,34 @@
|
||||
Coupling = measurement of dependencies
|
||||
|
||||
- if x depends on y, there is coupling between them
|
||||
- Afferent coupling (Ca) - who depends on me
|
||||
- Efferent coupling (Ce) - on what do I depend
|
||||
- If x depends on y:
|
||||
-
|
||||
- x is efferently coupled to y
|
||||
- y is afferently coupled to x
|
||||
|
||||
How much coupling is too much? How much coupling is necessary for a class to be useful, but not too high to make it tightly coupled? Certain low-level frameworks or classes we might expect to have a high coupling. For example, logging we would expect to be connected to a high number of other classes. In fact, a low coupling level for a coupling framework might signal problems (not enough logging going on, etc). Efferent coupling is really the bigger issue. A large set of changes can cause problems in the depending class. If A calls one method on B, is it's coupling the same as C which calls three methods on D? Probably not. D has one afferent coupling to C, but C has three efferent couplings to D. Coupling that you can't see
|
||||
Two components that depend on one DB are coupled together. **Loose coupling at the systems level**
|
||||
- minimize both types of coupling
|
||||
- zero coupling isn't really possible Coupling Aspect #1: platform
|
||||
Also known as interoperability. 1 of 4 tenets of service orientation: Share contract and schema, not class or type _Solutions_
|
||||
Text-based representation on the wire (XML/JSON)--with or without schema.
|
||||
Use standards based transfer protocol like http (or smtp, udp, etc). Coupling Aspect #2: temporal
|
||||
Synchronous calls. Caller has a high degree of coupling to callee. _Solutions_
|
||||
Canonical example: querying a system. There isn't much to do (for the client) until the data comes back. Caching can be used to reduce temporal coupling. Which side should cache be on? Providing or asking side? If you put it on the asking side, then at least you know that you are using a stale copy of data. This can reveal to business stakeholders where data can be stale. This, in turn, then can reveal where you proper service boundaries should be to meet business requirements. Pub/sub helps us solve temporal coupling.
|
||||
- Subscriber must be able to make decisions based on somewhat stale data
|
||||
- Requires a strong division of responsibility between publishers and subscribers
|
||||
- Only one logical publisher should be able to publish a given kind of event Designing events: nothing everything should be modeled as an event. Bad: "SaveCustomerRequested".
|
||||
Good examples: "CustomerSaved", "OrderAccepted". It's a fact--already done. Subscriber shouldn't be able to validate it. Include validity period in events so that subscribers know how long to use it. ProductPriceUpdates { Price: $5, ValidTo: 1/1/2015 } Your assumption should be that the way you first divided up your services is actually wrong. _Temporal coupling goes hand in hand with business consistency._ Coupling Aspect #3: spatial
|
||||
Topology of IP addresses, DNS and machines. _Solutions_
|
||||
Application level code should not need to know whehre cooperating services are on the network.
|
||||
Delete communications to lower layer, the service agent pattern.
|
||||
How does the agent know which destination to send the message to. Load balancing - clients talking to servers through load balancer. Routing is first logical, then physical. Prefer many strongly-typed messages (clearly communicating intent) over parsing message intent from the content of the message. **Summary**
|
||||
Loose coupling is more than just a slogan. Coupling has 5 dimensions:
|
||||
|
||||
1. Platform
|
||||
2. Temporal
|
||||
3. Spatial
|
||||
4. Efferent
|
||||
5. Afferent
|
||||
@@ -0,0 +1,20 @@
|
||||
Focusing on one-way messaging for now. Why?
|
||||
|
||||
- Can reduce coupling
|
||||
-
|
||||
- XML/JSON for platform decoupling
|
||||
- Asynchronous for temporal decoupling
|
||||
- Can reduce afferent and efferent coupling
|
||||
|
||||
Asynchronous messaging: one-way, fire-and-forget.
|
||||
|
||||
- Requires ID for retry, deduplication
|
||||
Distributed queuing: queue is local, messages are stored and forwarded. When connectivity is present, outgoing queue sends message to incoming queue on remote machine. Once the message is queued for delivery, the fire-and-forget process is done. Various failure scenarios:
|
||||
|
||||
1. Network failure
|
||||
2. Remote machine goes down
|
||||
3. Remote process goes down
|
||||
With RPC-based systems, with increased load, throughput keeps step for as long as it can until memory garbage collection begins to overtake processing until throughput begins to drop dramatically as load continues to increase. You have too much synchronous processing going on. How does messaging improve this? Main thing: it replaces memory and CPU time with storage. Memory and CPU only has to queue the message (store it). It's async by default. Messages fully contain the information of the intent of the action to be taken. We can have more than one handler for a single message. Important point: your API becomes a set of messages. **Fault Tolerance Scenarios**
|
||||
When servers crash
|
||||
When databases are down
|
||||
When deadlocks occur in the database Without messaging, each scenario basically leads to the data evaporating and putting the onus on the user to notice he needs to resubmit, if he wants to. The client that originated the message is not responsible for retrying the message. We should store the data and retry it internally. The client isn't actively waiting for a response. Bad idea to keep messages in auditing queue for extended periods of time. Need to watch the audit queue and move messages to longer-term storage. Audit queue can be hard to interpret because messages are not in chronological order. **Leveraging message headers** => we can create a sequence of events, recreates http-like synchronous sequence of events.
|
||||
@@ -0,0 +1,7 @@
|
||||
**Web Services with messaging**
|
||||
Separate pieces of logic behind their own messages. This is so that, for example, if the database transaction fails, it won't continually try to hit the web services, or vice versa. If you separate the operations behind two different messages, then the database transaction can be retried on its own and the web service call can be retried on its own. Instead of trying to make web services idempotent and re-engineer everything that message does, just change the interaction between your service and the web service to take place over messaging instead of HTTP calls. Use client-generated IDs (GUIDs) so that data can be uniquely identified throughout the business process and de-duped after failures and retries. **Request/Response with messaging**
|
||||
Response is nothing different than the request. It's just a message going back the other way. It goes back to the return address. To make this work, you have to have a correlation ID so that the response an endpoint gets can be correlated to a specific message it sent. Otherwise, after sending 100 messages, who knows which message the response relates to? With NServiceBus, you can provide a callback that is executed when the return message is received. **Multiple Responses**
|
||||
We can send multiple responses back to the requester by simply using the same correlation ID. For example, this would be useful to report status to a UI on a long-running process. **Subscribe - Publish**
|
||||
Subscribe as a request, publish as a series of messages coming back to that subscriber over time. Logically, this is exactly the same as request, multi-response. The subscribe request doesn't actually need to send a message to the publisher. It depends on the queuing technology. If it supports pub/sub natively, then it's just a configuration of the broker to tell all subscribers when a message is published to a certain topic. Pub/sub is not multicast. If a subscriber is down when a message is published, it will not miss the message. It will be reliably delivered once the subscriber is up. _Important difference_: are subscribers independent subscribers (all should get event) or are they scaled out instances of the same logical subscriber (any one, but only one, should get the event)? NServiceBus will pick one instance to send the published message to. If you're doing something like invalidating a cache at multiple web frontends (therefore, all would have to get the event to invalidate their cache), don't use pub/sub! It's a distributed cache--so, use a distributed cache instead of individual caches on each web server. That is, use the technology that already solves the problem for you. **Exceptions**
|
||||
We assign too much emergency to exceptions being thrown. We need to change our mindset to allow transient error states in our systems that the system can recover from. Do we need to catch every exception and throw our own custom exceptions and log our own custom messages? Or can we just allow the exception to happen, allow the messaging to retry and only panic when message end up in the error queue. _Should we really check dependency-injected objects for null?_ Our system will fail consistently if we have it misconfigured to not inject dependencies. The error queue is your true source of problems--not exceptions. Once something has failed after retries, it truly is a problem. **Summary**
|
||||
You can get into a case where instead of one, monolithic ball of mud, you have 700 tiny balls of mud that send thousands of messages and subscribe and publish and you have no idea what's going on. This is where boundaries come in and are important!
|
||||
@@ -0,0 +1,46 @@
|
||||
Architectural style: what is and isn't allowed in an architecture. There doesn't have to be ONLY one in a system. For example, we mix MVC and layering. If we use layering, that doesn't mean every piece of code we write has to fit into _this_ style. When thinking about architecture, think about them as ingredients to a meal. Service Oriented Architecture is an architectural style. SOA is likely to be founded on messaging. Architecture is what architects do. Architects are those who do architecture. :-) **Bus & Broker Commonalities**
|
||||
Attempt to handle spatial coupling (but in very different ways). **Broker Architectural Style**
|
||||
Also known as hub and spoke. Another name: mediator pattern. Lots of apps talk to the broker. The broker mediates communication between the applications. Broker was introduced to save the integration between a large number of applications to all the other applications. Instead, all applications integrate with the broker and the broker figures it out from there. Problem: the more things you integrate, the more complex and loaded the broker becomes. The need for scaling presents itself. Examples:
|
||||
|
||||
- Biztalk
|
||||
- Websphere
|
||||
- MS SQL Service Broker
|
||||
- CORBA
|
||||
- UDDI (concept was service discovery)
|
||||
Challenges
|
||||
Not really tech itself, but what it was used for. Broker becomes bloated as number of integrating apps increases. Advantages
|
||||
Generic engine to use to communicate between applications.
|
||||
Central management of communication. IT can look at what's going on. Disadvantages
|
||||
Embodies 11th fallacy: business logic can and should be centralized SOA was a reaction to the problems caused by highly-centralized business logic (brokers). Brokers work well for a relatively small number of integrations. **Bus Architectural Style**
|
||||
Very simple, older style thank broker. Sources produce events, they go to sinks. That's it. Baseline assumption was that the things outside the bus were going to change. The assumption of the broker was that things outside the broker would _not_ change. PCI bus and ethernet are bus architectural styles. Internet was built around this. Smart endpoints, dumb pipes. This allows the endpoints to change a lot. This was all hardware implementations of bus topology. Software buses try to do the same thing.
|
||||
|
||||
- Everything on the bus needs a name
|
||||
- Just like an ethernet card, every component on the bus needs a bus
|
||||
Some new ESB products that are actually brokers: WebSphere, Mule, Sonic Software Bus techs: NServiceBus, MassTransit, Rhino Service Bus
|
||||
Tibco Rendezvous, RabbitMQ, Qpid JGW's bus setup is hub-and-spoke in physical topology, but logically still a bus (dumb pipes, no single point of failure). RabbitMQ and ZeroMQ were created trying to solve the problem of quick message transfer rather than super-reliable message transfer. Their motivation is speed over reliability. Difficulty: much more difficult to design distributed solutions than centralized ones. When researching technologies, make sure to discover the reason they were created and the space out of which they came and which problem they were trying to solve (or even which aspect of which problem they were trying to solve). **SOA Building Blocks**
|
||||
Tenets of Service Orientation:
|
||||
|
||||
1. Services are autonomous (single responsibility--high cohesion)
|
||||
2. Services have explicit boundaries (low coupling)
|
||||
3. Services share contract & schema, not class or type (platform coupling)
|
||||
4. Service interaction is controlled by policy (runtime elements to get things to talk to each other)
|
||||
Those who came up with these were not coming up with something new. They were looking back at old stuff and seeing what worked. What is a service?
|
||||
A technical authority for a specific business capability. Nothing is "left over" after identifying services. You can't say "the UI is over here and talks _to_ the services". The UI code (in this case) was written for a reason to serve some business process and therefore should below in one of the services. Everything must be in some service. What is NOT a service:
|
||||
|
||||
- A service that only contains functionality: this is a function!
|
||||
- A service that has only data is a database, not a service. (CRUD stuff). If all you have is a CRUD service, all you've done is create a proxy for a database.
|
||||
This was the message of object-oriented programming: encapsulation. SOA takes it to the next level: encapsulate business domains. If you want your services, keep them in separate code repositories. It's hard to cross those boundaries and that's good. Client platforms are not out-of-scope for services. Therefore, UI components can belong to services. When we say that a service is the authority for a particular business capability, this may span several systems. SERVICES ARE NOT SYSTEMS. UI composition allows you to put service-oriented components in different services. A pricing component could come from the marketing service and the order component could come from the sales service. SOA aims to divide up business responsibility to make it easy to add business features later one without changing a lot in the existing systems. You don't always want to model the way the business currently operates. There is usually a lot of overlap and disagreement on what requirements are. **Homework:**
|
||||
Example problem domain: hotel management system.
|
||||
Marriott in Dallas. A single hotel.
|
||||
Functionality to book a room.
|
||||
Search screen: check-in, check-out boxes. _Frontend experience_
|
||||
Use case #1: availability by in/out dates. What is the price? Can be multiple types of rooms. If multiple room types are available, show all and their prices. don't look for complexity around pricing--just assume list price. Use case #2: Making a reservation. Guest information (first, last, etc), credit card information for securing reservation. User clicks book now. One guest, one room, one reservation. _Hotel experience_
|
||||
Use case #3: check-in process. Finding reservation based on guest's name (what type of room, how many nights). Next, finding room to put guest in. Use case #4: check-out process. Simple for guest. From hotel's perspective: this is last night of reservation, print up bill on that night. Verify you've left the room. Total charge (finalizing the charges)--did you trash room? Did you eat minibar food? Ultimately, charging card for appropriate total? Edge cases to think about:
|
||||
|
||||
- Guest side: One room left, two people are trying to book it? How to preserve consistency? Overbooking is OK, but infinite overbooking is not allowed!
|
||||
- Hotel side: No show. Reservation made, but guest didn't show up. Probably a guest period.
|
||||
Objective: find service boundaries. What are the services? What data are they responsible for? What parts of the UI are they responsible for? What events do they publish? What events to they subscribe to? What do they do with the events? How do they collaborate with each other to implement the flows discussed? Hints:
|
||||
|
||||
- Be careful with naming services
|
||||
- Consider using stand-in names for services (red, blue, green--colors), then name them at the end.
|
||||
WHEN DOING DESIGN, DEFER NAMING AS LONG AS POSSIBLE!
|
||||
@@ -0,0 +1,16 @@
|
||||
**Reporting**
|
||||
|
||||
**Category #1: wants to apply filter to data**
|
||||
Turn numbers that business users are looking for in reports into domain events. "I want all orders over $1000". When we ask why, the answer is that such an order is a risky order. We now have a domain concept. We can now emit events that say something like "I've accepted a risky order". **Category #2: "what do you want", "I don't know"**
|
||||
Ultimately, all you can do is deliver data to this kind of user. You can't automate it. This user's job (he's really a researcher) is to do the un-automatable. _For which kind of situation is SOA problematic?_
|
||||
|
||||
- For startups and/or young companies.
|
||||
-
|
||||
- SOA is around stable business practices
|
||||
- Young startups don't have the stable business practices you need.
|
||||
- Everything is volatile--impossible to find service boundaries
|
||||
- SOA is about optimizing for certain known constraints
|
||||
- Building a "platform"
|
||||
-
|
||||
- The idea is that you can use this platform for anything
|
||||
- SOA, again, is dependent on established, known business practices which don't exist for a "generic" platform
|
||||
@@ -0,0 +1,17 @@
|
||||
Indications that you need to sub-divide a service into components:
|
||||
|
||||
- Quality of service requirements
|
||||
-
|
||||
- are there large variations in response times
|
||||
- ...in transaction processing times
|
||||
- The business might treat categories of customer differently
|
||||
- We should actually sub-divide our sales service into RegularCustomers component and StrategicCustomers component
|
||||
- These things can start to show up when the business starts asking you to treat something (like a customer) in little different ways throughout the system. You end up with a bunch of if statements asking the same question.
|
||||
-
|
||||
- Ask the business if this is really a new business component
|
||||
- Fork the code base and let them grow apart. This is liberating as you don't have to maintain both component requirements in one code base.
|
||||
- More examples
|
||||
-
|
||||
- Airlines - business vs economy class
|
||||
- Shipping - frozen goods vs regular toilet paper
|
||||
- Billing - charging credit cards vs invoicing
|
||||
@@ -0,0 +1,6 @@
|
||||
=> IT to business interaction There is no "the business". If you ask for "the business" there is no one person to come tell you everything. In most case, when the business comes to you, they are really wanting a work-around. "Add this column to this report". "Allow me to sort by this". These are not requirements, they are work-arounds. For the most part, you don't want to be building work-arounds. You need a product owner, requirements engineer or whatever who the business will listen to and can push back. Helpful in this phase is to do rapid prototyping. Well-formed estimates include a degree of confidence that the project will be done between a T1 and T2 time period. This assumes:
|
||||
|
||||
- Formed team (already worked together)
|
||||
- Team familiar with tech
|
||||
- Team not working on anything else
|
||||
Developers are familiar with the concept of being in the "flow" where we're at our most productive, most concentrated. We need to know our high-energy periods and not waste them. After 2-3 hours of this, however, we need a break, we run out of energy. During the down times, we can work on rapid prototyping work, project planning, etc.
|
||||
@@ -0,0 +1,12 @@
|
||||
You have two types of components:
|
||||
|
||||
1. Business components
|
||||
2. Autonomous components
|
||||
While you should probably only have 1 or 2 BCs in a service, you will have many more ACs. The number of ACs you have will be proportional to the number of systems your service participates in. An AC is responsible for one or more message type. Its message handlers could be real (server-side) message handlers on the bus, or could be javascript event message handlers--or, whatever else. Multiple ACs can be hosted together.
|
||||
|
||||
- Don't try to reuse code between ACs.
|
||||
- Strive for "disposable" code
|
||||
- Solve for today's problem - not tomorrow's (JFHCI = just frickin' hard code it)
|
||||
**Shades of Physical Autonomy**
|
||||
We can have everything deployed into one shared space. We can put parts of a performance-sensitive AC to their own environments. Or, we could just deploy the entire AC to it's own location. SOA = business value. ACs help us to deploy separately, so that we can deploy high-value components out from their current location to another where it will perform better. **Summary**
|
||||
The runtime environment is not made up of services. Services are logical organizational constructs. ACs are the deployment components. Commands are sent within service boundaries. One AC in one service would not send a message to an AC in another service.
|
||||
90
Work/Training/Advanced Distributed Systems/Homework 1.md
Normal file
90
Work/Training/Advanced Distributed Systems/Homework 1.md
Normal file
@@ -0,0 +1,90 @@
|
||||
**Use case #1: get available rooms**
|
||||
Data
|
||||
|
||||
- Room
|
||||
-
|
||||
- Type
|
||||
- Price
|
||||
- Description
|
||||
- Name
|
||||
- Pictures
|
||||
- Check-in date
|
||||
- Check-out date
|
||||
|
||||
Actions
|
||||
|
||||
- get room description (type, picture, etc)
|
||||
- get available room list
|
||||
**Use case #2: making a reservation**
|
||||
Data
|
||||
|
||||
- Guest
|
||||
-
|
||||
- First name
|
||||
- last name
|
||||
- Payment information
|
||||
-
|
||||
- card number
|
||||
- expiration date
|
||||
- name on card
|
||||
- check-in date
|
||||
- check-out date
|
||||
- room ID
|
||||
|
||||
Actions
|
||||
|
||||
- room still available?
|
||||
- reserve room for guest
|
||||
- validate payment information
|
||||
**Use case #3: check-in process**
|
||||
Data
|
||||
|
||||
- Guest
|
||||
-
|
||||
- First name
|
||||
- Last name
|
||||
- Payment information
|
||||
-
|
||||
- number
|
||||
- expiration date
|
||||
- name
|
||||
- room
|
||||
-
|
||||
- number
|
||||
- type
|
||||
|
||||
Actions
|
||||
|
||||
- Find reservation by guest name
|
||||
- Find reservations by today's date
|
||||
- realize reservation
|
||||
**Use case #4: check-out process**
|
||||
Data
|
||||
|
||||
- Guest
|
||||
-
|
||||
- GuestId
|
||||
- Room
|
||||
-
|
||||
- RoomId
|
||||
- Reservation
|
||||
-
|
||||
- ReservationId
|
||||
- Check out Date
|
||||
|
||||
**Homework:**
|
||||
Example problem domain: hotel management system.
|
||||
Marriott in Dallas. A single hotel.
|
||||
Functionality to book a room.
|
||||
Search screen: check-in, check-out boxes. _Frontend experience_
|
||||
Use case #1: availability by in/out dates. What is the price? Can be multiple types of rooms. If multiple room types are available, show all and their prices. don't look for complexity around pricing--just assume list price. Use case #2: Making a reservation. Guest information (first, last, etc), credit card information for securing reservation. User clicks book now. One guest, one room, one reservation. _Hotel experience_
|
||||
Use case #3: check-in process. Finding reservation based on guest's name (what type of room, how many nights). Next, finding room to put guest in. Use case #4: check-out process. Simple for guest. From hotel's perspective: this is last night of reservation, print up bill on that night. Verify you've left the room. Total charge (finalizing the charges)--did you trash room? Did you eat minibar food? Ultimately, charging card for appropriate total? Edge cases to think about:
|
||||
|
||||
- Guest side: One room left, two people are trying to book it? How to preserve consistency? Overbooking is OK, but infinite overbooking is not allowed!
|
||||
- Hotel side: No show. Reservation made, but guest didn't show up. Probably a grace period.
|
||||
Objective: find service boundaries. What are the services? What data are they responsible for? What parts of the UI are they responsible for? What events do they publish? What events to they subscribe to? What do they do with the events? How do they collaborate with each other to implement the flows discussed? Hints:
|
||||
|
||||
- Be careful with naming services
|
||||
- Consider using stand-in names for services (red, blue, green--colors), then name them at the end.
|
||||
|
||||
WHEN DOING DESIGN, DEFER NAMING AS LONG AS POSSIBLE!
|
||||
Reference in New Issue
Block a user