← All transcripts

Lesson 223 - Approaches for Legacy Migration Transcript, AI Summary & Key Points

Software Architecture Monday · 10 days ago · Education · 11:20 · EN

Watch on YouTube

AI Summary

Legacy migration begins by determining whether modularity is justified and whether the system is feasible to decompose. Distributed architectures provide scalability, responsiveness, and fault tolerance, but add complexity and cost. Low coupling and definable components support component-based decomposition, while highly coupled or unstructured systems may require refactoring, continued monolithic development, a greenfield rewrite, or tactical forking. Component-based decomposition extracts services through controlled refactorings and lets the architecture emerge, whereas tactical forking copies the repository and removes unwanted code to produce predefined services.

Key Points

  • Neil Ford and Mark Richards use a flowchart to evaluate legacy migration approaches.
  • The first question is whether modularity is justified; without a clear justification for breaking apart the system, keeping the monolithic application is preferable.
  • Distributed architectures provide scalability, responsiveness, and fault tolerance, but introduce complexity, cost, and other architecture-dependent drawbacks.
  • Feasibility depends partly on coupling between components. References to classes outside a namespace, package structure, or directory couple components together.
  • Sonargraph, VS Code, and X-ray can show coupling levels between architectural components.
  • Low coupling makes migration more feasible. Heavy coupling may require code refactoring before migration, while an extremely entangled system may be better kept monolithic and replaced with a new greenfield system.
  • Definable components support component-based decomposition; unstructured balls-of-mud systems typically call for tactical forking.
  • Component-based decomposition uses iterative refactorings to identify components and domains, then extracts domains into domain services and potentially microservices.

Tools & resources

2 items

Business ideas

A migration approach that first determines whether modularity and decomposition are justified, then selects a controlled extraction process for systems with definable components or a faster replication-and-pruning process for unstructured systems.

For
Teams responsible for legacy applications that may need scalability, responsiveness, or fault tolerance from a distributed architecture.
Solves
Legacy systems are difficult to migrate because distributed architectures add complexity and cost, while tightly coupled or unstructured code can make decomposition impractical.
  • Sysops squad ticketing system: component-based decomposition identified reporting, ticket assignment, notification, and routing structures, which were grouped into domains and extracted into separately deployed services.
🔒  Build steps and tools for 1 idea. Unlock

Links mentioned

🔒 Full analysis locked

Unlock more videos and the full analysis

A credit unlocks one video's full analysis for good — the build steps, the tools and how each was used, the methods behind every use case. Pro opens the whole library instead, and raises how many videos you can analyse a day.

Unlock full analysis — free

Transcript

Searchable transcript of Lesson 223 - Approaches for Legacy Migration — Software Architecture Monday (11:20). Search for a phrase, then click its timestamp to jump straight to that moment in the video.

Captions sourced from the original video on YouTube, published by Software Architecture Monday. The video, its captions and all related intellectual property remain the property of their respective owners; AINotes claims no ownership. Provided for research, accessibility and search — see the Transcript Notice and Copyright Policy.

00:00 Hello everyone and welcome to software architecture Monday. My name is Mark Richards and in this lesson number 223, I'll talk about a couple of approaches to migrate legacy systems to distributed architectures. Neil Ford and I came up with this flowchart uh for determining what would be the best approach for migrating a legacy system. And I want to go over the flowchart and show you two approaches in this lesson, tactical forking and component-based decomposition.

00:36 The first thing we ask when we tackle a legacy migration is ask is modularity justified. And the point of this is if we cannot justify the reasons why we want to break apart our application or system, then we keep a monolithic application. Distributed architectures are hard and they carry with them a lot of superpowers including things like scalability, responsiveness, fault tolerance.

01:05 However, there's also a lot of well kryptonite I will say and that is in terms of the complexity, the cost and other factors det depending on the particular architecture style. But let's say we can justify it. We need those kind of superpowers. Then we ask, is it even feasible to decompose the existing legacy system? And as a matter of fact, let me show you a couple of criteria you could use on that.

01:35 So, here's some components in our well-known sysops squad uh system uh which is a trouble ticket system. Uh notice I'm creating a class file here to create a ticket. Well, that belongs to this particular component right here. But notice that create ticket invokes ticket assignment which belongs to another component. And when we import that ticket assignment and invoke a method, essentially what we're doing is coupling those architectural components.

02:10 As a matter of fact, anytime we reference a class outside of our namespace or package structure or directory, essentially we're coupling those components together. There's a lot of tools we can use. Sonar graph, as a matter of fact, VS Code, uh, a tool I'll show you which was an older tool because I've got some actual screenshots as a tool called X-ray.

02:32 So these tools show you the coupling level between components not not classes but rather components those building blocks and the lines between those boxes or components are the coupling level. Now this is an actual screenshot of a system I migrated and you can see that it's fairly well independent. There's very little coupling which makes it very feasible to tackle this kind of migration.

