Java Deep

Pure Java, what else

How We Chose Framework

When you develop your application most of the time you are writing code that deals with some of the resources. Code lines that open database connection, allocate memory and alikes. The lower level you code the more code is dealing with the computational environment. This is cumbersome and though may be enjoyable for some of the programmers the less such code is needed the better. The real effort delivering business value is when you write code lines that implement business function. It is obvious that you just can not make a simple decision to write only business function implementing code. The other types of code lines are also needed to execute the code and it is also true that the border between infrastructure code and business code is sometimes blurry. You just can not tell sometime whether the code you type is infrastructure or business.

What you really can do is to select a framework that fits the business problem the best. Something that is easy to configure, does not need boiler plate code and easy to learn. That way you can focus more on the business code. Well, easy to say, hard to do. How could you tell which framework will be the best on the long run when the project has so many uncertainties? You can not tell precisely. But you can try and strive for more precision. And a model does to follow does not hurt. So what is the model in this case?

During the lifetime of a project there will be a constant effort to develop the business logic. If the business logic is fixed the number of the code lines to develop that can not change much. There may be some difference because some programming language is more verbose than the other, but this is not significant. The major difference is framework supporting code. There is also an effort to learn the framework, however that may be negligible for a longer project. This effort is needed at the start of the project, say sprint 1 and 2 and after that this fixed cost diminishes compared to the total cost of development. For the model I setup I will neglect this effort not at least because I can not measure a-priori how much effort an average programmer needs to learn a specific framework.

So the final, very simplified model is to compare the amount of code delivering business value compared to the amount of code configuring and supporting the selected framework. How to measure this?

I usually… Well, not usually. Selecting a framework is not an everyday practice. What we did in our team last time to perform a selection was the following:

We pre selected five possible frameworks. We ruled out one of them in the first run as not being widely known and used. We did not want to be on the bleeding edge. Another was filtered out as closer examination showed that the framework is a total misfit for our purpose. There remained three. After that we looked up projects on GitHub that utilized one of the framework, at least two for each framework (and not more than three). We looked at 8 projects total and we counted the lines categorizing each as business versus framework code lines. And then we realized that this just can not be done during the lifetime of a human, therefore we made it simpler. We started to categorize the classes based on their names. There were business classes related to some business data and also classes named after some business functions. The rest was treated as framework supporting, configuration class.

The final outcome was to sculptured into a good old ppt presentation and we added the two slides to the other slides that qualitatively analyzed the three frameworks listing pros and the cons. The final outcome, no surprise, was coherent: the calculation showed that the framework requiring the less configuration and supporting code was the one we favored anyway.

What was the added value then?

Making the measurement we had to review projects and we learnt a lot about the frameworks. Not as much as one coding in it, but more than just staring at marketing materials. We touched real code that programmers created while facing the real problems and the real features of the frameworks. This also helps the evaluator to gain more knowledge, gives a rail to grab on and lead us where to look, what to try when piloting the framework.

It is also an extremely important result that the decision process left less doubt in us. If the outcome were just opposite then we would have been in trouble and it would have made us thinking hard: why did we favor a framework that needs more business irrelevant code. But it did not. The result was concise with common sense.

Would I recommend this calculation to be the sole source for framework selection? Definitely no. But it can be a good addition that you can perform burning two or three days of your scrum team and it also helps your team to get the tip of their fingers into new technologies.

Logging or Commenting ?

When my recent article was republished on dzone Jonathan Fisher added a valuable comment stating:


I think I have something else you should write an article on: “Logging or Commenting?” I see debug statements as “living comments”, one that explain the execution of the program to the next guy, but also provides valuable intel in production.

I have seen that practice only once. There was a coding environment with strict coding rules that forbid commenting. They said you should comment Javadoc on the interfaces but nothing else. If your code is not readable reading the code and the unit tests then your code has to be changed.

In this environment programmers, who wanted to comment, soon started using logs. But before getting to that let’s see why.

Is Commenting Bad?

