Object Commando languages, development and design

12Feb/094

Clean Code By Robert Martin – Part 1

I'm just started reading through Clean Code by Robert C. Martin. It's a book on writing good software at a low level. Things like how to name variables, how methods should look etc. His examples have been in Java, but the concepts are very general. I like what he has to say in the book and I agree with a lot of what he says. I have some comments on things I found interesting below.

Switch Statements

He shares a dislike for switch statements like I do. He gave the rather typical refactoring scenario of changing the switch code to be more object oriented through an Abstract Factory and Polymorphism. The example code he gave was:


public Money calculatePay(Employee e) throws InvalidEmployeeType {
  switch (e.type) {
    case COMMISSIONED:
      return calculateCommissionedPay(e);
    case HOURLY:
      return calculateHourlyPay(e);
    case SALARIED:
      return calculateSalariedPay(e);
    default:
      throw new InvalidEmployeeType(e.type);
  }
}

This is a pretty text book refactor to an Abstract Factory. Create a polymorphic method like "caluclatePay()" and have the employee subclasses provide their implementation of it. In the book he discusses burying that code deeper in the stack. In the Enterprise Java world, I find myself puting that logic into Hibernate. In this case, the Employee has a type, COMMISSIONED, HOURLY and SALARIED. Typically what I do is have the Employee become abstract and in the Hibernate mapping, indicate the descriminator as maybe "employeeType". Then I map all three employee types as their own subclass of employee (maybe using single table inheritence). I end up with three more classes CommisionedEmployee, HourlyEmployee and SalariedEmployee, but they should probably be pretty small classes. With this set up Hibernate does the dirty work previously done by the Abstract Factory described in Clean Code.

How to Name Your Interfaces

This always seems to be a hot button issues. I'm not entirely sure why. There is the more straightforward case of several up front implementations of an interface. For example in a bank scenario, you have Account and implementers of Account are maybe SavingsAccount, CheckingAccount etc. What seems to cause controversy is when initially there is only one implementation. As an example, maybe there is an Account Service. In Clean Code, the suggestion is having AccountService and then AccountServiceImpl. As a nice counter example, in Implementation Patterns by Kent Beck, I remember him taking the approach of IAccountService and AccountService. In general, I have found fierce opposition to prefixing interfaces with I. My personal preference is, if it can be named differently (such as Account above) it should be, if there's only one, I prefer Kent Beck's approach. To me, it seems like Impl is redundant and doesn't tell me much. Every implementation of the interface is an "impl". However, I have found that there are far more pressing issues in the code than whether or not to have Impl on the end of a class name.

Comments

After reading through the chapter on comments and giving it some thought, I agree with a lot of what he has to say. One quote in particular at first struck me as odd, "The proper use of comments is to compensate for our failure to express ourself in code. Note that I used the word failure. I meant it. Comments are always failures. " But when I thought about it, it made a lot of sense. The code is what matters, it's what is executed and in the end, comments are just decoration. We know the code has to be up to date, the comments are questionable. If I'm putting comments in to help understand the code, then the code is not very understandable on it's own, and I should work to make it better. Several times he mentions that when too many comments appear, or the same comment appears too frequently, we automatically block it out. I agree with this and I find myself blocking out most comments most of the time. I think the reason why these noisy or redundant comments make their way into the code because of a culture of comments. Early on, we are taught that comments are good and we should write them. So when a code review happens, and there's no comments on the methods of a class, there's usually a "oh, there should be a comment here" response. It usually has nothing to do with the actual method and most of the time (myself included), we don't ask, why there should be a comment there. Is it because the method name isn't intention revealing? Is the parameter or return type ambiguous?

Filed under: Best Practices 4 Comments
3Feb/090

Maven and Ivy

Recently I have been working a lot with Maven. The shop I'm working in now is mostly Maven, but previously I had used Ant and Ivy. To be honest, I'm not that big of a fan of either. I think that Ant is far too verbose, and it's too difficult to write good build files that are reusable. I don't like Maven much either. It seems to do most of what I want, but that last piece of what I want it to do seems to be a very long road. It also seems to have many bugs and is very low on documentation.  Maybe sometime soon Gradle will come to the rescue.  For this post though, I'm ignoring the build/deploy portions of Maven and am focusing on dependency management.  I'll discuss some of my favorite features of Ivy and Maven dependency management.

latest.integration

Ivy has the concept of latest.SOMETHING in your Ivy config. This basically says find the latest version with the tag SOMETHING. So this could be "latest.integration" which would pull whatever the latest version of a library is. Now at first this seems like the SNAPSHOT concept in Maven, but this is very different. First, you're not relying on 2.0.0-SNAPSHOT, it can be any version of the library. Another difference is when the link to the latest version of the library happens. In Maven, when you rely upon the SNAPSHOT build, that build can change because the artifact that is produced in the build has a relationship to the SNAPSHOT. In Ivy, once the build artifact is created, latest.integration changes to an actual version. So what I've done in the past is just increment a version number, so assume version 123 is the latest version of library B and I'm going to build version 22 of library A.  In program A's Ivy file, I indicate I want latest.integration version of B.  Now, when I build verison 22 of library A, the artifact that is created has a dependency on version 123 of library B.  So let's say several new versions of library B come out, but library A stays at version 22.  When program C depends on library A, it will automatically get version 123 of library B.

"latest.integration" is good for early development of a library, but not the greatest long term strategy. The integration part of this can be changed for other configurations. I have also created milestone builds that tended to be more stable, users of the library simply needed to use latest.milestone. With this, whatever build is the latest version with the milestone tag is pulled in.

Dependency Math

Maven never seems to pick the version of the library I want it to pick if there is a conflict. I know the algorithm pulls the version of the software that is in the "nearest" pom.xml.  In many situations, I find that this isn't what I want.  Ivy approaches this differently.  By default, it resolves conflict by picking the latest version number.  Although there can be problems with this approach, it seems that the Maven solution to the problem caused me a lot more grief.  Although I've not needed it, I thought it was interesting that Ivy allows other conflict resolution strategies.

Module Configurations

Another nice feature of Ivy is being able to define configurations for the modules. Basically this lets the publisher of modules define different dependencies based on configuration settings.  Examples of this would be having a library that supports more than one XML parser. Maybe there's a version that uses basic dom4j and another that supports a higher level framework.  As a user of the library, I would indicate a dependency on that module, with the "dom4j" configuration (this can be named anything).  These configurations are published as part of the ivy module definition and the user of the library doesn't need to know anything about the internals of the library or it's dependencies.  To do this in Maven, the only way that I know how, is to explicitly exclude the libraries that I don't want. This is less than ideal, because now the user of the library needs to know internal details of the library.  How do I know which dependencies to exclude?  Will it work if I exclude dependency X?

Central Repository

Although the central Maven repository can cause issues from time to time, it still saves a lot of time over Ivy. Ivy does have the ability to pull dependencies from the central Maven repository (it converts the Maven metadata to something Ivy can use), but I have not used it. Usually what I have done is create an enterprise repository and just populate everything in there that is needed there by hand (see below).

Repository Administrator UIs

This is something I frequently found myself wanting in the Ivy world. There are artifact administrator UIs in the Maven world, such as Nexus that make maintenance of the repository very easy. You can do things like proxy remote repositories such as the maven central repository, and it's easy to upload an artifact into a local repository. The initial setup and the on-going maintenance of an Ivy repository is probably the most painful aspect of Ivy.  It's all done by hand, without any slick web based tools and the files are stored in a normal file system hierarchy, which means no (easy) searching, like you would get with a Nexus type of UI.

Tagged as: , No Comments