Tuesday, April 3, 2012
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?
So, to make life easier for everyone, deliver something. Don’t go
with the attitude that you need to understand the whole application
before you can deliver something valuable. It’s a completely false
notion. Adding a small and localized Javascript validation may be very
valuable to the business and when you deliver it, the manager feels
relieved in that he is able to justify your contribution to the upper
management and showcasing employee value for the company’s money.
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.
6. Conclusion
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.
Subscribe to:
Posts (Atom)