Generally commenting is bad. It was not bad when assembly and FORTRAN were the programming languages. Those languages were to generate executable code and not to express ideas. Languages today focus more on expressiveness, ease of coding and the translation from ideas to executable is done by compiler more than this was possible in the era of FORTRAN. Now we have the CPU and memory to compile languages like Java, Groovy, Scala. When these language are at hand and you feel like needing comments you have to think about two things:

  1. Is your code really readable? Could not it just been rewritten to express the ideas carved into the comment?
  2. Is the information you want to type as a comment really a comment? Or it should be part of the documentation, and should not be put into the code?

If you think you can not write the code more expressive because the business domain is just complex and does not fit the code, please visit the article The Golden Rules of Code Documentation and the rant to the challenge.

Comments are to be read by programmers, who maintain your code. If the words would rather fit the documentation in a Wiki, do not distract the programmers following you.

Are logs bad?

Generally logging is good. However if logging is to overcome the commenting restrictions then a good weapon is used for the bad. Don’t. It is a more general concept than logging. As a matter of fact even broader than programming. Don’t use a tool it was not designed for.

There is a fear that logging decreases performance. Using modern logging libraries and solutions this should not be a factor to seriously consider except edge cases. Even if it is, first measure and then tune. Do not prejudice or have a-priory assumptions about performance.

Conclusion

Logging should add to readability. Since it is a separate aspect, different from the original business aspect the code was developed for, there is a danger that inserting the logging statements will decrease readability. When you develop code you should pay attention to this. For example I recommend that you never externalize or use fields/variables to store the logging strings. Logging texts should make sense where the statements are.

Insert logging statements bravely, never hesitate. When you code review take into account that there are two sequences of logging statements. One sequence is linear as you read the code. The other sequence is how the printouts get into the log file following the program execution. Perhaps making a log review involving production, support people can be a good practice. It can be similar to code review: a fresh eye looks at the generated logs and gives feedback on readability. I have experienced this ad-hoc but never as a planned activity. If anyone tried, give feedback.

And generally: do logging for logging. Use commenting for commenting. If you have to dig a grave, use a shovel. If you have a nail: use a hammer. Use the appropriate tool and do not mix usage.

Unit test deprecated methods

Deprecated methods have to be treated different. At least in my opinion. The question I did not discuss in that article is if we have to unit test deprecated methods or not. For the impatient here is my statement:

Deprecated methods have to be unit tested the same way as other methods.

Probably this is not a question when there is already a unit test for the method. In that case you just leave it there and keep it running each time the CI server fires. The question may come up in your mind when you inherit some legacy code and you, yourself deprecate some methods or just find it deprecated with no appropriate unit test. Why bother to invest time writing unit tests when the method will no longer be in use?

The answer to this why lays where the difference is between a deprecated and a deleted method. The deprecated method is still in use. It may happen that no one uses the method but that is not guaranteed. If it were you could just delete the method. Deprecated method is still in the published API with a slight comment: you better do not use it. Clear?

What if there is no time to write the unit tests?

If there is no time (treat this precondition as a hypothetic and not questionable: that is another topic for what to have time) then there is no question.

Unit test are not writing themselves during the night, while you sleep.

What if you have some time but kind of short. In that case, if nothing else prevails, you can linger the tests for the deprecated methods to the end of the task list. If nothing else prevails. Being deprecated does not necessarily mean: not important. Many may still use it. It means: deprecated.

You can program bug free

Money Spent Wise on QA

Money Spent Wise on QA

You can not. This is a lie, just like the cake. You can lower the number of bugs. The more you spend wisely on QA the less bugs you will have. The magic word is “wisely”. You can spend unlimited amount without increasing the quality. Old truth in just any area: you can waste money if you are not wise.

On the other side of the line there is no free lunch. If you do not spend enough on QA you can only dream about properly working software. You won’t have less bugs if you do not spend on QA. And you will never be bug free.

Bug free software is contradiction. We have bugs, and we do not like them. We have to zap them.

Ad-hoc bug zap

Most of the bugs are zapped in an ad-hoc manner. The developer writes some test, develops some code. The code does not work, has bugs and the developer fixes the code until it runs fine with the unit tests crafted beforehand. Integration tests and end-to-end tests may also discover some bugs. These are usually reported in a bug tracking system and the developers fix them and they are eliminated in the next release.

Sometimes, however bugs are not that easy to handle.

Classified bugs

