Suppose you are a Java developer who is developing and maintaining a project with 2000 classes and using many frameworks. How do you understand this code? In a typical Java enterprise project team, most of the senior engineers who can help you appear to be busy. Documentation is also sparse. You need to deliver results as quickly as possible and prove your capabilities to the project team. How would you handle this situation? This article provides some advice for Java developers starting a new project.
1. Don’t try to understand the entire project at once
Think about it carefully, why is understanding the project code the first priority? Most of the time you are asked to fix a bug or enhance an existing feature of the system. The first thing you have to do is not understand the architecture of the entire project. This (understanding the entire project architecture) can cause a lot of stress on you when maintaining the project.
Even a Java developer with 10 years of solid programming experience may not understand the core workings of the project, even though they may have been working on the project for more than a year (assuming they are not the original developer). For example, for authentication mechanisms or transaction management mechanisms.
How did they do it? They understand their areas of responsibility very well and are able to deliver value to the team. Delivering value every day is far more important than knowing something you’re not sure you’ll have in the future.
2. Focus on delivering value as quickly as possible
Then have I denied your enthusiasm for understanding the project architecture? Absolutely not. All I ask is that you deliver value as early as possible. Once you start a project and set up a development environment, it shouldn't take you a week or two to deliver something, no matter how big or small it is. If you're an experienced programmer and don't deliver anything for two weeks, how will your manager know if you're actually working or watching the news?
So delivery can make everyone relaxed. Don't assume you have to understand the entire project before you can make valuable deliverables. This is completely wrong. Adding a piece of javascript verification code is very valuable to the business, and the manager can gain trust in you through your delivery. This can prove your contribution and employee value to your superiors.
Day after day, as you continue to fix bugs and enhance functions, you will slowly begin to understand the project structure. Don’t underestimate the time it takes to understand every aspect of the system. Spend 3-4 days understanding the authentication mechanism and 2-3 days understanding transaction management. These all rely on previous experiences with similar projects, but the key is to take time to fully understand them. Carve out time in your daily work and don't ask your manager for specific times to do it.
Look to see if the project has some unit test cases that are continuously maintained. Effective unit test cases are a great way to understand the code of large projects. Unit tests can help understand code snippets, including a unit's external interface (how the unit is called and what it returns) and its internal implementation (debugging unit tests is much easier than debugging the entire actual use case).
If you can understand some content well, write some notes, or draw some class diagrams, sequence diagrams, and data model diagrams so that you or other developers can maintain them in the future.
3. Skills necessary for maintaining large-scale projects
If you can engage in the current job, you must already have good Java technology. Let’s talk about other skills that will allow you to perform well on new projects. Most of the time, your tasks in a project will be to fix bugs and enhance functionality.
There are two very important skills that can help you maintain the code of large projects.
3.1 Able to quickly discover needed classes
In any maintenance activity, whether it is fixing bugs or enhancing functions, the first action is to identify the classes called in the currently fixed or enhanced use cases. When you locate the classes/methods that need fixing or enhancement, you're halfway done.
3.2 Able to analyze the impact of changes
After you complete the necessary modifications or enhancements, the most important thing is to confirm that your modifications do not damage other parts of the code. You need to use your Java skills and understanding of other frameworks to find out what parts may be affected by the change. Here are two simple examples detailing the last mentioned situation:
a) When the equals() method of class A is changed, calling the contains() method of a List that protects an instance of A will be affected. Without sufficient knowledge of Java, it is difficult to consider such an impact.
b) In a web project, we assume that the "user id" is saved in the session. A new programmer may add some information to the "user id" as a bug fix, but not know that it will affect the use cases associated with the "user id".
When you improve the above two skills, most maintenance tasks will become much easier even if you don’t know much about the project. If you fix a bug, you locate and fix the bug, and make sure the changes don't break other parts of the project. If you enhance or add a feature, you basically just copy the existing feature and use a similar design.
In an online banking project, why do the designs of “View Account Summary” and “View Transaction History” need to be so different? If you understand the design of "View Account Summary", you can completely imitate and develop the "View Transaction History" function.
When it comes to bug fixes and enhancements, you don’t have to fully understand what all 2000 classes do and how the code runs to drive the system. If you have the above skills, you can quickly locate the part of the code that needs to be modified, use good Java and framework skills to fix it, ensure that the change will not break other parts of the project and deliver it, although you may only know a small part of the project design.
4. Use tools to find the required changes and the impact of the changes
Continuing with our theme of delivering as quickly as possible, you should look for tools that can help you implement delivery as quickly as possible with as little understanding of the project as possible.
4.1 Quickly discover tools that need to be changed
Whether it is fixing bugs or enhancing the system, you must first find the classes and methods called by the use case that you need to modify. There are basically two ways to understand how a use case works, static code analysis and runtime analysis.
Source code analysis statistics scan all codes and display the relationship between classes. There are many devices and tools on the market. For example: Architexa, AgileJ, UModel, Poseidon, etc.
The disadvantage of all static code analysis tools is that they cannot accurately display the runtime calls of classes or methods in use cases. Therefore, Java has added new features, such as callback patterns. For example, static analysis tools cannot infer which Servlet was called when the page submit button was clicked.
Runtime analysis tools can display the status of classes and methods when the use case is running. Tools include: MaintainJ, Diver, jSonde, Java Call Tracer, etc. These tools can capture the runtime stack state and generate sequence diagrams and class diagrams for a use case.
The sequence diagram shows all the methods called by the use case during runtime. If you're fixing a bug, it's likely that the bug is one of these methods being called.
If you are enhancing an existing function, use sequence diagrams to understand the calling process and then modify it. It may be to add a new verification, modify DAO, etc.
If you are adding new functions, find some similar features, use sequence diagrams to understand the calling process and then imitate and develop new functions.
Be careful when choosing runtime analysis tools. Too much information is a major problem with this type of tool. Choose tools that provide simple filtering of invalid information and convenient viewing of various views.
4.2 Tools for quickly discovering content that needs to be changed
If the unit test is effective, you can run the unit test to find out whether the change destroys other test cases. There are still relatively few unit tests that can effectively maintain and cover large enterprise applications. Here are some tools for this situation.
There are still two techniques that can be used: static code analysis and runtime analysis. There are many static code analysis tools available in the market. Such as: Lattix, Structure101, Coverity, nWire and IntelliJ's DSM.
Given a changed class, the above tools can identify the collection of classes that are dependent on the class. Developers need to "guess" the use cases that may have an impact based on this information, because these tools cannot show the calling relationships between runtime classes.
There are not many tools on the market that can be used for runtime impact analysis, except MaintainJ. MaintainJ first captures all classes and methods called in a use case. When the above information for all use cases is captured, it is easy to find the impact of class changes on the use cases. The prerequisite for MaintainJ to work effectively is that all use cases of the project should be run first so that the runtime dependencies can be obtained.
In short, at present, you can still get limited help from tools in quickly and accurately analyzing the impact of changes. First perform some impact analysis as needed, and then judge the impact of the change based on review by yourself or other senior members of the team. You may need the tools mentioned above to double-check your judgment.
5. Two pieces of advice on the above content
5.1 Do not reduce code quality
In order to deliver quickly, we do not fully understand the architecture, but we must not reduce code quality as a condition. Here are some code quality issues you may have caused by focusing solely on fast delivery.
Since modifying the code involves many dependencies, the risk of adding new code is relatively small. For example, there are 5 use cases that all call a certain method. To improve a use case, you need to modify the implementation of this method. The simplest thing to do is to copy the method, rename it, and call the new method in the modified use case. Don't do this. Code redundancy is definitely very harmful. Try to wrap or rewrite the method, or even modify it directly, and then retest all use cases. It is usually a better way to stop and think about it and then implement it yourself.
Another example is to change the "private" method to "public" so that other classes can also call it. Try not to expose unnecessary parts. If refactoring is needed for a better design, it should be done.
Most applications have a certain structure and pattern to implement. When fixing or enhancing your program, make sure you don't deviate from this pattern. If you're not sure about the convention, ask other senior developers to review your changes. If you must do some implementation that violates the contract, try to place it in a smaller class (a private function in a class with 200 lines of code should not affect the overall design of the application)
5.2 Don’t stop understanding the project architecture in depth
According to the method listed in the article, assuming that you can deliver while knowing less about the project and continue doing so, you may stop having a deep understanding of the project architecture. This will not help your career in the long run. As your experience increases, you should take on larger module tasks. Major improvements such as building a complete new feature or modifying some basic design of the project. By the time you're able to make these improvements, you should have a pretty good idea of the overall architecture of the project. The methods listed in the article are to allow you to improve yourself in the shortest possible time, rather than to prevent you from fully understanding the entire project.
6. Conclusion
The entire article focuses on rapid delivery under the premise of necessary understanding of the project. You can do this without compromising code quality.
If you fix a bug, quickly locate and fix it. Runtime analysis tools can be used if necessary. If you add a new feature, you can look for similar features, understand the process (tools are necessary) and write.
Maybe this sounds simple, but is it practical? certainly. But the premise is that you have good Java technology and enough understanding of the framework to modify the code first and then analyze the impact of the change. Analysis of the impact of a change requires more skill than implementing the change. You may need a senior developer to assist you in analyzing the impact of the change.
Approximately 50% of the IT operational budget is spent on simple bug fixes and feature enhancements. According to the suggestions in the article, it should be very helpful to save funds in maintenance activities.