Suppose you are a Java developer developing and maintaining an application that contains 2000 classes and uses many frameworks. How do you understand this code? In a typical Java enterprise project team, most of the senior engineers who can help you seem busy and have very little documentation. 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 do you want to understand the project code first? Most of the time someone asks you to fix a bug or enhance an existing function of the system. The first thing you have to do is not understand the architecture of the entire project. Doing this (understanding the entire project architecture) can be extremely stressful for you when performing maintenance on your project.
Even Java developers with 10 years of programming experience cannot understand the core working mechanism of the project, even though they may have been working on the project for more than a year (assuming they are not the original developers). For example, there is still a lack of precise understanding of the authentication mechanism or transaction management mechanism.
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 do I want to discourage you from understanding the project architecture? Not at all. All I ask is that you deliver value as early as possible. Once you start a project and set up a development environment, you shouldn't take a week or two to deliver content, no matter how big or small it is. If you're an experienced programmer and you haven't delivered anything for two weeks, how will your manager know if you're actually working or just watching the news? .
So delivery can make things easier. Don’t think you have to understand the entire project before you can deliver something of value. This is completely wrong. Adding a piece of Javascript verification code is very valuable to the business, and managers can trust you more through your delivery. This can prove your contribution and employee value to your superiors.
Day after day, after constantly fixing bugs and enhancing 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 to 4 days understanding the authentication mechanism and 2 to 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.
Find out if the project has some effectively maintained unit test cases. Effective unit tests are a great way to understand the code of large projects. Unit testing can help you 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, then write some notes, or draw some class diagrams, sequence diagrams, data model diagrams, etc. so that you or other developers can maintain it in the future.
3. Skills necessary for maintaining large projects
If you can engage in your 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 role in the 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 the required classes
In any maintenance activity, whether it is fixing bugs or enhancing functions, the first thing to do 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 have completed the necessary modifications or enhancements, the most important thing is to make sure that your modifications do not break other parts of the code. You need to use your Java skills and understanding of other frameworks to find out what parts the change may affect. The following two simple examples detail the last mentioned situation:
Therefore, you need to have a deep understanding of both the Java language and the framework you use in your application, so that you can analyze the impact of a change.
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 want to fix a bug, you locate and fix it, and make sure the changes don't break other parts of the project. If you want to enhance or add features, basically you just need to imitate the existing features and use a similar design.
In an online banking project, why are there huge differences in the design of “View Account Summary” and “View Transaction History”? If you understand the design of "View Account Summary", you can completely imitate and develop the "View Transaction History" function.
In terms of bug fixes and enhancements, you don’t have to fully understand the working content of all 2000 classes and the principles of how the code-driven system operates. As long as you have the above skills, you can quickly locate 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 then deliver it, even though you may only know the design of a small part of the project .
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 as assistance, which only require little understanding of the project to help you implement delivery as quickly as possible.
4. 1 Tool to quickly discover the required changes
Whether you are fixing bugs or enhancing the system, you must first find the classes and methods called by the use case that need to be modified. There are basically two ways to understand how a use case works, static code analysis and runtime analysis.
Source code analysis statistics will scan all codes and show the relationship between classes. There are many tools on the market. For example: Architexa, AgileJ, UModel, Poseidon, etc.
The disadvantage of all static code analysis tools is that they cannot accurately show the runtime calls of classes or methods in use cases. Therefore, Java has added some new features, such as callback patterns. For example, static analysis tools cannot infer which Servlet will be called when the submit button of the current page is clicked.
Runtime analysis tools can display the status of classes and methods when the use case is run. Such 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 use cases.
The sequence diagram will show all the methods called by the use case during runtime. If you're fixing a bug, chances are the bug is one of these methods being called.
If you are enhancing existing functions, perhaps adding verification, modifying DAO, etc., then you can use sequence diagrams to understand the calling process and then modify it.
If you are adding new functions, you can find some similar features, use sequence diagrams to understand the calling process, and then imitate and develop new functions.
Choose runtime analysis tools carefully. Too much information is a major problem with this type of tool. Choose some tools that can provide simple information, filter out invalid information, and provide convenient viewing of various views.
4. 2 Tools for quickly discovering required changes
If the unit test is valid, you can find out whether the change breaks other test cases by running the unit test. There are still relatively few unit tests that can effectively maintain and cover large enterprise applications. Here are some tools for this situation.
Here, there are still two techniques - static code analysis and runtime analysis - that can be used. There are many static code analysis tools available in the market. Such as: Lattix, Structure101, Coverity, nWire and IntelliJ's DSM.
For the 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, perhaps only MaintainJ. MaintainJ will first capture all classes and methods called in the 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 the 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 to double-check your judgment using the tools above.
5. Two pieces of advice on the above content
5. 1 Don’t reduce code quality
In order to deliver quickly, it is not necessary to fully understand the architecture, but it must not be conditional on reducing code quality. Here are some code quality issues you may have caused by focusing solely on fast delivery.
Since modifying the code involves many dependencies, adding new code is relatively less risky. For example, there are five 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 improved use case. Don't do this. Code redundancy is definitely very harmful. You have to try to wrap or rewrite the method, or even modify it directly, and then retest all use cases. It is usually a good 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, then it should be done.
Most applications have a certain structure and pattern to implement. When fixing or enhancing your program, you want to make sure you don't deviate from this pattern. If you're unsure about the protocol, ask other senior developers to review your changes. If you must do something that violates the specification, try to place it in a smaller class (a private function in a 200-line class 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 if you continue like this, you may stop having a deep understanding of the project architecture. This won't help your career in the long run. As your experience increases, you will take on larger module tasks. Such as building a complete new feature, or modifying some basic design of the project and other major improvements. When you are able to make these improvements, you should have a pretty good understanding of the overall architecture of the project. The methods listed in the article only allow you to improve yourself in the shortest possible time, but do not prevent you from fully understanding the entire project.
6. Conclusion
The focus of this entire article is to have the necessary understanding of the project and then deliver it quickly. You can do this without compromising code quality.
If you want to fix a bug, locate and fix it quickly. Runtime analysis tools can be used when necessary. If you want to add a new feature, you can look for similar features, understand the process (using tools if necessary) and write it.
Maybe this sounds simple, but is it practical? certainly. The premise is that you have good Java skills and a sufficient understanding of the framework, and then you can modify the code first and then analyze the impact of the changes. Analyzing the impact of a change requires more skill than implementing it. You may need a senior developer to assist you in analyzing the impact of the change.
Approximately 50% of the operational IT budget is spent on simple bug fixes and feature enhancements. The suggestions in this article should still be very helpful in saving money in maintenance activities.