Sometimes bugs are not that simple to handle. Sometimes it takes a lot of time to fix a bug. It may need analysis how and when the bug manifests. Sometimes bugs magically disappear like if computers were non deterministic. Other times fixing a bug requires significant code modification. This is, by the way, a clear sign of design shortage on the technical or business level (or both).

If a bug is difficult developers may be reluctant to hunt for it and fix it. If it needs alteration of lot of code they may tend to declare the behavior to be a feature rather than a bug. Fortunately we know who has the last word in such a debate: money. Feature is what business uses to make value. Everything else is just behavior. And here comes the other aspect of bug classification: does business care about a certain behavior? If yes, the behavior is a bug and is a target for fix. If not then this is just a behavior.

Bug Classification Quadrandt

Bug Classification Quadrandt

Looking at that in a quadrant we have four different types of bugs.

  1. There are bugs that are easy to fix and have high impact on the business. They are the easy picks. Developers are usually eager to fix those bugs and become the hero of the project.
  2. Bugs hard to fix and having no business impact will never be fixed. There is no point.
  3. Bugs easy to fix and low impact on business are fixed many times when a developer has some time (minutes) to do the fix. This is the hobby area.
  4. There are bugs that are hard to fix and have high impact on the business. These are the critical bugs that get most of the attention. These bugs will not be fixed from one day to the other and therefore they have to be assessed, budgeted, scheduled and eventually fixed.

Cost of bug fix

Business needs these bugs fixed and many times the cost to fix them does not represent any extra value. Usually business feels that these bugs just have to be fixed but not on their costs. They have already paid for the feature, which eventually fails. If the development organization is separate company then the vendor should have the budget to do the fix. It had to be included in the contractual price. If the development is in-house the cost may not be discussed or may be T&M based. In that latter case the developers “charge” only the hours they spent developing the feature instead of project fixed price but when there is some bug the hours to fix are also charged. This is something not clarified well enough among the players and is a source of interdepartmental stress in many times.

“Easy picks” are fixed without budgeting and business people press the developers to fix the bugs “in their free time” without separate budget. The driver for this may be to lessen the burden of costs that business people are usually measured on and also many times to hide the errors that were in the specification, communication on the business side. On the other hand developers want even easier to fix bugs to be assessed since they are usually measured on billable time. They are also reluctant to burn their so called “free time”. This time is not really “free time”. This time is covered by work hours and is usually used for self education. And developers (at least those that deserve the title) love to educate themselves (for example reading blogs like this).

For this reason there is no clear and precise border between the “Easy Pick” and the “Assess, Budget, Schedule, Fix” areas. Business people want to pull the border to east leaving more and more bugs in the easy pick area, while developers want the border more to the west, and the fight area is in between. And the real problem is when the project members spend significant amount and effort in that area.

Conclusion

When you find yourself in a debate about bugs and features with the business people, try to bring up this quadrant in your mind. Many times the cost/value coordinates of the bugs are not discovered. Think about it even qualitatively.

Knowing the bits

We use complex systems. My mother once said that there could be little leprechauns behind the TV screen redrawing the screen 50 times a second she could not care. (At least she new that the TV in Europe had 50 (half) screens every second.) Most of the people do not care about the electronics and the softwar around us. The trend is that this technology penetration is going to be even more dense. Electronics gets cheaper, programming becomes easier and soon toilet papers will have one-time-use embedded computers on it. (Come up with a good application!) Face recognition is not the privilege of NSA, CIA, KG or Mosad and the technology spread does not stop at the level of big corporations like FB, or Google. Shops start to install cameras and software that recognizes and identifies frequent buyers helping the work of the sales. People get used to it and IT personnel are not different, are we?

Kind of yes. The difference is that we are interested in the details of those leprechauns how they do their job. We know that these days there are liquid crystals in the screen, they are controlled by low voltage signals (at least compared to the voltages of the former CRT solutions) and that there is a processor in the TV/toaster/toilet paper and it is programmed in a language called e.g. Java.

We, Java programmers, program these applications and we not only use the language (including RT) but also layered software, frameworks. How do these layered software work? Should we understand or should we just use it and hope that it works?

The more you know a framework the better you can use it.

Better means faster, more reliable, creating code that is more likely to be compatible with future versions. On the other hand there should be a reasonable stop when you have to halt learning and start using. There is no point to know all the details of a framework, if you never start using it. You should aim for the value you generate.

