Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

2011-09-04

Concise code

This subject has been bothering me for a long time. So I decided to collect my arguments in single place, here.
I insist on that good code is concise code (but not necessarily otherwise, to be precise). Objections to this that I heard most often so far are
1. The code is being read more times than it is written. Denser code is hard to read.
2. The code is for human beings and that is why it should be clear. Denser code is harder to read.
3. Copy-past is not bad since in future requirements may change and then copied parts would naturally diverge. Extra code in the project is just extra code - it sits there and costs nothing.

And all of them ARE WRONG.
Yes code is being read more often than it is written. And that is why short code matters. There are numerous observations that human brain can manipulate by limited number of symbols at a time. If you present whole program in a way that brain can grasp at once you get a bonus understanding what is going on here. This is instead of working as meat-based decompiler trying to understand pieces of system, then trying to put pieces together, then trying to understand how this system works as a whole. By writing program that fits in your brain you turn computer into your friend that has interface compatible with you. This is surprising how may program systems where not even one developer understands. Developers working on them just get used to navigating symbol browsers in their IDE without even trying to understand parts of code that are not directly related to task at hand.
Yes code is being read more often than it is written. To an extent. New code almost always needs refactoring as requirements and more appropriate designs become more apparent. The less code is there the more chances rewriting it would be feasible the better chances design would be sound in future. In that very future rewrite is often impossible. So keeping code compact is one of ways to better software. I have seen developers who were reluctant to rewrite code that was first written yesterday even though every one understand that rewrite would significantly decrease complexity. You see? Even yesterday's code might be already too old for rewrite.
Every middle or large size project I participated in contained many hundreds or even thousands lines of unnecessary code. Worse then it's redundancy is often not apparent since only some parts of it have textual similarity. You need time to understand that this large chunk of code is completely unnecessary.
And anyone who will dig this code will have to expend an effort to understand these parts of code. One have to understand code before changing it, right? Instead of immediately seeing that this and that parts of system are essentially the same thing with minor tweak in the middle that is passed as parameter, I have to work as overpaid diff program that scans two large chunks of code for that single dot that is in different place. And after finally finding it still wondering if it is bug introduced by sloppy maintenance or a deliberate change in functionality. This is part of increased support cost due to unnecessary code. Unnecessary  code is not jut sitting there on a hard drive and bothers no one. Instead it constantly sucks team's time and energy to support it.

They say that when requirements change those copy-pasted pieces can be changed separately. The problem is that you never know how those requirement will change. And there is big chance at least, say 50%, that requirements will change in a way that would require both of those pieces. And the large project the higher chances that required changes will be cross-cutting. You ain't gonna need it.

Yes, in less denser code it is easier to understand one isolated line of code. But is there a point in understanding line "i++;" or "}"? Is there a point in understanding separate lines of code if  you still do not understand what is going on? You need to understand what the program is doing if not as whole but at least a substantial piece of it. Yes in denser code you probably need some times more mental effort to understand it but is it a problem since you need in proportion less lines of code that does the same thing? And remember that you will have better chances to understand and maintain the code.

I have one more observation related to good design. To write concise code you have to understand deeply what your program should do. And this is only way to do it. Often people who unconsciously equate boated code to more approachable one imagine some big system written as 1 megabyte regexp as example of brief code. No you cannot do that. At most you could cram what you have into a few percent less lines of code indeed impairing readability. To have better code one should understand it.

Several years I have been working with Java. And there is one thing that is related to it. Some tools (programming languages)  just do not have adequate means for code structuring. Often trying to implement in Java approaches that reduce code significantly in other languages lead to more bloated code. Java just resist being concise. So it is not just about design.

One last piece is somehow related to Java is use of design patterns. As any good idea that gets into popular culture (popular programming culture in this case) it becomes a parody on itself. I find this gem by Sarah A. Sheard to be most memorable text on the subject. They forget that every pattern has not only benefits but also an area of applicability and drawbacks. So one have to ponder if code would be better if  a pattern is applied. They think instead that the more patterns used the better. They forget that patterns is not something devised by demigods and given to us mortals to be unquestioningly used. Patterns are extracted from real systems. And ones system might need some pattern that is not in GoF bible. And the best way to extract relevant patterns is refactoring. Seeing how often patterns are overused is upsetting since most of them increase amount of code. How often have you seen factory is used where a plain constructor would suffice? Sigh.

2010-12-30

Do not do this, please: this instanceof

