Tips to Developers Starting on Large Applications
Let's assume that you are a Java developer who just started working on a large Java application which comprises of 2000 classes and uses multiple frameworks. How would you go about understanding the code base? In a typical enterprise Java team, most of the senior developers who can help you are likely to be quite busy. Documentation will be sparse. You will need to quickly deliver and prove yourself to the team. How would you resolve such a situation? This article offers some suggestions to Java developers starting on a new project.
1. Don't try to understand the whole application
Let me ask you this - why do you want to understand the code in the first place? Most probably you are asked to fix a bug or to enhance an existing feature of the application. The first thing you should not do is trying to understand the whole application architecture. When starting afresh on a project, this approach can be quite overwhelming.
Even Senior Java developers with more than 10 years of solid coding experience may not understand the working of certain parts of the application despite being on the same project for more than a year (assuming they are not the original developers). They may be happily oblivious to the authentication mechanism or the transaction management aspects of the application, for example.
Then how do they manage? They just understand the areas of the application they are working on very well and make sure that they deliver value to the team. Delivering value today is more important than spending time on understanding something that may or may not help you later.
2. Focus on delivering immediate value
So am I discouraging you from understanding the application architecture? No, not at all. All I am asking you is to deliver value early. Once you start on a project and once you have set up the development environment on your PC, you should not take more than a week or two to deliver something, however small it may be. If you are an experienced programmer and don’t deliver anything after 2 weeks, how would a manager know if you really working or reading sports news?
As weeks go by and after you have delivered a few fixes and enhancements, you would start to slowly understand the architecture. Do not underestimate the time needed to understand each aspect of the application. Give yourself 3 to 4 days to understand the authentication mechanism and maybe 2-3 days to understand the transaction management. It really depends on the application and your prior experience on similar applications, but the key is to take the time to understand something thoroughly. Steal the time in between fixing the defects. Do not ask the manager for that time.
Find out if the application has any well maintained unit test cases. When available, unit test cases are a good way to understand large code bases. Unit tests help to start at the smallest pieces of the code base and to understand both the external interfaces of the units (how a unit should be called and what it should return) and their internal implementation (debugging unit test cases are much simpler than debugging an entire use case).
When you understand something well, write notes or draw the class, sequence and data model diagrams. They will help you and your peer developers.
3. Important skills required to maintain large applications
If you are hired for the job, you must already be having good Java skills. Let me talk about the other skills that will help you to perform well on a new project. Most of the time, your tasks on the project will involve either bug fixing or enhancing the application.
There are two important skills that will help you in maintaining large code bases.
3.1 Being able to quickly find the classes of interest
For any kind of maintenance activity, whether it is a bug fix or enhancement, the first task is to identify the classes called in the use case that you are fixing or enhancing. Once you have identified the classes and/or methods to fix or enhance, half the work is done.
3.2 Being able to analyze the impact of a change
After you make the necessary changes to fix a defect or enhance a feature, the most important thing is to ensure that your change does not break any other part of the code. You need to use your Java language skills in tandem with your knowledge of other frameworks to figure out what could be impacted by your change. Below are two simple examples to elaborate the last statement:
- a) When equals() method of class A is changed, calls to contains() method on the lists that contain instances of A will be affected. Unless someone knows Java well, they might not be able to guess this.
- b) In a web application, let us assume that the 'user id' is stored in session. A newbie programmer might append something to the 'user id' as part of a bug fix without knowing that it will impact other use cases that depend on the 'user id'.
So, it is imperative that you know both the Java language and the frameworks used in the application well enough to analyze the impact of a change.
Once you develop the above two skills, most of the maintenance tasks will become easier even when you do not know much about the application. If you are fixing a bug, you will first find the location of the bug, fix it and make sure that it does not break the rest of the application. If you need to enhance a feature or add a new feature, most of the time, you just need to imitate an existing feature that follows similar design.
For instance, in an online banking application, why would the design for 'View Account Summary' and 'View Transaction History' differ greatly? If you understand the design of 'View Account Summary', you can just imitate it to develop 'View Transaction History'.
The bottom line is you don’t need to understand what all the 2000 classes are doing or how the application plumbing code works to fix a bug or enhance the application. If you have the above skills, you can quickly locate parts of the code that you need to change, change it with your Java and frameworks skills, ensure that your changes don't break other parts of the application and deliver your changes, even with minimal knowledge of the application design.
4. Tools to find what to change and to find the impact of a change
Continuing with our theme of delivering immediate value, you should look for tools that help you to deliver immediate value by learning barely enough about the application.
4.1 Tools to quickly find what to change
Whether you are fixing a bug or enhancing a feature, your first task is to find out the classes and methods called for the use case that you need to fix or enhance.There are basically two approaches to understand how a use case works - static source code analysis and runtime analysis.
Source code analysis tools scan the entire code base and show the relations between the classes. There are many source code analysis techniques and tools in the market. A few examples of these tools are: Architexa, AgileJ, UModel, Poseidon, etc.
All these tools use static time code analysis and suffer from the fact that it is impossible to exactly determine the classes and methods called at run time in a use case. The reasons for this are late binding in Java, callback patterns, etc. For instance, the static analysis tools can never infer which Servlet will be called when the Submit button is clicked on a page.
Runtime analysis tools can exactly determine the classes and methods called in a use case at runtime. Some examples of these tools are: MaintainJ, Diver, jSonde, Java Call Tracer,etc. These tools typically capture the call trace at runtime and use that information to generate sequence and class diagrams for a single use case.
The sequence diagrams show all the methods called at runtime for that use case. So, if you are fixing a bug, the bug will most probably be in one of those methods called.
If you are enhancing an existing feature, understand the call flow of that feature using the sequence diagram and then enhance it. The enhancement may be like adding a new validation, changing the DAO, etc.
If you are adding a new feature, find some other feature similar to what you need to develop, understand the call flow of that feature using the runtime sequence diagrams and then imitate it to develop the new feature.
Choose the runtime analysis tools carefully, though. Verboseness is the primary problem with these tools. Choose the tool that offers ways to easily filter out unwanted details and allow you to read and understand the diagrams easily.
4.2 Tools to find the impact of a change
If unit test cases are available, they should be run first to find out if the code changes you made break any other test cases. You may not often find well maintained unit tests that cover most parts of the code for large enterprise applications. Below are some tools and techniques that can be used in such situations.
Again, the two techniques that can be used are static time source code analysis and runtime analysis. There are many static analysis tools available in the market. Some examples are: Lattix, Structure101, Coverity, nWire and IntelliJ's DSM.
Given a class that is changed, all the above tools identify a set of classes that depend on it using static time code analysis. With this information, programmers have to 'guess' the impacted use cases because these tools cannot determine the classes actually called in a use case at runtime.
There are not many tools available in the market that can perform runtime Impact Analysis, except for MaintainJ. MaintainJ first captures all the classes and method called in a use case. Once this information is captured for all use cases, one can easily find the use cases impacted by changes to a set of classes. The precondition for MaintainJ's solution to work is that all the use cases of the application should be run first to capture the runtime dependencies.
All said, currently, you have limited help from tools to quickly and accurately analyze the impact of a change. First recognize the need to conduct proper impact analysis and then depend on your judgement or of other senior members of the team to determine the impact of a change. You might use the above mentioned tools to cross-check your judgement.
5. Two caveats to my argument above
5.1 Do not compromise on code quality
Just because you are delivering quickly without understanding the entire application architecture, you should not compromise on code quality. Below are a few examples where you may be tempted to compromise on code quality for a quick delivery.
Adding new code is usually less risky than changing the existing code that has many dependencies. For example, there may be a method that is called in five use cases. As part of enhancing one of the use cases, you might have to change the implementation of that method. The easiest thing to do might be to copy that method, rename it and call it in the use case you are enhancing. Do not ever do that. Code duplication is bad and there are no two ways about it. Check if you can build a wrapper to that method or override that method or just change it and retest all use cases. Usually, if you stop, think and really apply yourself, there will be a better way.
Another example is changing a 'private' method to 'public' so that it can be called from another class. It is always bad to expose more than what you must. If you need to do a bit of refactoring to put forth a better design, just get on with it.
Most applications have certain structure and patterns of doing things. While fixing or enhancing the application, make sure that you do not deviate from these patterns. If in doubt whether you are confirming to the conventions, ask a senior developer to review your changes. If you must do something that does not follow the conventions, at least ensure that it is local to a small class (a private method in a small class of 200 lines may not ruin the application’s design).
5.2 Do not stop making an effort to understand the architecture
By following the approach outlined in this article, if you are able to deliver by learning barely enough and survive in the industry, you might stop making an effort to understand the application architecture. Doing so will not help your career in the long run. This can be avoided by working on bigger tasks as your experience increases on the project. There will be larger enhancements like building an entirely new feature or a change that affects the fundamental design of the application. By the time you are attempting such changes, you should understand the application architecture reasonably well. The approach illustrated in this article is designed to get you up to speed and help you deliver in minimal time and not to dissuade you from comprehensively understanding the application.
The whole point of this article is to focus on delivering value quickly by learning just enough about the application. You can do that without compromising the code quality.
If you are fixing a bug, quickly find the location of the bug and fix it. Use the runtime analysis tools to locate the bug if necessary. If you are adding a new feature, find a similar feature, understand its call flow (using the tools if necessary) and enhance.
You might say it all sounds to simple, but is it really practical? Yes, it is. But the pre-condition is that you have good Java language skills and know the frameworks well enough to first make the code change and then to analyze the impact of that change. Better skills are required to analyze the impact of a change than to actually make the change. You might seek the help of a senior developer to analyze the impact.
About 50% of IT operational budgets go toward simple bug fixing and enhancements. By following the approach suggested in this article, it is possible to save a considerable amount of money, spent on such maintenance activities.
Disclaimer: Choudary Kothapalli, the author of this article, is also the founder of MaintainJ, one of the products mentioned in this article.
About the Author
Choudary Kothapalli is the founder of MaintainJ Inc., the company that builds tools to reduce the costs of maintaining large Java applications. He has over 15 years of experience in developing and maintaining enterprise Java applications. He is a Sun Certified Enterprise Architect and Java Programmer. He lives with his wife and two sons in Toronto, Canada.
Ask ask ask
First, ask them to describe the context of the first work you got to do: why, how, what are the reasons, etc...
Then take the time to study the code, invent one or two possible solution(s) but do not actually code it. Just ask: find a colleague with enough experience and motivation and take his time: he'll prefer you take one hour of his time rather than have you write bad code or duplicated code or code having bad consequences on the whole app.
After you have coded, just ask again this colleague to review your code.
By asking the right people, you'll soon know every single tip on the project: they'll help you use the right tools, will explain you why you have to do like this or like that. They'll be happy to share the knowledge they earned through hard work, it will spare you precious time, will help you understand the weigh of legacy code and the reasoning behind strange looking code.
In a word: ASK ! ;)
Re: Ask ask ask
I agree that I didn't emphasize it enough, but that is because I started the article with the assumption that the senior developers who can help are likely to be quite busy. I agree that when available, they are better sources of information than any documentation or tools.
But in real life, one would face one of these 2 scenarios:
a) Ideal scenario - The other developers are knowledgeable, friendly, ready to help, but busy
As a new developer on a large project, one would need lot of help to set up the machine and the application on the local machine. In spite of the set up document, there will just be many places where one might go wrong and the new developer will be using up lot of 'goodwill capital' if I can use that word. So it would be better to minimize the number of times a new developer goes asking for help if that can be avoided.
b) Hostile scenario - Some projects are just messy. The code can be very complex for a number of reasons and the team's morale might not be very good. In such teams, it can be difficult to get help. The best option might be to get out of the project if possible :), but it real life that might not be an option.
As a whole, I agree that asking for help is the first thing a new developer should try to do. I did mention in my article that when in doubt of the impact of a change made, the new developer should consult the experienced developers in the team. But the tips and the tools suggested should help to minimize the requests for help.
Thanks for your great job
this is the chinese version of this artical.www.blogjava.net/matuobasyouca/archive/2012/03/...
Re: Ask ask ask
Re: Ask ask ask
On another project, the design was very complex. There were very strong and senior developers on the team. But they were very busy to help the developers starting on the project. Moreover, it was difficult to convey all the design principles in the short time they were able to spare.
Best way to understand your code
The tool is so efficient I now (by myself) conduct maintenance on around 15 existing applications, add new features to each app as needed, analyse business needs, gather requirements for new projects and build a few new web apps each year. Right now I’m building a enterprise level contract management system that integrates with Microsoft CRM.
So I think the best way to understand a large scale application is to use the best development environment on the market. Visual Studio 2010. It just keeps getting better and better.