On the other end of the line however, if you do not have enough knowledge of the framework you may end up using a hammer digging a hole instead of a shovel. I usually feel confident when my knowledge reaches the level of understanding that I know how they (the developers of the framework) did it. When I can bravely say:

If I had time (sometimes perhaps more than lifetime of a single person) I could develop that framework myself.

Of course, I will not, because I do not have the time and also, more importantly because there is no point developing something that is already developed with appropriate quality. Or is there?

I could do it better.

I have heard that many times from junior programmers and from programmers, who considered themselves not that junior. The correct attitude would have been:

I could do it better, but I won’t because it is done and is good enough.

You do not need the best. You just need a solution that is good enough. There is no point to invest more if there is no extra leverage. There is no point to invest more even if there is leverage but it is lower than the investment in other areas would be higher.

Generally that is it when you are professional. Face it!

We hate/love lambda

We have the long waited lambda feature in Java 8. And we love it. We love to use it at places where we used anonymous class. We love to use it where we used some looping construct. Now we use functional interfaces instead and thus we get faster performance using parallel streams and we get more readable code. The time is a short period of euphoria to be replaced by the several, low orbiting WTFs reviewing out others code. I write nice and readable code but I continually experience that others write ugly, unreadable and wrong code. (Please feel the delicate odour of irony.) And I expect lambda will make it worse.

There are two main values in a programming language feature:

  1. How well can you express your ideas utilizing the feature.
  2. How badly one can use (or abuse) the feature.

Good language features aid a lot in expressing yourself and can not be abused. They just shine bright readable in all their glory no matter how hard a bad guy may use them the wrong way. They end up with properly working and readable code. The only problem with these ideal language features is that they do not exist.

On the other hand bad language features are hard to use to express your ideas and are easy to misuse. And contrary to the previous one: they exist.

The reality is that most languages have language features that provide great ways to express your ideas but at the same time they can also be misused. Usually the easier to express yourself the easier to misuse a feature. Java language does not shine with brilliant syntax to briefly express your ideas but the same time you can not abuse it really. You can abuse it a bit, but there is no Java counterpart of the obfuscated C contest. Java is verbose, dull, boring. It is so dull that the language that wanted to overcome this dullness is named groovy. Groovy is many steps ahead of Java implementing shiny features. They have the tools and they are not afraid to use it. Groovy developers are and should not be afraid of unreadable code written by the bad guys or else they are going to have bad time. If you are to maintain Groovy code, prepare for the worst. No matter how good and beautiful Groovy code could be it will be just bad, because it was written by average programmer.

The Groovy language implements a feature if the feature can be used well and brilliant but how bad the feature can be abused is not considered really. The designers of the Groovy language assume that the programmers are all brilliant, and experienced artists. We all are, aren’t we?

Implementing lambda Java made a step towards the Groovy direction. It is a great feature that can replace the ugly anonymous class use, aid functional style and so on. But at the same time …

OpenSource License Manager

What is a License Manager?

License managers are used to enforce license rights, or at least to support the enforcement. When you develop an open source program, there is no much you need to or can do to enforce license rights. The code is there and if anyone just wants to abuse the program there is nothing technical that could stop them. Closed source programs are different. (Are they?) In that case the source code is not available for the client. It is not possible to alter the program so that it circumvents the license enforcement code, and thus there is a real role for license rights enforcement.

But this is not true.

The truth is that there is no fundamental difference between closed and open source code in this respect. Closed source codes can also be altered. The ultimate “source” for the execution is there after all: the machine code. There are tools that help to analyze and decode the binary to more or less human readable format and thus it is possible to circumvent the license management. It is possible and there is a great source of examples for it. On some sites hosted in some countries you can simply download the cracked version of practically any software. I do not recommend to do that and not only for ethical reasons though. You just never know which of the sites are funded by secret services or criminals (if there is any difference) and you never know if you install spy software on your machine using the cracked version.

Once I worked for a company where one of the success measurements of their software was the number of the days after release till the cracked versions appeared on the different sites compared to the same value of the competitor. The smaller the number was for their software the happier they were. Were they crazy? Why were they happy to know that their software was cracked? When the number of the days was only one single they, why did not they consider applying stronger license enforcement measure, like morphing code, hardware key and so on?