03:03 However, most of the time you'll see something that looks like this where there's a lot of coupling areas and we start to question even if it's feasible to break this system apart. In this case, we may have to apply some actual code refactorings before we tackle a migration. However, if your system looks like this, then run away in the opposite direction.

03:30 And this is by the way an actual screenshot of a system that I worked on. So the point is if we end up with something that looks like the coupling analysis that you saw on the last slide uh then keep it a monolithic application and just simply rewrite a new green field one. However, if it does look like we can decompose it and there are uh not much coupling levels, we then ask are there definable components that we can actually see.

04:04 Now, a lot of times we may have an unstructured system or a structured. If we have definable components, then we can use something called component-based decomposition. However, for unstructured balls of mud systems, typically we use tactical forking. And both these approaches end up with a distributed application or a distributed system. I want to take the rest of this lesson to briefly show you these two techniques and approaches and the corresponding tradeoffs between them.

04:35 So, let's take a look at component-based decomposition. First, this is a series of refactorings that allow us to then identify through refactorings components and then domains and correspondingly services and extract that code from the legacy system thereby creating a service whether it be a domain service or a micro service. And so it's all about extraction.

05:04 Domain-based decomposition follows uh a series of small iterative controlled refactorings. We start with our monolith. We identify and size our existing components and then we do what's called flattening those components. In other words, we we push all of the code, all of the source code to the leaf nodes in our directory, package structures or namespaces, thereby identifying those components, the building blocks.

05:33 Because when we move code and break apart a legacy system, we don't actually move class files around. We move components around. Grouping those classes into those components is the real key. Then we analyze those dependencies that I showed you to see what we're facing in terms of feasibility. Then we create component domains. We start grouping components into domains and then extract those domains into domain services.

06:00 Finally going to microervices. Our book software architecture the hard parts in chapter five. It's a fairly detailed chapter that covers all of these different refactoring patterns and also how to apply them. Now, let me show you the sysop squad as an example. We start with our monolith. We start identifying components and sizing them. Notice that reporting on the right hand side there is fairly large.

06:31 And we have ticket assign, notify, and route kind of building up these little hills. Well, flattening is about kind of moving everything to the leaf nodes but also resizing some of the larger components. From there, we start creating component domains. We group these components into domains effectively doing domain driven design uh from the bottom up and then we take each of those domains and we extract those into separately deployed services and then we can further decompose them from there.

07:05 So the trade-offs of component-based decomposition, it's fairly low risk. These are controlled refactorings where the new architecture essentially emerges. In other words, we may not know what kind of services. As a matter of fact, usually we don't know what kind of services we're going to end up with. We just keep refactoring the structure of the code, not the actual source code itself, but the structure of the code to have the architecture emerge.

07:32 Well, that sounds great, except it's a relatively slow process and it's not really suitable for unstructured code where you don't have existing components. So, let's take a look now and finish the lesson by looking at tactical forking. This is another approach that teams can use. So we just saw with component-based decomposition effectively we're extracting our services.

08:01 Tactical forking says no we're not going to extract. What we're going to do is replicate code and then just delete what we don't want from it. Essentially with tactical forking we are all acting as sculptors. taking a block of ice, marble or granite and then chipping away at the stuff we don't want so that the stuff we do want ends up emerging. And that's the idea of tactical forking.

08:29 So here's how it works. So we have multiple teams on a system. We fork that application. And when I say fork, I mean actually copying the repository. So each team's working on a copy of that repository or team A could be working on the original one and then each team works as a sculptor to start stripping away the parts they don't want finally ending up with the appropriate services.

08:58 Let's see this in action with the SISOP squad ticketing system. So we have our existing system. What we do is we take that repository and we copy it. As a matter of fact, I'm going to make two copies. Now, we have to sculpt something. We have to start chipping away at code we don't want, which means we have to know what those end result services are.

09:19 And we see the first difference between component-based and tactical forking. So, I envision we're going to create a reporting, ticketing, and customer service. We have three teams and each team ready set go concurrently starts chipping away at the source code they don't want finally ending up with a reporting service ticketing and a customer service.

09:42 However, one of the negatives of tactical forking is you got all that common code. Uh what do we do with an address class that ticketing needs and customer needs and reporting needs? uh infrastructure things like logging or metrics auditing any of these kind of uh date routines. That's one of the issues with tactical forking because unfortunately it's very difficult to extract that common code once we start forking those systems.

10:16 So the trade-offs we can see here is it's a fast process and really good for unstructured code. However, the bad part of this, the trade-offs is that duplicate shared code across multiple services, which again is very, very hard to reconcile. The results are usually as messy as the existing unstructured system. And so, we're not really gaining anything from a maintainability, testability, deployability, or reliability standpoint.

10:42 And we have to know what services we're sculpting up front unlike component-based decomposition which lets those services emerge. So here's two approaches that you can use for legacy migration and the trade-offs associated with each of those. So anyways, thank you so much for listening. This has been lesson 223, approaches for legacy migration. Stay tuned next month on the first Monday of each month for the next lesson in software architecture Monday.