By Yunyue
Code related to outdated technologies:
• Code associated with operating systems or software libraries that are no longer supported.
• Code that relies on obsolete technology stacks or programming languages.
Code retained for compatibility with backward features:
• Code segments retained in modern software to ensure compatibility with older versions.
• Code that must be preserved to maintain backward compatibility.
Code lacking documentation and maintenance:
• Old code that does not have adequate documentation.
• Code that lacks modern development practices (such as unit testing and code reviews).
There are three approaches to resolving legacy code:
Approach |
Pros and Cons |
Rewrite from Scratch |
The cost is high and the system is running, which will bring code risks. |
Refactor |
|
Add Unit Testing |
Identify problems in existing code through unit testing and provide quality assurance for possible future code changes. |
According to the above description, adding unit testing is an effective method for addressing legacy code. However, this approach still has some problems:
• A large amount of legacy code lacks unit testing, and the cost of testing is very high due to complex dependencies between code segments.
• The specific measurement metrics are not clear enough to define good unit testing.
• Which code needs to have unit testing added?
• Pseudo unit testing without assertions: Developers may resort to calling functions without assertions to improve coverage metrics, resulting in many invalid unit tests.
• Treat unit testing as white-box testing: Some opinions classify unit testing as white-box testing, but they should be considered black-box testing for function signatures.
• Depend on the real environment: The main obstacles to unit testing include laziness and dependency on environment configuration. Without using Stubs or Mocks to decouple from external environments (such as network IPs and databases), unit testing will struggle to meet the FIRST principles (Fast, Independent, Repeatable, Self-validating, Timely).
Unit testing not only brings benefits but also incurs certain costs. Analyzing legacy code from a cost-benefit perspective can help clarify the strategy for adding unit testing to legacy code. This strategy is known as selective unit testing. So, how can we define the costs and benefits?
Unit testing for legacy code can be classified into quadrants based on their costs and benefits. The classification criteria and detailed explanation of each quadrant are as follows:
• X-axis (Cost): The higher the code dependency, the greater the testing cost.
• Y-axis (Benefit): The higher the code complexity, the greater the quality benefit.
Code Category | Characteristics | Description | Benefit | Cost |
---|---|---|---|---|
Algorithms Code | High cyclomatic complexity and high fan-in. | It contains many conditional statements and loop statements, has few dependencies on other code, but is relied upon by a large amount of code. | High | Low |
Trivial Code | Low cyclomatic complexity and high fan-in. | It is typically simple with only one or two lines of code. | Low | Low |
Coordinators Code | Low cyclomatic complexity and high fan-out. | Located at the upper level of the call hierarchy, it reflects specific business scenarios by calling other codes. | Low | High |
Overcomplicated Code | High cyclomatic complexity and high fan-out. | It is a typical code smell due to its complex logic with many dependencies, lengthy functions, and numerous parameters. | High | High |
• Cyclomatic Complexity: Measure the number of logical branches in the code.
• Fan-in: The number of modules that call the current module. Higher fan-in indicates higher reusability.
• Fan-out: The number of modules called by the current module. Higher fan-out indicates more dependencies.
Based on the above analysis, the strategies for handling legacy code become clear:
• Algorithms Code: Generate unit tests.
• Coordinators Code: Perform interface tests.
• Overcomplicated Code: Look for opportunities to refactor.
• Trivial Code: No action is required.
When maintaining legacy code in a project, you can first use the @workspace feature to understand the purpose of the entire project and the various modules involved.
1) Generate unit testing for algorithms code
Select the part where code generation based on production code is required. When generating, pay attention to the required frameworks and dependencies such as Mock. You can supplement this information by appending it to the unit testing generation command. For example: /generate unit testingCppUTest.
In general, the number of unit testing cases generated based on existing code is usually limited. If you have specific requirements for testing scenarios and the number of use cases for unit testing, you can generate more unit testing by continuing the test function in the newly generated unit testing files. In the continuation process, Tongyi Lingma will try to follow the existing testing cases as a reference context.
2) Perform interface tests for coordinators code
For coordinators code, unit testing is not an ideal solution, as the high number of dependencies significantly increases the testing cost. For such code, interface testing or functional testing should be used to achieve coverage. However, when writing automated test cases, developers often encounter related issues. Therefore, by using Tongyi Lingma, developers can quickly grasp and understand the testing framework.
For the creation of test cases, you can select the corresponding function to be tested and directly ask in the Q&A section: Generate test cases for the following code based on Robot Framework. Following this approach, you can also implement corresponding Keywords and other content.
3) Refactor overcomplicated code
For overcomplicated code, you can use the /generate optimization command in Tongyi Lingma to obtain optimization suggestions for the selected code. Code reviews and optimizations will provide suggestions for improvement from multiple dimensions, including syntax issues, exception handling, code cleanliness, security, and risks.
For the optimization of complex legacy code, it is not recommended that developers blindly carry out comprehensive optimization and refactoring. Changes to legacy code can pose significant risks. Therefore, developers should refactor and optimize the code based on the specific scenario, seize appropriate opportunities, and abide by the Boy Scout rules. In this process, Tongyi Lingma will also provide you with strong support.
The above are practices that can be referred to when dealing with legacy code. Handling legacy code requires delving into its complex structure and meticulously tracing every possible branch node. In this process, in addition to identifying and fixing potential defects, all tasks must be completed within a limited time. To avoid this situation, the best strategy is to prevent code degradation, make good use of tools, and follow sound programming principles from the outset.
212 posts | 13 followers
FollowAlibaba Cloud Native Community - December 31, 2024
Alibaba Cloud Native - March 19, 2025
Alibaba Cloud Indonesia - February 7, 2025
James Lee - December 24, 2024
Alibaba Cloud Community - April 12, 2024
Alibaba Cloud Community - January 21, 2025
212 posts | 13 followers
FollowA unified, efficient, and secure platform that provides cloud-based O&M, access control, and operation audit.
Learn MoreManaged Service for Grafana displays a large amount of data in real time to provide an overview of business and O&M monitoring.
Learn MoreAccelerate and secure the development, deployment, and management of containerized applications cost-effectively.
Learn MoreExplore Web Hosting solutions that can power your personal website or empower your online business.
Learn MoreMore Posts by Alibaba Cloud Native