The answer is the following. This company knows very well that license management is not to prevent the unauthorized use. It can be used that way but it will have two major effects which will ruin your business:

  • Writing license management code you spend your time on non-productive code.
  • License management (this way) works against your customer.

Never implement license management against your customer.

When your license management solution is too restrictive you may restrict the software use of your customer. When you deliver your code using hardware key you impose inconvenience to your customer. When you bind your license to Ethernet MAC address of the machine the application is running on, again: you work against your customer.

Set<User> != Set<Customer>

Face the said truth: there will always be people, who use your software without paying for it. They are not your customers. Do they steal from you? Not necessarily. If there is someone who is not buying your software, he is not your customer.

If you know that there is no way they would pay for the software and the decision was in your hands whether you want them to use the software or use that of your competitor what would you choose? I guess you would like your software to be used to get more feedback and more knowledge even in the area of non-customers. People using your software may become your customer more likely than people not using it. This is why big companies sell out educational licenses to universities and other academic institutions.

Should we use license management at all in that case? Is license management bad down to ground in all aspects? My answer is that it is not. There is a correct use case for license management, even when the software is open source (but not free, like Atlassian products). To find and understand this use case there is one major thing to understand:

The software is for the customer, and any line in the code has to support the customers to reach their business goals.

Paying the fee for the software is for the customers. If nobody finances a software the software will die. There is nothing like free lunch. Somebody has to pay for it. To become a customer and pay for the software used is the most straightforward business model and provides the strongest feedback and control for the customer over the vendor to get the features needed.

At the same time paying for the software use is not the core business of the customer. Paying for the resources used supports them to reach their business goals is indirect. This is where license management comes into picture. It helps the customer to due their duties. It helps them remember their long term needs. This also means that license management should not prevent functionality. No functionality should stop if a license expires. Not to mention functionality that may prevent access to data that actually belongs to the customer.

If you approach license management with this mindset you can see that even open source (but not free) software may need it.

License Management Tool: license3j

Many years ago I was looking for some license management library and I found that there was none open source. I wanted to create an open source (but not free) application and it required that the license management is also open source. What I found was also overpriced taking into account our budget that was just zero for a part time start-up software (which actually failed business wise miserably, but that is another story). For this reason I created License3j which surprisingly became one of the most used library of my OS projects.

License3j is very simple in terms of business objects. It uses a simple property file and lets the application check the content of the individual fields. The added value is handling electronic signature and checking the authenticity of the license file. Essentially it is hardly more than a single class file.

<dependency>
	<groupId>com.verhas</groupId>
	<artifactId>license3j</artifactId>
	<version>1.0.4</version>
</dependency>

Feel free to use it if you like.

How not to use Java 8 default methods

Warning: you can not make this unseen once you have read

I was talking about the multiple inheritance of default methods in the last blog article and how they behave during compilation and run time. This week I look at how to use default methods to do real inheritance, which actually, default methods were not designed for. For this very reason, please read these lines at your own risk, and do not imply that this is a pattern to be followed, just as well do not imply the opposite. What I write here are some coding technics that can be made using Java 8 but their usability is questionable at least for me. I am also a bit afraid to let some ifrit out of the bottle , but on the other hands those ifrits just do not stay there anyway. Some day somebody would let it out. At least I attach the warning sign.

Sample problem

A few years ago I worked on an application that used a lot of different types of objects that each had a name. After many classes started to contain

public String getName(){...}
public void setName(String name){...}

methods that were just setters and getters the copy paste code smell just filled the room unbearable. Therefore we created a class

class HasName {
  public String getName(){...}
  public void setName(String name){...}
}

and each of the classes that had name were just extending this class. Actually it was not working for a long time. There were classes that extended already other classes. In that case we just tried to move the HasName upward in the inheritance line, but in some cases it just did not work. As we went up the line reaching for the top we realized that those classes and their some other descendant do not have a name, why to force them? To be honest, in real life it was bit more complex than just having name. If it were only names, we could live with it having other classes having names. It was something more complex that would just make the topic even more complicated and believe me: it is going to be complex enough.

