Saturday, March 5, 2022

Leetcode algorithms: Good ideas to learn from Raymond Gan

Good ideas:

1. Jr engineers: I've begun to code ALL 152 LeetCode "Top Classic Interview Questions" in JavaScript: 48 Easy, 52 Medium, + 52 Hard #datastructures + algorithm questions: https://lnkd.in/gCpZVmiK. I hope to post answers to new problems daily on LinkedIn + my GitHub: https://lnkd.in/g-V76cd. Many top companies (like FAANG) ask #leetcode questions in software job interviews.

Buy LeetCode: https://lnkd.in/g2QuZtrh

I posted answers to these 4 "easy" problems:

- Valid Anagram: https://lnkd.in/g7Zz2bmT
- Reverse Linked List: https://lnkd.in/gS3zZncz
- Remove Duplicates From Sorted Array: https://lnkd.in/g9wCpxa4
- Best Time to Buy + Sell Stock 2: https://lnkd.in/gpia8jxZ

Why? 8 years since finishing my coding bootcamp, I've met hundreds of bootcamp grads very WEAK in Data Structures + Algorithms (DS&A). They often fail LeetCode type software interviews + are scared, frustrated, + clueless on how to teach themselves this difficult skill. Failing #algorithms questions is often the #1 thing that gets them rejected! They struggle alone.

Most bootcamps do a horrible job teaching DS&A, rushing through a zillion topics with no depth. I see new grads who can't do basic things like write a class, object, loop, or function in their main computer language!

Last week, I wrote of a Trilogy Education grad who couldn't do basic JavaScript, OOP, or write a linked list: https://lnkd.in/gcB9-Z7P

Today I worked with a Lambda School grad who didn't know how to write a loop, if statement, or use a dictionary (or hash) in Python.

I want to SHOW you, by solving 150+ LeetCode problems, to do DS&A in depth. I'll start each problem WITHOUT looking at other answers first. I'll time how long it takes me to finish, since speed matters in tech interviews.

In each problem on GitHub, you'll see:

1. My full code answer, sometimes with comments + screen outputs for more depth.

2. Often I do a problem 2-3 times. I may post my rough draft answer, then my final better answer, so you see how I improved it.

3. How long it took me to do it. I may take 1 hour to do it from scratch, then code it again 2 more times for speed, cutting my time to 1.5 minutes. I may post both my original (slow) time + my fast time.

4. My answers' Big O time + space complexity.

5. Which top 3 companies (on LeetCode) ask each question. This often means Google, Facebook, Amazon, Microsoft, etc.

I use the hashtag #raymond_dsa for all my LeetCode + DS&A posts. Follow it. I'll number each post.

Post your LeetCode answers on GitHub + in my comments. Let's all learn, teach each other, + help us get great new software jobs! ❤️

Plan to work on Leetcode algorithms

March 5, 2022

Introduction

I like to get back to work on Leetcode algorithms in next three weeks, so that I can learn something from my own experience. I like to experience a lot of failures, and then figure out how to advance my skills in terms of problem solving. I will figure out better ideas later on. 

Algorithm to plan to work on

I chose to work on Leetcode with tag Facebook, last six month most frequent algorithms.

  1. Algorithm 314, 1762, 1570, 1650, 528, 408, 339, 71, 31, 670;
  2. 10 more: 498, 162, 523, 282, 1891, 1011, 708, 1382, 1539, 2060;
  3. 10 more: 266, 286, 1868, 1216, 348, 778, 536, 270, 1428, 825;
  4. 10 more: 269, 658, 16, 2056, 43, 1060, 380, 1344, 1522, 1944;
  5. 10 more: 1644, 2076, 689, 1424, 983, 224, 298, 742, 767, 333;
  6. 10 more: 2019, 2033, 238, 1541, 1209, 2071, 296, 1244, 2065, 2081;
  7. 10 more: 406, 271, 1498, 735, 163, 1245, 1559, 247, 2025, 1197;
  8. 723, 2092, 62, 540, 1985    

work hard | Hard work beats talent 

Do not think too much. Just work on more algorithms. Solve as many algorithms as I can. Once I solve another 20 algorithms, stop and review what I have learned, and then continue to solve another 20 algorithms. 

March 7, 2022

Four algorithms, 1640, 528, 408

Here are discussion posts. 

Plan to work on those three tree algorithms first: Leetcode 333, 742, 767. 