Since I do like refactoring I decided that I would document code patterns that I stumble upon.
Consider following code (Java). First snippet shows
It is uneasy for me to explain why this is not a good solution because it is so obvious to me. It's like explaining why anecdote is funny to someone who does not get it. But since I met such code in more than one project written by different people there must be something worth explaining.
First, look at better version of this code:
This rewrite eliminates runtime check, removes dependency of base class on it's subclasses and removes temptation of junior developers who will modify this code after you to insert more insanceof checks in same method. And after all, in Java subclassing is language's idiomatic way do do such things.
I have written what wanted on this case but it is hard to me to stop here, so I continue.
If I would do refactoring I would stop after this rewrite. But looking at the methods I would scent that something else needs improvement: call to "bark" suggests that it belongs not to absrtact animal but to a dog. So if indeed we have only two subclasses Cat and Dog, I would further rewrite the code as:
I would advocate using composition over subclassing if everything else is equal. So if after these changes there's no real code left in Animal I would convert it to interface:
They tell me "ship it" and here I stop.

2010-02-17

Stream close template.

I wanted to DRY my Java code by introducing common code for patterns like this:
InputStream input = new FileInputStream(file);
try {
  doSomethingWithStream(input);
} finally {
  if (null != input) input.close();
}
So I had two approaches to try out both having two functions: one for opening stream, other for doing actual work. First solution was with template utility function that accepts 2 function-like objects, second one used template class.

Code for first approach looks like following:
interface Ctor {
  A get();
}
interface F {
  void put(A arg);
}

class Utils {
  static  void withCloseable(Ctor streamConstructor, F block) throws IOException {
    C c = null;
    try {
      c = streamConstructor.get();
      block.put(c);
    } finally {
      if (c != null)
        c.close();
    }
  }
Use case might look like this:
Utils.withCloseable(
  new Ctor() {
    InputStram get() { 
      return new FileInputStream(file);
    }
  }, 
  new F(InputStream in) {
      doSomethingWithStream(in); // Whatever
  }
);
Second approach that uses template class expects used to extend class to provie necessary methods:
abstract class WithCloseable {
  protected abstract C open() throws IOException;
  protected abstract void runWith(C c) throws IOException;

  public T exec() throws IOException {
    C c = null;
    try {
      c = open();
      runWith(c);
    } finally {
      if (c != null)
        c.close();
    }
  }
} 


Alas, while both approaches allow to make closing streams more regular they also made the code look involved and bloated. The situation only worsened when I tried to modify the code to it returns value from function that works with stream or try to nest several templates if I want to work with more than stream (for example, one for input other for output).


It is frustrating to watch every time how Java resist being more consice. I am looking forward for using Clojure or Scala in projects at my job I have no doubt that clojures if they ever appear in Java will be yet another half-solution made with compatibility as sole requirement (first one was generics).

2010-02-06

How to refresh resources in Eclipse's workspace

Since we add own file system implementation to EFS there's need to refresh different resources in workspace to provide better feedback to user.

Naive usage of IResource.refreshLocal(Monitor) caused cryptic exceptions a about conflicting rules. This for example happens when you first start refreshing a file and while it is processed you request to refresh it's folder. It took some time and several re-opened bugs in project I am working to figure out proper way to do refreshes. The fact that IResource also implements ISchedulingRule also adds to confusion. First problem-less implementation used Workspace.getRefreshManager().refresh(resource). Refresh manager maintains queue for refresh requests that run consequently so they do not conflict. Unfortunately Workspace is not part of public API so it lead me to look for other solutions. Parameter "monitor" in IResource.refreshLocal() lead me to inspect Job class that is used for long running background tasks. It turned out that Job has method Job.setRule(ISchedulingRule). So I created a job and set resource being refreshed as scheduling rule, this still caused refresh conflicts. So finally working code looks like this:
public static void refresh(final IResource resource) {
        final Job job = new Job("Refreshing " + resource) {
            @Override
            protected IStatus run(final IProgressMonitor monitor) {
                try {
                    resource.refreshLocal(IResource.DEPTH_INFINITE, monitor);
                    return new Status(IStatus.OK, "my.shiny.plugin", "Refreshed " + resource);
                } catch (final CoreException e) {
                    return new Status(IStatus.ERROR, "my.shiny.plugin", "Error refreshing "
                            + resource, e);
                }
            }
        };
        job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().refreshRule(resource));
        job.schedule();
    }
Last tar pit you might step into is names of rule factory. "createRule" returns rule for resource creation operation (although it worked in my case). The method that returns rule for refresh is "refreshRule".

On security

My VPS recently got banned for spam which surprised me since none of my soft there sending email. So my first thoughts were that this is a...