Summary: we could not implement having the name for some of the objects implemented in some spare classes. But now we could do that using default methods.

HasName interface with default implementation

Default methods just deliver default functionality. A default method can access the this variable, which is always the object that is implementing the interface and on which behalf the method was invoked. If there is an interface I and class C implements the interface, when a method on a C c object is invoked the variable this is actually the object c. How would you implement getName() and setName()?

These are setters and getters that accessing a String variable that is in the object. You can not access that from the interface. But it is not absolutely necessary that the value is stored IN the object. The only requirement is that whatever is set for an object the same is get. We can store the value somewhere else, one for each object instance. So we need some value that can be paired to an object and the lifetime of the value has to be the same as the lifetime of the object. Does it ring the bell?

It is a weak hash map! Yes, it is. And using that you can easily implement the HasName interface.

public interface HasName {
    class Extensions {
        private static final WeakHashMap<HasName, String> map = new WeakHashMap<>();
    }
    default void setName(String name) {
        Extensions.map.put(this, name);
    }
    default String getName() {
        return Extensions.map.get(this);
    }
}

All you have to do is write at the end of the list of interfaces the class implements: ,HasName and it magically has.

In this example the only value stored is a String. However you can have instead of String any class and you can implement not only setters and getters but any methods that do something with that class. Presumably these implementations will be implemented in the class and the default methods will only delegate. You can have the class somewhere else, or as an inner class inside the interface. Matter of taste and style.

Conclusion

Interfaces can not have instance fields. Why? Because in that case they were not interfaces but classes. Java does not have multiple implementation inheritance. Perhaps it has but "please don't use it" kind of. The default method is a technological mistake. You can call it compromise. Something that was needed to retain backward compatibility of JDK libraries when extended with functional methods. Still you can mimic the fields in interfaces using weak hash maps to get access the inherited class "vtable" of fields and methods to delegate to. With this you can do real multiple inheritance. The type that your mother always warned you about. I told you mate!

Another warning: the above implementation is NOT thread safe. If you try to use it in multithread environment you may get ConcurrentModificationException or it may even happen that calling get() on a weak hash map gets into infinite loop and never returns. I do not tell how to fix the usage of weak hash maps in this scenario. Or, well, I changed my mind, and I do: use default methods only the they were designed for.

Java 8 default methods: what can and can not do?

What default method is

With the release of Java 8 you can modify interfaces adding new methods so that the interface remains compatible with the classes that implement the interface. This is very important in case you develop a library that is going to be used by several programmers from Kiev to New York. Until the dawn of Java 8 if you published an interface in a library you could not add a new method without risking that some application implementing in the interface will break with the new version of the interface.

With Java 8 this fear is gone? No.

Adding a default method to an interface may render some class unusable.

Let’s see first the fine points of the default method.

In Java 8 a method can be implemented in an interface. (Static methods can also be implemented in an interface as of Java8, but that is another story.) The method implemented in an interface is called default method and is denoted by the keyword default as a modifier. When a class implements an interface it may, but does not need to implement a method implemented already in the interface. The class inherits the default implementation. This is why you may not need touch a class when an interface it implements changes.

Multiple inheritance?

The things start to get complicated when a concrete class implements more than one (say two) interfaces and the interfaces implement the same default method. Which default method will the class inherit? The answer is none. In such a case the class has to implement the method itself (directly or by inheritance from a higher class).

This is also true when only one of the interfaces implement the default method and the other one only declares it as abstract. Java 8 tries to be disciplined and avoid “implicit” things. If the methods are declared in more than one interfaces then no default implementation is inherited, you get a compile time error.

However you can not get a compile time error if you have your class already compiled. This way Java 8 is not consistent. It has its reason, which I do not want to detail here or get into debate for various reasons (e.g.: the release is out, debate time is long over and was never on this platform).

  • Say you have two interfaces, and a class implementing the two interfaces.
  • One of the interfaces implement a default method m().
  • You compile all the interfaces and the class.
  • You change the interface not containing the method m() to declare it as an abstract method.
  • Compile the modified interface only.
  • Run the class.

default method multiple inheritance
In this case the class runs. You can not compile it again with the modified interfaces, but if it was compiled with the older version: it still runs. Now

  • modify the interface having the abstract method m() and create a default implementation.
  • Compile the modified interface.
  • Run the class: failure.

