Sunday, March 18, 2012

Eclipse Open Declaration has usability issue with upcast variables


By Mahmoud M.Orabi

Introduction:
When using Eclipse for Java development, we need to go through each method declaration at some points to see the implementation for these methods. Eclipse has several usability advantages with quick key strokes and proper hierarchy when navigating between super types. However, it is not that usable when it comes to the upcast variables delectation, as in all cases it will take us to the interface or abstract method definition

Pre-Requirements:
Download and use any eclipse with Java support from Eclipse website at: http://www.eclipse.org/downloads/

Scenario Preparation:
Start a new Java project from File/New, and name it “org.usability.show”.
 
Create an interface ILogger, which is implemented by an AbstractLogger. And this abstract logger is extended by a Logger class. Finally, there is ExtendedLogger that extends Logger
The class implementations would be as follows:

ILogger:
public interface ILogger {
      public void start();
      public void end();
      public void log(String... args);
}

AbstractLogger:

public abstract class AbstractLogger implements ILogger {
     
      private boolean started= false;
      private boolean done= false;
     
      public AbstractLogger() {
            this.started= false;
            this.done= false;
      }
     
      public void start() {
            this.started= true;
      }
     
      public void end() {
            this.done= true;
      }
     
      public boolean isStarted(){
            return this.started;
      }
     
      public boolean isDone(){
            return this.done;
      }

      public void log(String... args) {
            System.out.println(args);
      }
}

Logger:
public class Logger extends AbstractLogger {

      public void log(String... args) {
            System.out.println("Start Logging");
            super.log(args);
      }
}

ExtendedLogger:
public class ExtendedLogger extends Logger {

      public void log(String... args) {
            System.out.println("My extended Logger");
            super.log(args);
      }
}

And then create a static class that uses your methods. Let's name it LoggerTest:
public class LoggerTest {
      public static void main(String[] args) {
            ILogger myLogger= new Logger();
            myLogger.log("Log1", "TesTLog");
           
            doLog(myLogger);
            doLog(new ExtendedLogger());
      }
     
      public static void doLog(ILogger logger){
            logger.log("This is a test");
      }
}

Usability testing Scenario:

- Open LoggerTest class.
- Right click on the method called “myLogger.log”, and choose Open Declaration:
 
- This will take us to ILogger definition, which is just a definition with now implementation:
 
However, in my definition, I created an instance of “Logger,” but my upcast variable was an “ILogger”, so Eclipse will assume that we will open the declaration for ILogger – not the Logger – even if my instance is an instance of Logger.

Expected Usability Result:
When I need to navigate to “myLogger.log” declaration, I would like to get navigated to the Logger#log method declaration:
 
 



Challenges to apply the required usability changes:
This can be easily implemented if the variable is defined at the scope of the method. For instance, in the pre-mentioned example, the ILogger instance was defined in the same scope, so we can  track its required level of abstraction from that point.
This will more difficult if the instance is defined from a different scope. For example, if we receive the value as an argument for a method. For example:
public void doLog(ILogger logger){
      logger.log("This is a test");
}

In such place, this will make it difficult to determine where to exactly go. This method can be used and have any kind of ILogger passed.
For this, there could be two recommendations:

1) Prompt the user where to go:
For our example, the user will get prompted for choices: Logger, AbstractLogger, and ILogger. At  least we can decide which one to go to. For now, the workaround to do that is to accept that we will go to ILogger, and then show its call hierarchy, and see which classes are using it. However, this way is not that usable, as it will lead us to too many clicks. With the proposed solution, we will only need to choose which class to navigate to.

2) Better handling during Debugging session:
When debugging,and stepping into that method, we shall be able to hold the real-time instance for that objects. When we choose open declaration, the Eclipse must be smart enough to open the declaration for the active instance.
 
So, eclipse already has the required information on the logger instance class. So, when trying to open the declaration for logger#log, we must go to Logger#log definition.
And for example such as follows:
 
We will be interested in opening the declaration for ExtendedLogger#log method in that case. 

Conclusion:
Eclipse “Open Declaration” is one of the commonly used features in Eclipse. However, we have usability issues when it comes to interface-oriented programming or abstraction. We are not able to open the delectation of the actual object method declarations, which makes it hard  for several occasions, especially when you are debugging.

No comments:

Post a Comment