Friday, March 4, 2022

My experience finding renters remotely in Florida

 March 4, 2022

Introduction

It is a tough project to find renters for my rental property in Florida. How do I make plans and then find renters? What technologies do I use? How do I evaluate Zillow.com posting? How do I evaluate wechat app to find renters as well?

Will continue

I will add more later. Stay tuned. 


Thursday, March 3, 2022

Boca Raton, Florida rental home

March 10, 2022

I like to post pictures to share with Zillow.com applicant. My rental property is in Boca Raton, Florida, address: 260 nw 19th st, Boca Raton, FL 33432

Here is the link.

Here is Google drive's link. 

 

Pamela 18:11

Pamela 18:11

Pamela 18:11

Pamela 18:11

Pamela 18:11

Pamela 18:11

Pamela 18:11

Pamela 18:11

Pamela 18:11

Pamela 18:12

Wednesday, March 2, 2022

Section 8 (housing)

 

Section 8 (housing)

From Wikipedia, the free encyclopedia
Jump to navigationJump to search

Section 8 of the Housing Act of 1937 (42 U.S.C. § 1437f), often called Section 8, as repeatedly amended, authorizes the payment of rental housing assistance to private landlords on behalf of low-income households in the United States. Fort Lauderdale, Florida Housing Authority Director William H. Lindsey, upon the advice of Housing Authority attorney J. Richard Smith, initially developed 11(b) financing in the early 1970s to accommodate a local savings and loan interested in assisting with urban renewal projects Lindsey eventually brought to fruition[citation needed] . This was the initial impetus for the subsequent development of the now well known Section 8 Program[citation needed]. Of the 5.2 million American Households that received rental assistance in 2018, approximately 2.2 million of those households received a Section 8 Housing Choice Voucher. [1] 68% of total rental assistance in the United States goes to seniors, children, and those with disabilities.[1] The U.S. Department of Housing and Urban Development manages Section 8 programs.[2]

Book reading: Rush to read Microservice architecture Book

Page 129 | Countermeasure: Semantic lock  

COUNTERMEASURE: SEMANTIC LOCK

When using the semantic lock countermeasure, a saga’s compensatable transaction sets a flag in any record that it creates or updates. The flag indicates that the record isn’t committed and could potentially change. The flag can either be a lock that prevents other transactions from accessing the record or a warning that indicates that other transactions should treat that record with suspicion. It’s cleared by either a retriable transaction—saga is completing successfully—or by a compensating transaction: the saga is rolling back.

The Order.state field is a great example of a semantic lock. The *_PENDING states, such as APPROVAL_PENDING and REVISION_PENDING, implement a semantic lock. They tell other sagas that access an Order that a saga is in the process of updating the Order. For instance, the first step of the Create Order Saga, which is a compensatable transaction, creates an Order in an APPROVAL_PENDING state. The final step of the Create Order Saga, which is a retriable transaction, changes the field to APPROVED. A compensating transaction changes the field to REJECTED.

Managing the lock is only half the problem. You also need to decide on a case-by-case basis how a saga should deal with a record that has been locked. Consider, for example, the cancelOrder() system command. A client might invoke this operation to cancel an Order that’s in the APPROVAL_PENDING state.

There are a few different ways to handle this scenario. One option is for the cancel-Order() system command to fail and tell the client to try again later. The main benefit of this approach is that it’s simple to implement. The drawback, however, is that it makes the client more complex because it has to implement retry logic.

Another option is for cancelOrder() to block until the lock is released. A benefit of using semantic locks is that they essentially recreate the isolation provided by ACID transactions. Sagas that update the same record are serialized, which significantly reduces the programming effort. Another benefit is that they remove the burden of retries from the client. The drawback is that the application must manage locks. It must also implement a deadlock detection algorithm that performs a rollback of a saga to break a deadlock and re-execute it.


Commutative updates - design update operations to be executable in any order | Commutative updates

March 2, 2022

Here is the article. 

WHAT IS COMMUTATIVITY AND WHY IS IT SO USEFUL IN DISTRIBUTED SYSTEMS?

Commutativity is an algebraic property that means that order doesn’t matter. Because network messages arrive out of order, it’s the perfect property for distributed systems. In this episode, you’ll learn what it is (with some real world examples), why it’s useful, and 3 ways you can make an existing operation commutative.

