'. '

ConfigurationObject

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(JavaBeans like Style)
Line 55: Line 55:
== [[JavaBean]]s like Style ==
== [[JavaBean]]s like Style ==
 +
[[JavaBean]] specification is popular in [[Java]] and using some familiar patterns (in this case [[GettersAndSetters]]) when designing own [[API]] will increase the [[time to market]] and [[cluelessness]] of users of your [[API]]. The [[JavaBean]] style for the above example would look like:
 +
 +
<source lang="java">
 +
public final class UpperConfig {
 +
private String text;
 +
private boolean firstLetterOnly;
 +
public void setText(String text) {
 +
this.text = text;
 +
}
 +
public String getText() {
 +
return text;
 +
}
 +
public void setFirstLetterOnly(boolean f) {
 +
this.firstLetterOnly = f;
 +
}
 +
public boolean isFirstLetterOnly() {
 +
return firstLetterOnly;
 +
}
 +
}
 +
public final class Upper {
 +
private Upper() {}
 +
public static String upper(UpperConfig c) {
 +
if (c.isFirstLetterOnly()) {
 +
return c.getText().substring(0, 1).toUpperCase() + c.getText().substring(1);
 +
}
 +
return c.getText().toUpperCase();
 +
}
 +
</source>

Revision as of 11:03, 22 February 2015

ConfigurationObject pattern is often used by JavaScript libraries to deal with evolution in a manageable way. While TheAPIBook advocates getting ready for the fact that first version of any API is never perfect, people keep repeating the same design mistake again and again: optimistically ignore the need for evolution! Usual history of an API starts with introducing function with one argument:

function upper(text) {
  return text.toUpperCase();
}
upper("Hello World!") === "HELLO WORLD!" || error();

then one finds an additional argument is needed:

function upper(text, firstLetterOnly) {
  if (firstLetterOnly) {
    return text.substring(0, 1).toUpperCase() + text.substring(1);
  }
  return text.toUpperCase();
}
upper("hello world!") === "HELLO WORLD!" || error();
upper("hello world!", true) === "Hello world!" || error();

and later another one, and another and so on, until one realizes the whole API is total mess and it is time to switch to ConfigurationObject design pattern:

function upper(data, firstLetterOnly) {
  if (typeof data === "string") {
      data = {
          "text" : data,
          "firstLetterOnly" : firstLetterOnly
      };
  }
  if (data.firstLetterOnly) {
    return data.text.substring(0, 1).toUpperCase() + data.text.substring(1);
  }
  return data.text.toUpperCase();
}
upper({ 
  "text" : "hello world!"
}) === "HELLO WORLD!" || error();
upper({ 
  "text" : "hello world!",
  "firstLetterOnly" : false
}) === "HELLO WORLD!" || error();
upper({ 
  "text" : "hello world!",
  "firstLetterOnly" : true
}) === "Hello world!" || error();

Adding named parameters is more easily evolvable. Moreover it is certainly easier to use ten named arguments than a function with ten parameters. No surprise the ConfigurationObject becomes more and more popular in many JavaScript libraries.

Now let's take a Java view. DukeScript (a way to use HTML from Java) is all about Java and JavaScript co-operation. To prevent reinventing the wheel the core of DukeScript ecosystem is built around wrapping JavaScript libraries with type-safe Java APIs. As ConfigurationObject is becoming more frequent, it is more and more important to find proper realization of such API in Java. Let's discuss the options.

JavaBeans like Style

JavaBean specification is popular in Java and using some familiar patterns (in this case GettersAndSetters) when designing own API will increase the time to market and cluelessness of users of your API. The JavaBean style for the above example would look like:

public final class UpperConfig {
  private String text;
  private boolean firstLetterOnly;
  public void setText(String text) {
    this.text = text;
  }
  public String getText() {
    return text;
  }
  public void setFirstLetterOnly(boolean f) {
    this.firstLetterOnly = f;
  }
  public boolean isFirstLetterOnly() {
    return firstLetterOnly;
  }
}
public final class Upper {
  private Upper() {}
  public static String upper(UpperConfig c) {
    if (c.isFirstLetterOnly()) {
      return c.getText().substring(0, 1).toUpperCase() + c.getText().substring(1);
    }
    return c.getText().toUpperCase();
  }
Personal tools
buy