When there are two interfaces providing default implementation for the same method the method can not be invoked in the implementing class unless implemented by the class (again: either directly or inherited from another class).
invalid multiple inharitance of default methods
The class is compatible. It can be loaded with the new interface. It can even start execution so long as long there is no invocation to the method having default implementation in both interfaces.

Sample code

directory structure of test

To demonstrate the above I created a test directory for the class C.java and three subdirectories for the interfaces in files I1.java and I2.java. The root directory of the test contains the source code for the class C in file C.java. The directory base contains the interface version that is good for execution and compilation. I1 contains the method m() with default implementation. The interface I2 does not contain any method for now.

The class contains a main method so we can execute it in our test. It tests if there is any command line argument so we can easily execute it with and without invoking the method m().

~/github/test$ cat C.java 
public class C implements I1, I2 {
  public static void main(String[] args) {
    C c = new C();
    if( args.length == 0 ){
      c.m();
    }
  }
}
~/github/test$ cat base/I1.java 
public interface I1 {
  default void m(){
    System.out.println("hello interface 1");
  }	
}
~/github/test$ cat base/I2.java 
public interface I2 {
}

We can compile and run the class using the command lines:

~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1

The directory compatible contains a version of the interface I2 that declares the method m() abstract, and for technical reasons it contains I1.java unaltered.

~/github/test$ cat compatible/I2.java 

public interface I2 {
  void m();
}

This can not be used to compile the class C:

~/github/test$ javac -cp .:compatible C.java 
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
       ^
1 error

The error message is very precise. Even though we have the C.class from the previous compilation and if we compile the interfaces in the directory compatible we will have two interfaces that can still be used to run the class:

~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1

The third directory, wrong contains a version of I2 that also defines the method m():

~/github/test$ cat wrong/I2.java 
public interface I2 {
  default void m(){
    System.out.println("hello interface 2");
  }
}

We should not even bother to compile it. Even though the method is double defined the class still can be executed so long as long it does not invoke the method, but it fails as soon as we try to invoke the method m(). This is what we use the command line argument for:

~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
	at C.m(C.java)
	at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$

Conclusion

When you start to move your library to Java 8 and you modify your interfaces adding default implementations, you probably will not have problems. At least that is what Java 8 library developers hope adding functional methods to collections. Applications using your library are still relying on Java 7 libraries that do not have default methods. When different libraries are used and modified, there is a slight chance of conflict. What to do to avoid it?

Design your library APIs as before. Do not go easy relying on the possibility of default methods. They are last resort. Choose names wisely to avoid collision with other interfaces. We will learn how Java programming will develop using this feature.

Documenting API using Concordion

Concordion is an open source tool for writing automated acceptance tests in Java.” It is a handy little tool, simple to use and even the source code of the tool is good style. You describe the tests using HTML with special markups and when you run your special unit tests using the ConcordionRunner it processes the HTML and replaces the special tags with the actual values fetched from the tests. In the end you get an HTML colored with red and green spots where some tests failed or succeeded respectively. This is a result good for the eyes, BAs and easy to spot any error. This way it is similar to fitnesse and GreenPepper.

Even though the tool was designed for automated acceptance test — which one could argue is a non-sense term — I wanted to use it to document API.

The usual way to document API is JavaDoc. JavaDoc includes the signature of the methods, and comments. The comments are supposed to depict the way the method should be used. This is fairly good approach but has some shortages:

  • The comments become outdated. Developers change the way the method is to be used, but forget to update the JavaDoc.
  • A method many times should be used in different ways together with other objects and methods.

For this reason many developers believe that unit tests are the real documentation of an API. Two approaches with good and bad aspects. How could we leverage the best of the both world?

I decided to write a small library that can be included into Concordion fixtures using delegation and which can read the source code of the fixture or just any other source code, cut off some lines from the code and return them as string. Referencing the method Concordion output can include (presumably preformatted) Java code. This way the resulting HTML will contain living documentation including actual code without manual copy pasting that decreases the danger of the documentation getting outdated.

The project is available from GitHub and also from Sonatype repo. The documentation of the project was also created this way.

Follow

Get every new post delivered to your Inbox.

Join 909 other followers