TRANSCRIPT

Eric Normand: What is commutativity and why is commutativity so useful in distributed systems? By the end of this episode, you will have three ways to use commutativity to make your distributed systems more reliable, faster and easier to scale. My name is Eric Normand, and I help people thrive with functional programming.

Commutativity is important for a number of reasons. You could say, “Eric, you’re getting all math-theta on me again, I don’t want to go back to algebra class. Why commutativity?” Well, listen, commutativity is just a name that mathematicians have made up.

I’m sorry if you had a bad experience in math class. Commutativity is super important for distributed systems. When you have distributed systems, one of the most costly, expensive things you can do between those nodes and the system is to communicate, so that you can coordinate.

You don’t want to be waiting for each other. You don’t want to be waiting for messages to travel across the network. The whole point is that you can work independently. If you didn’t want to work independently, you’d be on the same machine.

We want to reduce the interdependence of the ordering of our operations. We want to make it so that the order the work gets done in doesn’t matter. That’s what commutativity is.

Let’s go over the what. Commutativity is an algebraic property of certain operations. By extension, we can say it’s also a property of certain actions, certain effects. Not just mathematical functions, but also effects on the world.

You can do them in different orders and get the same result.

What it means is that order doesn’t matter. In some things, the order does matter. If you’re making a sandwich, the order matters. You got to start with the bread, then put something on the bread, and then put something else on.

If you did it in a different order, you’ll get a different sandwich. It might fall apart. Might not even be a sandwich anymore. If you put the meat on the outside, it wouldn’t be a sandwich.

In some operations, the order doesn’t matter. That’s very nice. One example that we use all the time is adding stuff to a set. If you’ve got a set data structure in your language and you start adding things to it, it doesn’t matter what order you put them in. If you have a set of numbers and you put one, two, three, or three, two, one, it doesn’t matter.

The data structure is effectively the same. They might be stored differently in memory, but the semantics of the data structure are such that in a set, the order doesn’t matter. When you’re comparing to, it doesn’t look at the order of when they were added.

That’s a nice thing. It means that I can use a set and guarantee that it doesn’t matter what order. It means that different threads can be adding to the same set at the same time. It doesn’t matter how the threads are interleaved, if one is slower than the other, if one thread skips some numbers, and decides to do it in a different order from what you gave it. It doesn’t matter. They’re free to work in an uncoordinated fashion, which is very nice for distributed systems.

Why is this so nice? Once you’re on a network, the order of messages between nodes is just not guaranteed. If I make two requests to a web server, I cannot guarantee which one will arrive first, and I cannot guarantee which one will send its response back first. There’s so many things going on between my computer and the other computer, that there’s no way to guarantee that ordering.

Especially, if there’s a lot of processing that you have to do. If the other computer is going to do a little bit of computation, sometimes, computation takes longer than another time. There’s no way to do it. When you have two computers that are working together to work on a bigger job, so that each have a sub-job to do, you don’t know which sub-job is going to happen first, is going to finish first. You want to make sure that you can work out of order. It just helps things.

Order is actually something that we have to think about a lot in distributed systems. I’m going to give you three things that you can do to, hopefully, eliminate the stranglehold that order has on your system. If you want to get the right answer, you want to make it so that you get the same answer, regardless of the order that stuff happens in.

Number one. If you want to make something commutative, you can easily do that by using an existing data structure that has a commutative operation. We already talked about sets. Adding stuff to sets is commutative.

Here’s an example — if I want to count the number of people at the conference. They’re already there. They’re already in the conference. There’s different rooms that they’re in. They’re listening to different speakers. They’re moving around between rooms.

It takes a while to count them. By the time you’re counting them and you get to a person, he might have left and gone to another room. Sometimes, you’ve counted someone — I’ve counted the same person as you counted. We’re in different rooms.

People are moving around. You might count the same person twice. If what I do instead of just counting the number of people I see in the room, I scan their badges. I just remember every badge ID that I’ve seen, and you do the same. You’re remembering every badge ID.

Then we have a list of badge IDs that we’ve seen. Then we dump them all into a set. It doesn’t matter what order the people were counted or anything like that. All of that goes away. We know how many people were there because we can just count the number of elements in that set.

You could also have a central set that everyone is writing to. We can write to it in an uncoordinated manner. You write to the set. I write to the set. We don’t talk to each other. You can see a real-time count as people come in. If people are counted twice, it doesn’t matter, and the order doesn’t matter even.

