Transcript
Crispim: We'll be talking about how to evolve your architecture, looking towards the lens of modernization. Modernization is a constant need. I think we can't deny that. While you are doing something here, you might need to start looking at there. That's basically because there are couple drivers behind modernization that includes market demands, competitive pressure, advancements in technology. Here I'm not really talking about like Java 6 to Java 21. I'm talking about things that essentially change how we build or how we use software, mobile applications, cloud computing, and things like that, that you got to catch up, in a sense. Also, I cannot talk about talent attraction and retention. A couple stats, 78% of the enterprises have started their modernization journey after COVID, and as a result of COVID in 2019.
Many companies out there still delay, not even to the last responsible moment, but beyond that, which can be a problem, and don't prioritize modernization initiatives, and that can be pretty harmful to the business. Because you can say, modernization, and we're going to see that, it is a lot of effort. It is complicated. It is risky. Riskier than modernizing is not modernizing. The consequences of choosing not to modernize are huge. Here the first one is risks associated with system failure and downtime. You got to see that there are many others out there, and including being unattractive as a M&A prospect, so that can harm indeed the business.
Tech debt, lack of modernization can also get you out there in the news, and not as a very good thing, as we could see for SWA a couple years ago when they had a pretty huge meltdown with their booking systems and all that. It damaged their image, but also got them pretty down on their plans in revenue and all that, and still, nowadays they are facing the consequences of that meltdown, which was basically because of ignoring and putting aside the conversations about tech debt and application modernization as a whole.
It's not easy. Almost three-quarters of the organizations that go on the legacy modernization journey fail to complete them. What does failure mean in this context? First, people don't track how they are doing towards the modernization, or the business can't realize even the benefits of the modernization, many times because people just don't know why they are modernizing things. That can also be a problem. We're going to talk about that later. Not taking a holistic view about modernization can also lead to failure, when you think that it is only about technology, but in fact, there is much more around the technology modernization. You got to improve and see as a whole, transformation in the organization, like processes, people, culture, values. Modernizing for the sakes of technology, it doesn't really pay off.
Why Modernize?
We're going to be talking about the essential steps for modernization. I split this between five steps. It goes from why modernize, to how you can measure success. Starting with why modernize, if I ask many senior developers out there, or developers out there, why you should modernize, they're going to tell me, the code is very complex. I don't have confidence to change it. Or, can you believe it? It is a monolithic architecture, or it is pretty outdated. We are still working with Java 8, and we do have a huge cost around maintenance and the tech debt backlog just grows, or there is no tech debt backlog. I think they are all valid concerns and reasons to why to modernize. If you really want to get funding, if you really want to be able to work on a modernization initiative, you need to find out the business needs. You got to understand what are those things that call into your organization.
Let's see an example. The first scenario is a very well consolidated product, or a module, or for product. It is a monolithic application built in Java 6. It is a complex code base. People at that time didn't know about test automation or those kinds of things, or they just chose to ignore. It is a consolidated product that works well. You don't need to change it. There are no critical bugs in it, nothing like that. It's seen as a commodity. It doesn't differentiate you or your company anyhow. Why should you look at modernizing this? It works well, leave it there. If it works, that's fine. It doesn't matter if it's a monolith application or if it's built in COBOL even, you don't need to change it. You're not going to face the pain. You're not going to feel the pain.
In this scenario, you also have a very complex code base that is very hard to understand and very hard to change. The developers in the team, they don't have confidence to change it. There are not really guardrails in place, so you don't know the side effects of the changes that you're going to make. One day, your company was like, number one, top of mind. Digital native companies appeared, were born, and you've been losing market share over time. Those kinds of things make you realize, I got to do something. I got to catch up and innovate myself.
Otherwise, I'm going to keep losing market share, profit, revenue. In this case, you may want to look at, how can I improve this application? How I'm going to build new features so people can come back to my product, or even improve the user experience of it, because people might be dropping because the competitor has a better experience. In front of the technical challenges of modernization, you better look at the business needs. Valid ones in the scenarios that we spoke about are, it's difficult to add new features. The core system, it breaks. I got an outage during Black Friday, so my market campaign did really well, but the system didn't handle the load. You are struggling to hire top talent because people just don't want to work in certain technology or even with certain processes. The users don't want to use the platform anymore, they are dropping and they are using another one. Those are indeed real needs to start and look at modernizing things.
What to Modernize
How do I know what I should modernize? Sometimes, and I got this earlier in my career, people just thought like, we're going to modernize this. Sometimes they even told me, you're going to modernize this by doing that. Fine, but later, you might be the one looking at and analyzing what needs to be modernized. When doing this, you can have different three different perspectives, mainly. You're going to see and you can modernize the platform, so the infrastructure that it's deployed. For example, you can go from on-prem to cloud. Or even the tech stack, so programming languages, or the database, the data integration, and those kinds of things. You can modernize the product itself. When I'm talking about product, it means alignment with the product strategy.
In my case it's client, because I'm a consultant, but your business strategy client needs. Is it still relevant to them? Does it do what it was supposed to be doing? Does it solve their problems? Also, as I mentioned before, the user experience. Sometimes you got to revamp that, do some user research and understand what you can do with the technology available, or new technology available. The architecture modernization, though, I look at it from two different perspectives, the design and then domain. You can address tech debt. You can do a domain redesign, or even a rearchitect of the entire system. You can also look at remodeling the domain, and that means that you've got to deep dive and understand and discover more about the domain that you are in. The benefit of it would be evolvability, so it's easier to add new features. As the business changes, the software changes with it.
When defining what to modernize, you got to understand what are the features that are out there and their purpose, if they're fit for purpose. Usually, I say, don't reverse engineer things, basically because by doing that, you don't know exactly what's being used, and you might spend a lot of time looking at features that users just don't use because it doesn't add value to them. Instead of reverse engineering, look at the usage states of it, so how that is being used, how is the flow of the user and the product, and things like that. If you don't have tooling to do that, that's fine. Go and talk to the customers. Go and talk to your clients. Application rationalization, for those who are enterprise architects or have played this role, this is probably more common to them, or they're more aware of this.
It's basically looking at the inventory of applications that you have in your organization, and understanding, what are the critical ones? What is the value that it adds? Alignment with the business goals. Really like, is it commodity? Can I just go and buy one out of the shelf, two? Then it's fine, go and buy it. If it's something that differentiates you, you got to innovate, then it might be worth looking at building it and hence modernizing it. Total cost of ownership, basically the comparison here is, how much do I spend to keep the lights on in this legacy system versus how much value does it bring back to my business? Is it worth? Does it pay off? Otherwise, you might have a candidate to modernize. Last but not least, what are the technical limitations of the system, of the applications that you have? What is holding you back? Many times, the quality attributes of architecture, like performance, scalability, and things like that, are going to give you a pretty good clue of where are the problems and the bottlenecks? You got to check also for outdated technology, as well as code hotspots.
Basically, because code hotspots predict bugs. We're going to talk more about that later. How can I do that? For the first two ones, Wardley Mapping is a pretty good method and exercise that you can run. If you're going to do it, do in a very collaborative way that is much more valuable than, in fact, the artifact that is built from the exercise. Total cost of ownership, basically Excel and sheets out there. There are tools, especially in the cloud ecosystem, that can give you a pretty good clue about the costs that you have with cloud.
For the technical limitations, let's dive in a little bit more. Looking for technical issues and limitations, I got to say, assess your architecture. That regards scalability, performances, security, the age of technology, as well as try to find code hotspots, or very hot code hotspots. The first one, which is scalability, means, is the system able to handle the increasing volume of data or increasing number of users that you are projecting or that you are getting without degrading performance? If so, cool, then you don't have a limitation over there. You might run load tests, stress tests, load, you do look at some volume. You run it, see if everything's fine. If you want to see, how further can I go until it breaks? Then you go with the stress tests. For performance, how well the system responds in the current circumstances. Here we usually look at response time, latency, resource utilization, CPU, and things like that. You've got to find out, where are the bottlenecks? Is it processing? Is it memory, networking?
One sensible default tool that we usually use for performance testings nowadays is k6. It has a pretty good developer experience and command line interface where you can integrate it even in the build pipeline. If performance is really important for you, you got to check it every time that you make code changes, or changes in the software in general. Security, you got to see if you are vulnerable to cyber-attacks. Usually, identity, like authentication, authorization, and infrastructure configuration on the cloud, those are hotspots around security. Tools like ScoutSuite and Orca could help with that, could help you spot that. As well as Snyk, the OWASP Top 10, and there is dependency check for that, and other toolings that could help you. You got to see if you are compliant with the rules in your industry, or if you are risking being sued, or to pay a huge amount of money because of not complying with the industry standards.
For PCI compliance, we have cdk-nag. In the autonomous mobility space, there is a new entry. It is powered by Gen AI, so I thought you would be interested. It's Deontic. To find out if you are compliant with the open-source licenses of the libraries and frameworks that you are using in your software supply chain, there are FOSSA and CAST OSS risk control. The asterisks means that it's also powered by Gen AI. Those are just new entries in the field. We are still assessing and keeping an eye on it at Thoughtworks.
The other thing is the age of technology. If you have outdated technology, you very likely have vulnerabilities. If you have lack of support, either from the community or the vendors, there is a security vulnerability there, but there is no security patch being released because there is no support anymore. The other thing that you got to check for is compatibility with new technologies. In the project that I work on, the legacy system uses Hibernate 4, and we were trying to build new things with Spring 5 and more modern stack. At some point we couldn't, because the legacy technology was not compatible with the new technology that we wanted, and we had to drop and downgrade. We were a little bit frustrated, but that happens. Tools that can help you with that is basically dependency managers, plugins. For npm, there's also npm-outdated. I'm just giving you examples so you don't go out there thinking that, I need to do that all by myself. I'm going to write scripts to find out everything that Camilla said that I should be looking at. Keep in mind that you can leverage existing tools and technologies out there.
Code hotspots, this is really a concept that comes from "Your Code as a Crime Scene". Adam in the book, he defines the code hotspots as something that is very complex. It can be in even lines of code, even though it's not a very good metric, but complex somehow. Because there's even a study that says that doesn't really matter which complexity metric you are using, they all give you the same clues when you put together with the version control system data. It's basically code that is very complex and also changes over time, it's relevant. If you're touching, it's relevant. If you're touching and it's complex, and you don't have the guardrails in place, you very likely get a bug. Those are code hotspots, where you could potentially look at first. That will give clues where to start and what to modernize. Instead of looking at the aesthetic or the snapshot of the analysis or the data, look for trends.
Look, for example, for late development, like a year ago till now. That's going to give you a better clue of how things are progressing, and even tell you a little bit about how they're going to continue progressing. You're going to be more spot on on what and where you got to change. Hotspots can predict bugs. Tools that help you with that is CodeScene, which is a product of a company funded by the author of the book that I mentioned, but also CodeCity, and Toxicity Analysis. How toxic is your code? This is from a colleague, Erik Doernenburg, who is also a co-author of the Thoughtworks Tech Radar. He has these really high thresholds, which is like, there is really not consensus around, how long is a method? If it goes beyond 30 lines, it is indeed a very long method, and no one can deny it. That is going to extremes and looking at how toxic it is. The CAST Imaging is from the CAST family, which is also powered by Gen AI.
Current State Analysis
We looked at why and what, and now we are going to move into the current state analysis. One thing to note is, maybe we want it, but the process is not linear. You got to do this and come back. Got to do this and come back. Especially these two, like what and the current state analysis, there is a closed loop between them. When looking at code assessment, usually what I do, and people that work with me, we look at the broad system landscape. We look at the system boundaries. Look for readability, how is it to maintain? Also, for the legacy seams. Deep diving a little bit more, go broad to see the big picture. See how the components interact with each other. Have a look at what are the deployable units that you have and how they interact with each other in runtime.
If you find anything that looks like an anti-pattern, like bottlenecks, dependencies, points of failure even, then you got to zoom in a little bit more and try to find why that is happening. What are the side effects of that? Then you can come back to the what, and say, look what I found. Maybe we got to look at this subsystem first, instead of that one. System boundaries. Here, it is around mainly subsystems modularity. The integrity of the layering. For example, do you have business logic in the UI? Maybe you have a problem. Or, are my subsystems decoupled enough? Last but not least, subdomain alignment. In this case, it is very related to the domain of the application. Here we are talking about bounded context. We are talking about things that change together you keep together. Things that don't change together, then you can decouple. Otherwise, you have decoupled stuff that change together, then they are coupled anyways.
For readability and maintainability, a good trick is, have a look at the shape of the code. It is amazing how it's going to be easy to spot very complex code or testing cases when you actually look at a very simple and clean code. Then you can spot complexity, where it's very hard to understand the code. If I can't read, I can't understand, very likely I'm not going to be confident to change it. Then, if I'm looking at adding new features, I might have a problem here. Legacy seams, they are really helpful to break the whole modernization problem into smaller pieces. If you're looking at delivering in an incremental and iterative way, which you should, then try to find architectural seams, like how things depend on each other.
How the calls from the API goes over and over. What are the pieces of the ecosystem or the subsystems that it touches? The code seams are more related to coupling, like high coupled classes and things like that, and not so coupled as well. You got to understand a little bit more like, where are the hotspots? Then you might have an ability to split things. Then you say, I delivered this first, and then I can deliver that independently later. As I said, dependency mapping and look at test coverage and code quality. Do not look only for test coverage and quality code, because it doesn't give you a very broad view. It's very narrow. You might get into issues if you only look at that.
Visualize the architecture. Have a broad view. You got to build that somehow. At least in my bubble, the C4 model is the most used one, the most popular. If I can give you an advice around tooling, prefer diagram-as-code tooling. You're going to version it. It's going to live together with the code. If you need other stakeholders to see it, because sometimes that is what people say, to not version it together with the code, you can very easily get the diagrams to be plotted in an HTML and publish it in any internal website, Confluence or anything like that. The same applies to ADRs, architectural decision records. Please keep them together with the code, especially related to the code that is introducing the changes regarding that architectural decision record.
These toolings are the most famous ones, at least in my bubble: the Graphviz, Mermaid, and Structurizr. These two others can help you generate diagramming from your code and helping you to visualize and explore really in different levels of detail, the architecture, dependency mapping, and all that kind of stuff. The asterisk means powered by Gen AI. I don't know if they work, but they seem promising. Keep an eye on the Thoughtworks Tech Radar, we got to tell you if we have good experience with it later. This screenshot here is one of the pages from the C4 model website, and it gives you couple choices so you can get ideas about tooling that you can use. In this case it's got to be open source. I want static diagrams, and I want diagram and model as code. It gives me this range of tools here.
Before we move on, let's just highlight this. It is an important note. As I said at the beginning, there is a feedback loop. Things are not linear as much as we want it to be. You got to prioritize. The current state analysis is going to inform like what to modernize, giving you inputs for prioritization, how complex things are. How many dependencies do I have? It increases the risk of change. I can do a change and break really core applications in production. Those things, the feasibility of the modernization, or what to tackle first should also be analyzed in order to prioritize where you're going to start. If I can give you an advice, I usually start with things very simple that adds value to the client and to the organization in general, because I got to learn how things work. Many times, you have no clue how things work in the legacy world, so it is a continuous learning process.
The first pieces, we call thin slices. For the first thin slices, go with simple things that adds value, but let you learn a lot about what you are doing, what you are changing. Then you go with more complex stuff. This is one way to prioritize. I also like to use the effort reward matrix. It basically looks at some factors around the modernization, which is going to give you the feasibility, the complexity. Is it risky? It is risky. Then, how risky it is. I think this is going to give you a good clue. In this case, we were looking at minimizing the TCO. You got to see, what is the safer thing? This shows 1, 2, 3, 4, shows the prioritization, actually, that we made based on those high, medium, and low complexity, total cost of ownership, business value being delivered, how risky it is, and what are the dependencies. You can see the reconciliation, business capability scored really high in the dependencies. We left it towards the end, because then we learned a lot. Then we can go there with much more confidence.
How to Modernize
How to modernize, as I said at the beginning, there are very well-known migration patterns and things like that, that you can go out there and look. I'm going to give you just a couple advices, starting with why I stressed so much the why. The why you are modernizing determines how you're going to modernize, what you're going to modernize. You got to look like, I'm looking at rehost and platform modernization, or am I looking at product modernization. The technology is fine, but the experience sucks. Or am I looking at modernizing the design or the domain. Those are strategies. I put a little bit of how to read it. Basically, sunset and maintain, there is no modernization there. You got to see how you optimize things so you don't spend a lot of money keeping the lights on. If you choose lift and shift, that's basically taking the application that runs, for example, on-premise, moving it to the cloud. It can be a good strategy first, but you got to remodel and reshape it later to take full advantage of the cloud.
Things that were built to run on-prem, very unlikely is going to run well on the cloud. The legacy encapsulation and legacy policy are basically very technical modernizations. Legacy encapsulation, I like it because it is basically leaving the legacy in a box. You don't change it very much, but you expose their capabilities, you expose their features, very likely with an API. Then, that's where you start leveraging platform thinking, and thinking, what else can I build on my very core business capabilities? Then you can go broad and innovate. Then you go in different levels of it, until you get to the total modernization, which is pretty much like reinventing, reimagining your business capabilities. The role that your organization plays in the world, like going wild and changing the business capabilities that it provides, but also the technology, the platform. Of course, that is like the most expensive one, the riskier one, for sure.
When modernizing, and even if you are starting like a Greenfield, keep this in mind. I'm not going to be the person who's going to tell you which programming language you're going to use, but I'm going to be the person who cannot emphasize enough the guiding principles and the techniques that you should be using in order to do things right. Evolutionary architecture basically embraces that architecture is going to change. As much as business changes, requirements change, architecture is going to change. We left in the past the thing that architecture is something that you do first. It's not going to change. Just hand over to the teams and they're going to make it work. This is not going to work. What you're going to do is look at the guardrails, the fitness functions of the architecture, which is basically the quality attributes, like performances, scalability, the -ilities usually.
Look at how to measure it in an automated way, and that is going to guide how your architecture is going to evolve. You ensure that things evolve because they will. The architecture is going to change, but you're going to still keep them fit for purpose. It's going to still be doing what it was supposed to be doing in terms of performance, in terms of even encapsulation, layering, and things like that. There you can leverage things like architecture unit tests with ArchUnit, for example. Event-driven architecture. Basically, you build well decoupled systems with that. It is not easy, but you can do that. DDD, continuous delivery, and everything as code. Everything as code is like extending the idea of code application, and applying engineering practices to everything that you can write as code, like infrastructure, even like architecture, and so on.
The how to modernize, do not keep it only on the technical side. It is not only a technical challenge. It is also looking at release strategy. It is also looking at business strategy and what delivers value first. Avoid big bang releases as much as you can. Identify the architecture and the code seams. See how that can help you break the whole thing into smaller pieces. When you are looking at modernizing you may not be looking at the entire application or the entire subsystem. Search for thin slice. That means, I can start with one feature with this subsystem and go down thin-slice, so you get different layers of that specific feature. You improve it. You see what good looks like. You make it happen. Then you might go to another feature in another subsystem. You don't have to modernize everything in this subsystem or application, and then go to the other one, if that is not what the business needs. If it's not what adds value to the business, or aligns with their priority.
How to not modernize. Default to start from scratch. Yes, we are going to start decoupling everything and even storming, and that's going to give me the boundaries. It's going to be very exciting. You're going to fail, especially if you depend on the legacy system. If you might need some level of interoperability between what you were building and the old system. If you look at well consolidated patterns and ways of modernizing, very likely you're going to need to use the legacy system still. Over-engineering, I cannot emphasize that enough. You build this amazing end state target architecture, and you don't know even the first step to get there. Don't do that. Have a target architecture. Look at how you can get there in a very feasible way. Do not think that existing technology is going to solve the modernization for you. You got to do something. You got to change things. Be aware of that.
Measuring Success
Looking at how you measure, I'm going to say two things. Choose the right metrics, because metrics influence how people behave. Culture in this space is really important. Assess the metrics over time. Do not do one time and forget. Build the baseline, but assess it over time. Looking at, when can I stop? It would be ok to stop if the drivers were stuck, but the drivers of modernization keep moving forward, and you got to move forward with it. You can't just say, "The project's done. Fine, I've modernized". Then you need to modernize something else . To guide the way, use metrics that let you build it right, looking at an engineering excellence perspective, so you can build the right thing. You look at like the DORA metrics, you look at engineering excellence metrics, and then you can have a look at how that impacts the business. Success is not one single thing, it is very well rounded. I brought this here so you can see, and you're probably aware that this space is very complex, you cannot look at only architectural things. That would mean only the dark blue thing here. You got to see everything else that it allows, or that it impacts, or it's impacted by.
Summary
Bear in mind that modernization is a never-ending journey. It is a journey much more than a final destination. Embrace the process, learn, and enjoy the progress that you make. Finally, have modernizing.
Questions and Answers
Participant 1: Now I have a framework to be able to follow to help modernize my architecture. In my real work, my PM keeps asking me every day to push more features, and it's pretty hard for me to convince them the importance of them. What is your piece of advice to me to convince them the importance of these type of efforts?
Crispim: I faced that in many teams. My advice to people, like developers that are very frustrated about that was, look at how the tech debt impacts the final user, the customer, the experience. If it hits the product, if it hits the product strategy, it's going to get prioritized. If you have, for example, a tech debt that hits performance really hard, response time really hard, it impacts directly how the user experiences the product, I'm pretty sure the product manager is going to say, is that really the consequence of that? Then you're going to find a way to start the conversation. I'm not saying that they're going to deprioritize all the features, and start looking at only the tech debts and all that. You have a business way, or you can articulate in a way that the business understands. It is not like, my developers are always gold plating and they can't sleep at night because they didn't refactor. In fact, refactoring, and you do that as part of your job. It is just one way to move faster. Moving faster is exactly what the business wants.
Participant 2: If you come from a legacy monolith, and for example, there's one large database, and then you begin a modernization program, and then tens of databases begin to pop up all over the organization and are maybe not very well managed. What's your experience of that? What guidance would you have for a company in that situation?
Crispim: I just faced something similar, from what I understood of what you're saying. We're looking at modernizing the platform as a whole. At some point we were looking at decoupling the domains and all that. Every microservice got to have their database. We had a huge data consistency and transaction consistent and cohesion requirement, and we couldn't apply things like data reconciliation and things like that. The business at some point said, we might go with microservices, but we are not going to split the database. Everyone was like, "What? This is not microservices. The database is going to be a huge coupling point". All true, but, ultimately, it is a business decision.
You got to, as a technologist, understand what are the consequences of that. You cannot go against it. The other thing is, put the guardrails in place. In our case, what we did was we started with a modular monolith that could evolve to a microservices architecture. Because the database was so messed up, what we started doing was having ArchUnit tests in place that could ensure that the domains are not going to get mixed up, or that the low-end domain are not going to be using something from a non-related table just because it is there. Or even fields in the database that are in the wrong table, in the wrong place. We started looking at those mechanisms to ensure that the architecture is going to evolve in the right way. We're not going to repeat the errors from the past. Then, it's going to be, in fact, easier to extract microservices after that. I wish to be around to see how that's going to evolve.
See more presentations with transcripts