Welcome. Today we’ll take a look at refactoring within Lattix Architect. The refactoring we’ll focus on is architectural refactoring. We’ll look at a few examples and show you how you can take a large-scale application, which perhaps has become very difficult to maintain, or that you want to split up, or contains code that you want to share, and refactor it.
Let’s start with a simple example. I have loaded a C/C+ project called IsoAgLib, a micro-kernel. It has a set of directories, which contain some source files and header files and so on. We’ve created a map of all the dependencies by doing an analysis of the project.
You can see there are many dependencies between the elements. I’m going to apply partitioning and get an architectural sense of the code. I’ll select the component partitioner, which orders the elements according to the way the system should be layered. We can see now that all of the elements are coupled to each other.
For instance, comm depends on util and util depends on comm. That is a cycle. Until Lattix Architect came along, people would print out the cycles that existed within their various files or various subsystems. This could represent hundreds of different cycles.
So where should you snip your cycle? Where should you cut so you get rid of the cycle? The answer seems pretty clear. If I wanted to get rid of the cycle between comm and util I would get rid of that one dependency. The alternative is that I would have to get rid of 301 dependencies the other way. As an architect, I recognize that comm is where my application level code goes and that it’s going to depend on the utilities. Therefore, it makes sense for me to eliminate that dependency.
Let me simulate that and hide that particular dependency. With the dependency removed from my model and I can apply partitioning again. Once I apply partitioning again, all of the elements are still selected. Why is this? Comm still depends on util, and even though util doesn’t depend on comm anymore, it does depend on the hardware abstraction layer, which in turn depends on driver, which in turn depends on comm. That’s a cycle that’s got four different legs to it. You can easily have giant cycles.
So where should you split it now? Once again, the answer suggests that driver should never have any dependencies on comm. I can get rid of that dependency and hide it.
I’ve removed that dependency and now when I apply the component partitioner, I’ve decoupled the rest of my system from comm. In other words, comm, which is the application layer, uses the rest of the code, which is underneath it, but the dependencies are removed in the other direction.
If you go to the Work List, there is the full list of the dependencies we eliminated.
To summarize, unless you have visibility into the architecture, you wouldn’t know which dependency to remove. With Lattix Architect, you can focus in on the dependencies that are bad and the ones that are causing cycles and fix them.
Let’s take a look at another example. Say we wanted to share util with another application. What would we do? We would turn util into its own library, either a shared library or a static library, which is linked into IsoAgLib but also linked into some other application. If we tried to do it now, notice that util depends on ‘*’ and the files within ‘*’ would have to come with util. It turns out there is a header file in ‘*’ so when we bring in util we’ll have to bring in ‘*,’ as well.
Notice that util has a dependency on the hardware abstraction layer, which means that when we create a library out of util, it will depend on things that are in util. Once you pull in hal, it will pull in other elements because hal depends on driver. You’ll have to pull in driver and once you do, you pull in the scheduler. If you hadn’t removed those dependencies earlier, you would have pulled in comm, as well. This is what makes re-using code so difficult.
In this particular case, if I were to eliminate that dependency and this dependency, as well, because there is an indirect dependency of util on hal - util depends on ‘*,’ which depends on hal - I would be able to extract util as a separate library and be able to share it.
These are just two examples. Perhaps you have a large application and you want to split it up into microservices or separate applications. Perhaps you have a library that you want to replace with more modern technology. Lattix Architect will allow you to figure out the exact dependencies and will create a work list of all actions taken. Here we’ve created a work list of hidden dependencies. You can create your modules within Lattix and they’ll get added to the work list.
If you are facing a large-scale refactoring job in which you need to take an application, which has become hard to maintain, or that should be split apart, you can, without writing a line of code, create a comprehensive work list that tells you what you need to do to arrive at your desired architecture.
If this piques your interest, go to our refactoring page. You’ll find a webinar that describes in detail many of these techniques. There’s also a case study from L.L. Bean, which shows how a large-scale application was refactored using Lattix Architect.