That one actually, now that I think about this example, it also confuses idempotence because you’re not counting the same person twice. Just know that the order doesn’t matter. The final set is going to be the same, no matter what order people are counted in. That’s what’s important.

There are other commutative operations on data structures that you’ve got. If you are working with numbers, obviously, addition and multiplication are going to be commutative. It doesn’t matter what order you multiply your numbers in. You can pick the order that makes the most sense.

If you’re counting page hits on your website, you’re just adding one. That’s a commutative operation. You can do that in a distributed manner. My web server and your web server were load balanced behind the same load balancer. I can count web hits. You can count web hits to the same central server in whatever order. It doesn’t matter. That’s nice.

Another thing, and I hinted at this in the example. Number two is another way to add commutativity is to think about identity. Do I identify some kind of identity for your operations?

In this case, the identity was the badge ID. The badge ID was saying…That’s also for idempotence. It’s allowing you to count people and not worry about the order because the ID is separating people. It’s not like I say plus, you say plus one. That’s really confusing it with idempotence. These properties are often used in combination.

Another kind of identity is the index. Let’s say you do have some order imposed. For instance, I’m sending you packets on TCP packets of a file, they have to go in the right order. I can’t guarantee that they will arrive in the right order.

There’s going to be some packets dropped. I’m going to have to retry and so the order is just totally messed up. How do you get them back in order? How do you make it so that the order doesn’t matter when it really does?

Well, each packet is numbered. Each packet has its order as part of the payload, so you on the other side can reassemble them in the correct order. It doesn’t matter what order they arrived in, you can always reorder them to the correct order later. That’s another useful thing.

This is called an index because it’s like you have an array and you say, “Well, there’s zero chunk of work in the first, and the one chunk of work, the two chunk of work, they go into this array. I’m going to send them out, they’re going to come back in different orders, but I know where the answer is, go. Then I can tell when I’m done, and then I’ll have them in the right order.

Another thing is you could capture the time. If you have, say events where this user’s clicking buttons and that user’s clicking buttons, and they’re going to arrive at different times on the server. If you capture when they happened on the individual machines, you can reassemble a timeline of the actual order they occurred in.

That’s hard when you’ve got time on a distributed-system. I’m not going to go into that. You can fudge time if you need to, and that can give you a consistent way of reordering them when you need to.

The third thing is to think about partitions, are also known as sharding. If you have a bank, the bank’s operations depend on order a little bit, but you know that my account and your account are completely independent. We don’t have to focus on, if you have a check get withdrawn, I have a check get withdrawn.

It doesn’t matter if you withdraw mine first or you withdraw yours first from your account or from mine. It doesn’t matter because they’re totally independent. We only have a smaller problem to deal with, which is ordering the checks from my account and ordering the checks from your account.

They’re totally independent unless we do a transfer between us but please don’t take my money. Usually most bank accounts are not transferring money between the others all the time, so you can partition them.

We do this a lot with, say user accounts on online services. The users largely are not. The operation for a single user, do not affect the other users. My account is totally partitioned from your account, and so with that, “Lets us do,” is not worry about the order between the different users, we just have to worry about the order for one user.

That is much simplified because if it’s one user, it’s usually one person. They have one tab open at a time, and so the problem is much more tractable.

On the other hand, if you actually look at the traffic, the web server is getting thousands of web requests a minute in random order. You can have peace of mind that as long as you know what user account that that web request is for, you can figure out that there’s not that many per user coming in at the same time.

Let me give you some examples of existing commutative operations that you’d be familiar with. I talked about adding to a set. I talked about addition and multiplication of numbers. You also have AND and OR on bullions. These are commutative, which is a really nice thing to have.

There’s a commutativity that I call conditional commutativity, which is where you have, let’s say you have two hash maps, typically merge depends on the order. The order does matter. What is going to merge over what, because you might have the same key with different values. If you have the same key with different values, the one on the right is going to merge over the one on the left.

However, if you know that there’s no keys in common, because typically when we’re using hash maps, we do know the keys. When we’re treating it like an entity, we do know the keys. If we know that there’s no keys in common, then it is a commutative operation. You’re going to get the same answer with, A merged with B and B merged with A.

