Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Saturday, January 23, 2016

What is the appropriate way to plan for a Java API with new features over time?

What is the appropriate way to plan for a Java API with new features over time?


I'm working with a team on a new Java API for one of our internal projects. We probably won't be able to take the time to stop and hash out all the details of the Java interfaces and get them 100% perfect at the beginning.

We have some core features that have to be there up front, and others that are likely to be added later over time but aren't important now, + taking the time to design those features now is a luxury we don't have. Especially since we don't have enough information yet to get all the design details right.

The Java approach to APIs is that once you publish an interface, it's effectively immutable and you should never change it.

Is there a way to plan for API evolution over time? I've read this question and I suppose we could do this:

// first release  interface IDoSomething  {      public void hop();      public void skip();      public void jump();  }    // later  interface IDoSomething2 extends IDoSomething  {      public void waxFloor(Floor floor);      public void topDessert(Dessert dessert);  }    // later still  interface IDoSomething3 extends IDoSomething2  {      public void slice(Sliceable object);      public void dice(Diceable object);  }  

and then upgrade our classes from supporting IDoSomething to IDoSomething2 and then IDoSomething3, but this seems to have a code smell issue.

Then I guess there's the Guava way of marking interfaces with @Beta so applications can use these at risk, prior to being frozen, but I don't know if that's right either.

Answer by Lance Java for What is the appropriate way to plan for a Java API with new features over time?


You could take the approach that tapestry-5 has taken which it dubs "Adaptive API" (more info here).

Instead of locked down interfaces, tapestry uses annotations and pojo's. I'm not entirely sure of your circumstances but this may or may not be a good fit. Note that tapestry uses ASM (via plastic) under the hood so that there is no runtime reflection to achieve this.

Eg:

public class SomePojo {     @Slice     public void slice(Sliceable object) {        ...     }       @Dice     public void dice(Diceable object) {        ...     }  }    public class SomeOtherPojo {     @Slice     public void slice(Sliceable object) {        ...     }       @Hop     public void hop(Hoppable object) {        ...     }  }  

Answer by m3th0dman for What is the appropriate way to plan for a Java API with new features over time?


If you want flexible code generics can help.

For example, instead of:

interface FloorWaxer  {      public void waxFloor(Floor floor);  }  

You can have:

interface Waxer   {      void wax(T t);  }    class FloorWaxer implements Waxer   {      void wax(Floor floor);  }  

Also, Java 8 brought default methods in interfaces which allow you to add methods in already existing interfaces; with this in mind you can make you interfaces generic. This means you should make your interfaces as generic as possible; instead of:

interface Washer  {      void wash(T what);     }  

and then to later add

interface Washer  {      void wash(T what);         void wash(T what, WashSubstance washSubstance);   }  

and later add

interface Washer  {      void wash(T what);         void wash(T what, WashSubstance washSubstance);       void wash(T what, WashSubstance washSubstance, Detergent detergent);   }  

you can add from the beginning

@FunctionalInterface  interface Washer  {      void wash(T what, WashSubstance washSubstance, Detergent detergent);         default wash(T what, WashSubstance washSubstance)       {          wash(what, washSubstance, Detergent.DEFAULT_DETERGENT);      }        default wash(T what, Detergent detergent)       {          wash(what, WashSubstance.DEFAULT_WASH_SUBSTANCE, detergent);      }        default wash(T what)       {          wash(what, WashSubstance.DEFAULT_WASH_SUBSTANCE, Detergent.DEFAULT_DETERGENT);      }  }  

Also, try to make your interfaces functional (only one abstract method) so you can benefit from lambdas sugaring.

Answer by alain.janinm for What is the appropriate way to plan for a Java API with new features over time?


I would suggest to take a look at these Structural Pattern. I think the Decorator pattern (also known as Adaptive pattern) can fill your needs. See the example in the linked Wikipedia article.

Answer by Rostislav Matl for What is the appropriate way to plan for a Java API with new features over time?


You could use a new package name for the new version of API - this would allow old and new API live side-by-side and API users can convert their components to the new API one at a time. You can provide some adaptors to help them with heavy-lifting on boundaries where objects get passed across boundaries between classes using new and old API.

The other option is quite harsh but could work for internal project - just change what you need and make users to adapt.

If you are just adding, providing default implementation (in an abstract class) of the new methods can make the process smoother. Of course this is not always applicable.

Signalling the change by changing major version number a provide detailed documentation about how to upgrade the code base to the new version of API is good idea in both cases.

Answer by David P. Caldwell for What is the appropriate way to plan for a Java API with new features over time?


Here's the way I approach this situation.

First, I'd use abstract classes so that you can plug in default implementations later. With the advent of inner and nested classes in JDK 1.1, interfaces add little; almost all use cases can be comfortably converted to use pure abstract classes (often as nested classes).

First release

abstract class DoSomething {      public abstract void hop();      public abstract void skip();      public abstract void jump();  }  

Second release

abstract class DoSomething {      public abstract void hop();      public abstract void skip();      public abstract void jump();        abstract static class VersionTwo {          public abstract void waxFloor(Floor floor);          public abstract void topDessert(Dessert dessert);      }        public VersionTwo getVersionTwo() {          // make it easy for callers to determine whether new methods are supported          // they can do if (doSomething.getVersionTwo() == null)          return null;          // OR throw new UnsupportedOperationException(), depending on specifics          // OR return a default implementation, depending on specifics      }        // if you like the interface you proposed in the question, you can do this:        public final void waxFloor(Floor floor) {          getVersionTwo().waxFloor();      }        public final void topDessert(Dessert dessert) {          getVersionTwo().topDessert();      }  }  

Third release would be similar to second, so I'll omit it for brevity.

Answer by user4122955 for What is the appropriate way to plan for a Java API with new features over time?


If you haven't designed the final API, don't use the name you want for it!

Call it something like V1RC1, V1RC2, .. and when it is done, you have V1.

People will see in their code, that they are still using a RC-Version and can remove that to get the real thing when it is ready.

Rostistlav is basically saying the same, but he calls them all real API Versions, so it would be V1, V2, V3, .... Think that's up to your taste.

Answer by Lance Java for What is the appropriate way to plan for a Java API with new features over time?


You could also try an event driven approach and add new event types as your API changes without affecting backwards compatability.

eg:

public enum EventType {      SLICE(Sliceable.class),      DICE(Diceable.class),      HOP(Hoppable.class);        private final Class contextType;        private EventType(Class contextType) {         this.contextType = contextType;      }        public Class getContextType() {         return this.contextType;      }  }    public interface EventHandler {      void handleEvent(T context);  }    public interface EventHub {       void subscribe(EventType eventType, EventHandler handler);       void publish(EventType eventType, T context);  }    public static void main(String[] args) {      EventHub eventHub = new EventHubImpl(); // TODO: Implement      eventHub.subscribe(EventType.SLICE, new EventHandler { ... });      eventHub.subscribe(EventType.DICE, new EventHandler { ... });      eventHub.subscribe(EventType.HOP, new EventHandler { ... });        Hoppable hoppable = new HoppableImpl("foo", "bar", "baz");      eventHub.publish(EventType.HOP, hoppable); // fires EventHandler  }  


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.