This blog post is the long-awaited, postponed twice, part of the mini series about Framework Design Principles.

A framework or library should make it really easy to write code. It should be obvious how the library can be used and how the functionality can be extended. Also, we should help our users save keystrokes by supporting the auto complete features of our IDEs. And we should make it easy to write testable code and to find errors in the resulting code.

Don't repeat yourself (DRY)

And by “yourself” I don’t mean “yourself” (the framework developer), I mean your users. That is: Allow your users to follow this principle - do not force them to repeat themselfs. For example, Ruby on Rails has several features that enable writing code without repeating stuff.

With other frameworks, DRY is very hard or even impossible. Take android for example. This is some content of a layout file for an activity:

myactivity.xml

<Button android:id="@+id/submitButton"/>

But wait! The id has to be unique across all activities, so better prefix it:

<Button android:id="@+id/myactivity_submitButton"/>

Now we repeated some information: That the button “submitButton” is part of the activity “myActivity”. When you write the Java class for this activity it gets worse. You have to tell the system that yes, the layout “myactivity.xml” is the layout for “MyActivity” and that the “Button” object with the name “submitButton” corresponds to the button with the id “submitButton” from the xml file:

MyActivity.java

setContentView(R.layout.myactivity);
Button submitButton =(Button)findViewById(R.id.myactivity_submitButton);

In a similar way, Apache Wicket forces you to repeat some information from the HTML files in the corresponding Java classes: You have to create the same components and the same structure in the Java class. This is one of the reasons why Oliver Szymanski and I started the JSXP project.

Auto Complete

Never underestimate how much help the auto complete feature of your IDE can be for your users - and how annoying it can be if your framework does not support it well.

Just try this in a Java IDE:

JButton button = new JButton();
button.set[Ctrl]+[Space]

(Or whatever your shortcut for auto complete is) You’ll get an endless list of methods without any way to sort or filter them. For example, from this list you can not filter the methods that only effect the view.

In one version of JSXP2 (my re-write of JSXP that is not publicly available) I have also created some code where auto complete does not really support you, as a user: In a view controller in JSXP, you can get all the components of the page that are definded in XML by their “jsxp:id”. But auto complete gives you this:

auto-complete example

Only the last suggestion here is relevant to what you want to do: “getElementLoginForm” is the first method here that returns an element from the HTML page. To get meaningful auto complete suggestions, you have to type “getElement” before. Later I tried to group these methods into a protected object, which works a little bit better: In this version, you can access the login from with el.loginForm();.

Finding Errors

Help your users to find or - even better - avoid errors. Let me start with a negative example again: In Apache Wicket, you have to match literal strings from the HTML file in your Java code: The “wicket:id”s from the HTML and the ids in Java must be the same. And the components must be nested in the same way.

And you can only find errors by starting the application - or unit tests with WicketTester. You should absolutely use WicketTester. So, yes, you can find these kinds of errors automatically. But the situation is still pretty bad:

  • It is really easy to produce these kinds of errors
  • You find out pretty late - only when running the program
  • There are a lot of "false positives": Changes that should be compatible but still cause this error, because the structure has changed a little bit.

The thing is: Many of us use a statically typed language. And this has some advantages [*], at least it should have. One of the advantages is that we know very much about a program during compile time. We should use this knowlege to detect errors early - And most of the time, this is not done, so I see a lot of wasted potential here.

The thing is: Actually, we don’t know anything about the program. The compiler does. So, if we can somehow phrase our expectations about the program in a way the compiler understands the compiler could make sure that our expectations are met. This is easier than you might think: The Java compiler understands Java, so we have to write about our expectations in Java. And to make sure the error is not caused by our expectations, we should generate this code.

I guess you think right now “an example would be really handy at this point”. Well, ok ;) The second reason Oliver and I wrote JSXP was to eliminate certain kinds of errors.

When you defined an element in the view (HTML file) you should be able to make sure that it is available in the controller (Java file). And when you change these files in an incompatible way, you get a compiler error. A code generator is responsible for bridging the gap between HTML and Java: From the HTML file we generate code that lets you access the elements in a checked, type safe way, by calling a method. When you change the HTML or the Java code in an incompatible way, the method call can not succeed, so the compiler shows you an error.

I think it’s time for some code, but not from JSXP but from another project where I experimented with this technique. resdroid is a project that tries to bring the concepts of JSXP to Android. It generates code to make sure all IDs are unique and to provide a compile-time-checked, type-safe way to access widgets within an activity. Check it out, but beware: It is just a proof of concept at the moment!

The activity from the example above would look like this when you use resdroid:

myactivity.activity.xml

<Button android:id="@+id/submitButton"/>

From this file, the resdroid generator creates the real activity layout file where all IDs are prefixed so the IDs are unique across your App. It also creates a base class for your activity, where the button is defined as a protected member of class “Button”. The layout file and the button are initialized correctly in “onCreate”, so after the super call you can rely on it being available. Your own activity class could then look like this:

MyActivity.java

@Override
public void onCreate(final Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	submitButton.setOnClickListener(this);
	...
}

Conclusion

Make writing software based on your library or framework easy for your users! Make sure they don’t have to repeat certain kinds of information. Think about auto complete when designing public interfaces. Make testing easy and make sure certain errors can not be made or detect them at compile time.

[*] And also several disadvantages, I know. But this is an entirely different topic. Maybe for another post.