There’s that notion of conditional commutativity, and so I’d also like you to think about whether your operation can have some condition on it that you can satisfy. There’s also this idea of commutativity on effects. Can be like, let’s say I’m sending emails to customers. I’m sending, I don’t know what it is, like a yearly newsletter to every customer.

I’m just sending one newsletter to each email address I have on a list, does it matter what order they get sent out in? The effect is that they’re all going to wind up in the user’s inbox, or their spam box, or whatever. It doesn’t matter because they’re not going to call each other up like, “Did you get that at 6:01 or 6:02? Was mine first?” They don’t care.

Effectively, they do get sent out in some order, but it doesn’t matter, the effect is the same. That’s different from if you send the same person two different emails. Then the order does matter. The mail server is going to, or the mail client is going to show them in a particular order.

Maybe it wouldn’t make sense. The first email they get is like the second one, so it’s going to say, “Hey, I just sent you this thing. Did you get it?”

Then a minute later, they get one that’s like, “Hey, this is the first email.” It doesn’t make sense. The order does matter for an individual person but not across people. It’s nice to think about stuff like this this way. Let me recap real quick.

Distributed systems like commutativity because it lets things work in an uncoordinated fashion, just sending answers as soon as they have them. They can be combined out of order and you’re going to get the right answer. That’s awesome.

It’s really about independence. It’s this essence of independence. It’s decoupling the answer from the order that you got the sub-answers in. It means order doesn’t matter. It’s an algebraic property. Talked about that.

The how. One, use existing commutative operations on existing data structures. Two, think about order, bundling the order, an identity, or a time with the question and with the answers, so that they can be reordered on the other side. That’s helpful. This is how TCP works.

Also, think about partitioning, so that you can independently evaluate the order, like in the case of user accounts where users aren’t affecting each other, so the order that the operations happen between users doesn’t matter. Makes it much easier to reason about.

I gave some examples. I think that it would be good for you — for yourself — if you found some existing operations. You can use the ones I listed, find some others and play with them. Test them out, like at a rappel or in a little test program.

Think about how these work, and how they achieve commutativity. If you want to go further, you can look at stuff that you need to be distributed and see how you can make the order not matter.

If you can make the order not matter, you often can eliminate a lot of coordination code. Make your system more scalable, more performant, etc. If you found this episode useful, I would very much appreciate if you shared it with other people. They could find it useful too.

You could get a little bit of…a couple of good karma points from them, for that. Like, Comment, do what you do in your app. Also, subscribe, because if you found this one useful, the next episode is going to be similarly useful. You’ll be notified and you’ll have it on your device when it comes down the pipe.

If you’d like to ask any questions or get in touch with me, suggest another topic, you can email me eric@lispcast.com. I’m also available on Twitter @ericnormand with a D. You can find me on LinkedIn if that’s what you use, and we can connect there. Awesome. See you later.

ERIC NORMAND

Eric Normand is an experienced functional programmer, trainer, speaker, writer, and consultant on all things FP. He started writing Lisp in 2000 and is now a Clojure expert, producing the most comprehensive suite of Clojure training material at PurelyFunctional.tv. He has a popular Clojure newsletter and blog. He also consults with companies to use functional programming to better serve business objectives. You can find him speaking internationally at programming conferences.

Semantic lock - an application-level lock | PENDING state - Order example

 

What is the semantic lock counter-measure?

You might be wondering why createOrder() creates the order in a PENDING state, which is then changed to APPROVED by approveOrder(). The use of a PENDING state is an example of what is known as a semantic lock counter-measure. It prevents another transaction/saga from updating the Order while it is in the process of being created.

The article I read by Google search: 

Managing data consistency in a microservice architecture using Sagas - part 1

This is the first in a series of posts that expands on my recent MicroCPH talk on Managing data consistency in a microservice architecture using Sagas (slides, video).

The other posts in this series are:

Why sagas?

A distinctive characteristic of the microservice architecture is that in order to ensure loose coupling each service’s data is private. Unlike in a monolithic application, you no longer have a single database that any module of the application can update. As a result, one of the key challenges that you will face is maintaining data consistency across services.

Consider, for example, the customers and orders example application from my presentation. It consists of two services:

  • Order Service
    • Manages orders
    • Operations include createOrder() and cancelOrder()
  • Customer Service
    • Manages customer information including the customer’s available credit
    • Operations include createCustomer()

When the Order Service creates an Order it must ensure that there is sufficient credit available. Specifically, the createOrder() command must update data in both the Order Service and the Customer Service.

