Showing posts with label planning. Show all posts
Showing posts with label planning. Show all posts

Monday, March 19, 2007

Refactoring or Redesign?

If you ever worked on a software that has grown organically over time, you will agree that many candidates for refactoring can be found in it. These are identified as pain points, smells or simply things that suck. The reason is that as the software grows, requirements change and code needs to adapt in order to support these changes.

JIRA is not an exception. JIRA team will spend around 30 hours in each eight week release cycle on refactoring of existing code, improving design, making it easier to extend the current code base with new features. At the iteration planning meeting last week, my colleagues and I were discussing how to spend this time in the most efficient way, debating what is refactoring and what is not. One of my colleagues raised a question: "Is is refactoring or redesign?"

The answer is: "It's both."

According to The Pragmatic Programmer: From Journeyman to Master written by Andrew Hunt and David Thomas:

At its heart, refactoring is redesign. Anything that you or others on your team designed can be redesigned in light of new facts, deeper understandings, changing requirements, and so on. But if you proceed to rip up vast quantities of code with wild abandon, you may find yourself in a worse position that when you started.

Clearly, refactoring is an activity that needs to be undertaken slowly, deliberately, and carefully. Martin Fowler offers the following simple tips on how to refactor without doing more harm than good:

  1. Don't try to refactor and add functionality at the same time.
  2. Make sure you have good tests before you begin refactoring. Run the tests as often as possible. That way you will know quickly if your changes have broken anything.
  3. Take short, deliberate steps: move a field from one class to another, fuse two similar methods into a superclass. Refactoring often involves making many localized changes that result in a larger-scale change. If you keep your steps small, and test after each step, you will avoid prolonged debugging.

Thursday, February 22, 2007

Log4J Logger vs. Category

Logging is the practice of recording sequential data. This is also a low-tech method of debugging and in some cases also the only way as the proper debugging tools may not be always available or applicable. Logging in Java can range from simple System.out.println() statements to usage of sophisticated logging frameworks.

At the time of writing there are several logging frameworks for logging in Java available. There is a popular and probably the most widely used Log4J framework. Younger brother of Log4J is the Java's Logging API that became part of Java SE in version 1.4. See How does the Java logging API stack up against log4j for comparison. The are many other logging frameworks: SimpleLog, jLo, Protomatter Syslog, etc.

There are also several frameworks that enable abstraction from logging frameworks, also known as logging bridges (Apache Commons Logging, log-bridge). These allow switching between logging frameworks. These and many others can be found at Open Source Logging Tools in Java at java-source.net.

Log4J was one of the early logging frameworks that gained popularity and is present in many source code bases. In some cases you could encounter usage of Category class rather than Logger. If you work or worked on projects that are built on top of relatively young frameworks, you may not even know that Category class exists as its natural habitat is in old Java code. I hadn't known that Category class existed until I saw it one day. I saw it in a place where I would usually use Logger class. Since that day I kept reminding myself to look at it and see what's different from Logger class and why would one use it.

So what is the difference between Category and Logger classes? The Java documentation in Category class states

This class has been deprecated and replaced by the Logger subclass. It will be kept around to preserve backward compatibility until mid 2003.

Logger is a subclass of Category, i.e. it extends Category. In other words, a logger is a category. Thus, all operations that can be performed on a category can be performed on a logger. Internally, whenever log4j is asked to produce a Category object, it will instead produce a Logger object. Log4j 1.2 will never produce Category objects but only Logger instances. In order to preserve backward compatibility, methods that previously accepted category objects still continue to accept category objects.

Then the following example shows how Category was used and how Logger should be used.

// Deprecated form:
Category cat = Category.getInstance("foo.bar");

// Preferred form for retrieving loggers:
Logger logger = Logger.getLogger("foo.bar");

And that's it. That's all you have to do to replace Category with Logger (apart from renaming the variable).

The documentation also says

There is absolutely no need for new client code to use or refer to the Category class. Whenever possible, please avoid referring to it or using it.

Why is this important? The plan is that from Log4J version 1.3 Category class will be removed! What can we do to prepare our code for Log4J 1.3? Well Preparing for Log4J version 1.3 has it all spelled out. It's worth to read if you want to understand all implications this upgrade may have. I just shamelessly paste the steps here:

  1. Never refer to the Category class directly, refer to Logger instead.
  2. Do not invoke the deprecated Category.getRoot method. Invoke Logger.getRootLogger method instead.
  3. Do not invoke the deprecated Category.getInstance(String) method. Invoke Logger.getLogger(String) method instead.
  4. Do not invoke the deprecated Category.getInstance(Class) method. Invoke Logger.getLogger(Class) method instead.
  5. Never refer to the Priority class, refer to Level class instead.
  6. Do not invoke the deprecated Category.setPriority(Priority) method. Invoke Logger.setLevel(Level) method instead.
  7. Do not invoke the deprecated Priority.toPriority(int) method. Invoke Level.toLevel(int) method instead. The same holds true for the other variants of the Priority.toPriority method.
  8. Never refer to the deprecated Priority.FATAL, Priority.ERROR, Priority.WARN, Priority.INFO, Priority.DEBUG fields. Refer to the Level.FATAL, Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG fields instead.

  9. If you confiugure appenders programmatically, do not forget to invoke the activateOptions method of an appender after you have instantiated it and set its options.

and as the above mentioned document says

For 99.99% of users, this translates to the following string find-and-replace operations:
  1. Replace the string "Category.getInstance" with the string "Logger.getLogger".
  2. Replace the string "Category.getRoot" with the string "Logger.getRootLogger".
  3. Replace the string "Category" with the string "Logger".
  4. Replace the string "Priority" with the string "Level".

Happy logging!

Monday, May 01, 2006

Working on Tasks in XP

After we get the stories from the customer, the stories are broken down to tasks, the tasks are estimated. What happens next? Well, there are two ways to go about tasks during each iteration:

  1. Do tasks one at the time,
  2. Fill your bag.

One at the time

Description:
The developers pick up the task they would like to tackle. Then they work on it until it is done, then they take another task.

Advantages:
It does not create bottlenecks. When the task is finished, you take another one. If some pair gets stuck on one, the other tasks can still be going well. This approach also makes the pair focus on one task at the time.

Disadvantages:
The task estimate is a subject to change when somebody signs up for the task.

Fill your bag

Description:
Every pair signs up for tasks until their bag for the iteration is full. The tasks are assigned by some kind of auction where developers take ownership and estimate their tasks. It is usually those who took the story and broke it down into tasks.

Advantages:
The customer can have a better idea what will get done in the iteration and by whom. Developers can also have a sense of progress and a better sense of how all tasks fit into the story.

Disadvantages:
It can create a bottleneck. Some developers might get stuck on a task or can spend more time on it.


Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.