In a traditional application, you might consider using distributed transactions a.k.a. two phase commit (2PC). However, using 2PC is generally a bad idea a microservice architecture. It’s a form of synchronous communication that results in runtime coupling that significantly impacts the availability of an application.

What is a saga?

The solution is to implement commands, such as createOrder(), using a saga. A saga is a sequence of local transactions in each of the participating services. For example, here is the definition of the Create Order Saga, which is initiated by the createOrder() command:

StepParticipantTransactionCompensating Transaction
1Order ServicecreatePendingOrder()rejectOrder()
2Customer ServicereserveCredit()-
3Order ServiceapproveOrder()-

The purpose of each step is as follows:

  • createPendingOrder() - create the Order in a PENDING state
  • reserveCredit() - attempt to reserve credit
  • approveOrder() - change the state of the Order to APPROVED
  • rejectOrder() - change the state of the Order to REJECTED

The sequence for the happy path is as follows:

  1. Order Service : createPendingOrder()
  2. Customer Service : reserveCredit()
  3. Order Service : approveOrder()

The sequence for the path when there is insufficient credit is as follows:

  1. Order Service : createPendingOrder()
  2. Customer Service : reserveCredit()
  3. Order Service : rejectOrder()

What are compensating transactions?

The rejectOrder() command is an example of a compensating transaction. Unlike ACID transactions, sagas cannot automatically undo changes made by previous steps since those changes are already committed. Instead, you must write compensating transactions that explicitly undo those changes. Each step of a saga that is followed by a step that can fail (for business reasons) must have a corresponding compensating transaction.

In the Create Order Saga, createOrder() has the rejectOrder() compensating transaction because the reserveCredit() step can fail. The reserveCredit() step does not need a compensating transaction because the approveOrder() step cannot fail. And, the approveOrder() step does not need a compensating transaction because it’s the last step of the saga.

What is the semantic lock counter-measure?

You might be wondering why createOrder() creates the order in a PENDING state, which is then changed to APPROVED by approveOrder(). The use of a PENDING state is an example of what is known as a semantic lock counter-measure. It prevents another transaction/saga from updating the Order while it is in the process of being created.

To see why this is necessary consider the following scenario where the cancelOrder() command is invoked while the Order is still being created:

Create Order SagaCancel Order Saga
createOrder() - state=CREATED 
 cancelOrder() - state=CANCELLED
reserveCredit() 
approveObject() - state=APPROVED 

In this scenario, the cancelOrder() command changes the status of the order to CANCELLED, and the approveOrder() command overwrites that change by setting the status to APPROVED. The customer would be quite surprised when the order is delivered!

The PENDING state prevents this problem. The cancelOrder() command will only cancel an Order if its state is APPROVED. If the state is PENDING, cancelOrder() returns an error to the client indicating that it should try again later. The semantic lock counter-measure is a kind of application-level locking. As I describe in the presentation, it’s a way to make sagas, which are inherently ACD, ACID again.

In a later post, I’ll describe how to implement this saga.

To learn more

Book reading: Rush to read | Chris Richardson - Microservices patterns - With example in Java 2018

Page 128 | 4.3.2 Countermeasure for handling the lack of isolation

 

The countermeasures described by this paper are as follows:

 Semantic lock—An application-level lock.

 Commutative updates—Design update operations to be executable in any order.

 Pessimistic view—Reorder the steps of a saga to minimize business risk.

 Reread value—Prevent dirty writes by rereading data to verify that it’s unchanged

before overwriting it.

 Version file—Record the updates to a record so that they can be reordered.

 By value—Use each request’s business risk to dynamically select the concurrency mechanism.

Later in this section, I describe each of these countermeasures, but first I want to introduce some terminology for describing the structure of a saga that’s useful when discussing countermeasures.

Google those terms, and see if I can quickly learn from Google: Semantic lock, Communicative updates, Reread value, version file, by value

  1. Semantic lock - an application-level lock
  2. Communicative updates - design update operations to be executed in any order. 
  3. Pessimistic view - Reorder the steps of a saga to minimize business risk
  4. Reread value - Prevent dirty writes by rereading data to verify that it's unchanged before overwriting it
  5. Version file - Record the updates to a record so that they can be reordered. 
  6. By value - Use each request's business risk to dynamically select the concurrency mechanism.