Java Deep

Pure Java, what else

The dumbest interview question ever

This article is not really about informatics at first. But on second though…

Why are sewer covers round?

This is the interview question that I believe is the most pointless ever. This is asked many times and the interviewer usually expects the clever answer: “Because this is the shape that prevents the cover to be dropped into the hole under it.” When I got this question once I had different answer: “Because there are no corners and thus there are no singularities where very huge forces can appear, which are responsible for cracks usually.” Actually I learned that at the university when I had to study a subject about mechanics and machinery. I graduated as electric engineer and I only later became software specialist. After many years of software engineering I have now a different opinion about this question.

What I really think sewer covers are round for?

Because it was always the way like that. Somebody, sometime a hundred or two-hundred years ago created the first sewer top and there was some reason to design it round. They documented it (or not) and started the production. For a short period of time the engineers knew the reasons, but after, say 20 years, the reasons were forgotten and sewer covers were created round for some forgot reasons. Simply because that was the way to do it.

So what? Somebody designed it and it was good,we can follow. Is there any problem with the approach? YES.

The decision was made in a certain environment that radically changed. Labour was cheaper that time, automation was non-existent and metallurgy was far from what it is now. I do not imply that the round form is bad. I do not imply that we have to use octagonal or star shaped sewer tops. I only express my strong belief that nobody was checking the validity of the assumptions recently.

What does it do with software?

Nothing really more than design and logic that we also use in software engineering. As well as routine, practice, pattern, drill. Many times without considering the original boundary conditions.

So next time when somebody asks you this question on an interview just tell them: “Because this is the shape that prevents the cover to be dropped into the hole under it.”

Use of optional is optional

After the article of last week “Optional in collections” today I can’t help but talking a bit more about the same beast. A bit more detail.

The class Optionial originally introduced by Google Guava and later included in the Java 8 package is simply a wrapper that wraps an optional object. The wrapped object is optional in the sense that it is either there or there is no object in the wrapping, in which case it is empty. There is not too much magic there. The wrapping code, the class Optional insist that the object wrapped is not null. After all null is null and not an object. An object is never null. Only a reference to an object can be null.

These are nuances, fine details; but important fine details. After all, these fine details are those that required the introduction of Optional. Average java coder does not see the importance of such tiny details. They think that Optional is just as good as a variable to the wrapped object itself assuming that the variable can also be null. At some level they are right. At their own level.

That level says that the good code works, can be understood and that is it. Most of enterprise legacy code that run banks, insurance companies, pace makers and weapons were made on this level. You can not do about it, just hope that you have the luck and a software bug will not select your house, bank account or body (in case of medical device) in a “bomb” explode there. What you can do is to understand the issue and do your part to slowly improve the situation. It will take a few generations unless we all are wiped out before that.

“Code working” and “possible to understand” are the very basic requirement for software. Some old times we said that if the software runs then it was ok and for the maintenance it was enough if there were two “person” who could understand the code: the coder who created it and God, who created the coder. Fortunately there are also levels higher. (I mean above the coder. Not above God.)

“Code working” and “easy (not so hard) to understand” are the next level. This is important in case you have to debug the code and need to identify the root cause of some malfunction. “Code working” and “easy to modify” are again new steps up the ladder. I had seen code that I could easily understand. The code was running. But the dependencies between the different modules were so complex like a macrame or a traditional Italian spagetti. Wherever I wanted to change something to fix a bug here, there were a few other places where the program started to fail. Easy to modify: that code was not.

The next level is “code working”, “easy to modify” and “hard to create bad modifications”. This means that the code provides style and internal data structures and APIs that the maintaining person will follow to some level and will create a working modified code that still works, easy to understand and to modify. This is the point where we get to the point of Optional.

When a method returns Optional is says that it may return something or just nothing. Optional<Integer> may return an Integer but it may just return an empty Optional, which means: there was no Integer that I could return. Why is it any better than returning an Integer that may optionally be null?

Optional method return value

The answer is that in case of returned Optional<Integer> you can not

integer = methodReturningIntegerOrNull();
otherInteger = integer +1;

that causes NPE. Why you do that? Because you forget to check, and the JavaDoc mentions the possibility somewhere at the end of the description that is not visible in the mouse over window when you code. In case of Optional<Integer> you are forced to

optionalInteger = methodReturningOptionalInteger();
if( optionalInteger.isPresent() ){
  otherInteger = optionalInteger.get() +1;

Still there is a small chance that you will write:

optionalInteger = methodReturningOptionalInteger();
otherInteger = optionalInteger.get() +1;

but in that case you deserve what you get.

Optional helps you to create more code and less documentation. It gives a semantic to pass on some optional value in a way that is harder to neglect than a nullable value. It says: I do not trust you handling null properly, therefore I give you a wrapped object so you have to handle optionality explicitly.

If you consider that you can easily answer the questions

  • requiring Optional<Something> as a method argument
  • having a private field optional.

are good ideas.

Optional method argument

There are pros and cons. When the argument says

countFrom(Optional<Date> from, Date to);

it is clear that the from value may be missing and there should be some special default semantics when an absent value is passed. On the other hand the caller may pass null to get the special behavior. It is less likely that the caller will pass null just by mistake neglecting the optionality. Even if the argument is Optional the argument actually passed can still be null and I expect that the method throws NPE in this case. Last, but not least there is another danger introducing Optional: the caller may pass an Optional embracing an object that is not a Date. Generics can be circumvented in Java easy and a sloppy coder may pass a wrong Optional. It means that you have to implement assertions in your method:

  • argument is not null,
  • argument is of the proper type.

Also recall that Optional, in case of a method return value says: I do not trust you handling null properly, therefore I give you a wrapped object so you have to handle optionality explicitly. What would this message be when you create the API requiring Optional as an argument? Please do not trust me! Give me only Optional because even I do not trust myself to handle a null value properly. Weird… On the other hand I trust that you will not pass null or wrong type.

In my opinion: in this case using Optional does not deliver more value than having proper documentation for the API and does not force the caller to behave better than it would anyway. On the other side you put extra code on your own shoulder.

Give Optional to code you trust, accept it from code that does not trust your code but do not request it! Trust yourself!

Private Optional Fields

When you declare a local, private field to be Optional you will force the developer of the class itself to pay more attention to the optional feature of the field. The cost of this is the extra wrapper, the extra clutter in the code handling optional. On the other side there is no much gain, because you can get the same level of quality extending your unit tests checking all cases where null value of the field is to be considered. Since all the code is in the hand of the current developer being responsible for the whole code there is no benefit of Optional. It is again, like you not trusting yourself. That is a serious issue needing more and different treatment than what Optional Java class can provide.

Optional in functional programming

You can use Optional to program Java in functional programming style if you want, but Java is not a functional language and optional and lambda and the functional style methods alone will not make it to be. But that is a different topic for later.

Optional in collections

Sometime it is argued that the type Optional is worth being used in collections. It allegedly solves the problem of e.g.: HashMap that returns null in case there is no mapping for a key as well as when the value null is mapped to the key. If you use a Map<Optional<Something>> then you can clearly separate a missing mapping and an absent value. And that way you are one level deeper in the rabbit hole.

First of all

you can

tell if a key is mapped to null or not mapped without using Optional. There is the method containsKey(). This is one more method call to separate the non-mapped key from a mapped null value. However calling the methods of Optional is also. So what is the point? On the other hand

you do not need

to tell if the key is mapped to null or the mapping is missing. If there is a difference in your program code between the two cases then you created the code for the business login in a wrong way. This is certainly code smell. Think of null as “nothing”, and instead of thinking “null is assigned to the key ‘aaaaaarrghhh'” say out loud: Nothing is assigned to the key ‘aaaaaarrghhh’. You see? There is no difference except that all look at you now in the office.

And using optional as a value in a Map

you will

end up one level deeper in the rabbit hole after a while. Code lives independent life. It is not only you, who develop it. In large organizations there are developers who are certainly drunk when code. (This is the only reasonable explanation for some code.) They will soon populate your Map<Optional<Something>> with

  • null values,
  • absent Optional values
  • and even with Optional object that wrap something else but not your “Something“.

From time to time, if you are lucky you may even find some non null, non absent Optional<Something> values.

Some thoughts about yagni

Yagni means “You Aren’t Gonna Need It”. This is a phrase used many times to refuse the development of some features that may be needed later but not now. Yagni means that you should develop a feature in your code, which is needed and when it is needed and not sooner.

Why do we have this term at all? Do developers tend to develop features that are not needed? It should be like that otherwise there would not be any expression for the phenomena. It may seem crazy for someone not knowing how a programmer thinks and works.However the fact is that programmers do like to develop features that were not requested.

Why do programmers tend to develop features that are not needed?

Reasons and Problems of Yagni

Coding a feature, which is similar to one I have just developed is easier than something totally unrelated. Developing similar features one after the other is simpler than developing one, then doing something totally different and developing the second one weeks later. The developer is “on the track”. She knows how to develop the feature having just developed a similar one.

The problem is that many times the feature will not be needed (1). Even if it is going to be needed there is high probability that it will be needed a bit (or a lot) different from what has been developed (2). The code developed but not in use by business has costs attached to it (3), but no business benefit.

If (1) the feature is not needed in the future the investment devoted to the development of the feature is wasted. It does not matter who is financing it. It may be financed by the business but many times I see that it is financed by (usually junior) developers creating the feature after work hours. They argue that it was a good way of learning, practicing. However I strongly believe it is not a good way of learning. It is a way someone lies to him/herself. The cognitive patterns in the brain prevent to admit: “I was wrong and wasted my time.” One can do more valuable things during that time and doing free work is not professional. There are better ways for learning or practicing something. Be professional!

If the feature is needed but in a different format (2) you have to modify it. It is not likely that the cost of the development at the first place and the modification is cheaper than developing the feature the correct way upfront.

Even if it is needed and exactly the way it was developed the costs (3) associated with the prematurely developed features include maintenance, increased complexity debugging, maintaining and costs related to the delayed delivery of the features that were needed in early stage. It is likely that you do not deliver feature “ONE” faster if developed it together with feature “TWO”.

When Yagni is Good

The only situation when Yagni seems to be valuable is when developing a feature A alone needs extra coding that gets useless and erased when the latter feature is developed. For example you need feature A and to have it without the other feature B you need some extra classes that you will just throw away when you finished the development of B.

The reasoning is good as formal logic. Only the basic assumption that such situation exists may not be true. The need for some extra code for A but useless when B is developed is a code smell. In that case you have to think about how to develop those extra classes so that they can be usable also by the feature B later on.

But wait a minute! Isn’t that yagni by itself? Developing some classes differently just because some later features will need it differently? No, it is not. To get that correct we have to distinguish between

Feature Yagni and Structure Yagni

So far I was speaking about feature yagni. Structure yagni is different and is not really a yagni. Well, most of the cases.

Wording is important! I do not advocate writing the classes for A in a way so that they can be used by B but nothing else. What I recommend is that you check your style and coding to find the reason why the extra classes would be thrown away. If you can write it different way so that they can be used when B is implemented then they are reusable (by definition). In that case your code is generally good (or at least better) style.

That way implementing good style code, creating clean code, good data and class structures is not yagni. The implementation of a feature not needed yet: that is yagni.

Refactoring is not Yagni

Even if creating clean code needs more work than the Q+D solution this extra coding, including some extra classes is not yagni. We do develop code that is not strictly needed by any business function. That way when there is some not soo good code and we refactor it is also not yagni.  This is not l’art pour l’art. It is needed by business and sometimes, if the seniors and BA do their jobs right business people even know it.

Practice avoid yagni

Writing code that does not develop extra features and is not especially prepared to be ready for extra features not needed yet (yagni), but are open for extension is hard. It is a kind of art and needs a lot of practice. Actually this is what we do when we strictly follow TDD. We develop a test first and it fails. Then we deevelop the code that is minimally needed to fulfill the test. Then we create the next test and so on. When doing TDD you never create a new test while there is a test failing and you never develop any (non test) code unless there is a test failing and you develop the code to pass the test, but nothing else.

This is exactly the practice to develop without yagni. It works on the small scale. When you start you hate it first. It seems to be slow and cumbersome like dacing hogtied. But after a while it becomes a habit, your code style improves and without realizing your way of thinking changes and you get the yagni free design on higher levels.

Teenage Sex and What the sun.misc.Unsafe Misery Teaches Us Generally

Lukas Eder wrote an article about the miseries of the proposed drop off of sun.misc.Unsafe. If you have not heard that Oracle will remove the internal sun.misc.Unsafe class in Java 9 then read the article of Lukas and follow some of the links he provides at your discretion. His article is about what we learn from this happening.

sun.misc.Unsafe is a class available in most of the Java implementations delivering some “unsafe” functionality that are not available in other ways. These functions are not part of the specification and are not guaranteed to be available. They just happen to be there and are available via some nasty reflection hack. In other words: you should not use it, but you can. There are some Java tools that help protect you from using the interface but not too heavily.

Other languages, like Perl do not even have that level of protection. In that language there is no ‘private’, ‘protected’ or other access modifier. What is created in a module it is there. You can use an underscore in front of the method to signal that it is meant to be private but that is more a polite ‘please’ than a harsh ‘thou shalt not’. The philosophy there says that you won’t come to my bedroom, not because I am standing there with a machine gun, but because going there would not be nice.

What sun.misc.Unsafe misery teaches us is that it does not work. Sorry to say, but it seems you need to have a gun in your hand to prevent library users invading your bedroom. That is also what Lukas suggests: put all your library internal code into a single package and make all package private.

But there are also other approaches. If you look at Jira and Confluence and the extensions you can write you see a different approach. By natural evaluation Jira started small and the designers probably never dreamed about such a huge developer community writing all purpose extensions to their software. They simply did not define an API at all. There were the jar files, the classes in them and extensions were free to invoke any method of any class more or less. The result: every extension had to be tested against each version of the software and when you had an extension working with one of the versions of Jira it may not work with the next (minor upgraded) version. Atlassian had a long way to define an API that is stable and is “officially” available for extension modules. Do they put everything else into a single package? I do not think so. Instead they listen to their customers, they have developers forum and they do have empowered employees listening on those channels and understand the needs and their API provides features that are needed by the users.

And this is the more appealing approach. If you provide the features that the users of the library need, they won’t bother to go into the bedroom.

If you do not provide the features, they WILL come in. You can not prevent them doing that, just like you can not prevent teenage sex. If you do provide what they need, they will not use forbidden calls no non API classes.

This is actually what Sun and later ORACLE failed to do properly (imho). They did not provide the features and “unsafe” was just there. They warned us many times not to use that, but they failed to tell what to use instead. And now it all is coming apart at the seams. What will be the consequences?

What I see as most probably scenario is the following:

  • Java 9 will come out without unsafe.
  • Because many libraries make use of the “unsafe” package implementation the industry acceptance of Java 9 will be delayed. The enterprise standard Java version remains 8 (or 7 or 6 in some enterprises) for prolonged time.
  • There will be signs of possible market loss for Java that will drive Oracle to give some solution.
  • There will be some API developed by Oracle providing a limited set of features (most commonly used features) of the current unsafe feature set.
  • Libraries will be modified within few months using the new API.
  • Enterprises will skip to the version that supports the new API.

What I do not expect to change is the attitude of Oracle to customers.

We will see how accurate it was in … two to three years?

Why we do not use comments

When I learned PASCAL programming at TU Budapest in 1986 there was a preprocessor developed specially for student code. It stopped the compilation process if the number of inline comments was less than the number of executable code. There was a rule: we had to have at least 50% of the code meaningful comments. 30 years passed and now we fight inline comments. Clean code purists evangelize not to have inline comments at all and have unit documentation (JavaDoc in case of Java) only on the interface. Anything else explaining the implementation has to be self explanatory from the code itself.

That time there were even tools that extracted inline comments into documentation partially including the executable code. Can you recall WEB and TANGLE? That time it seemed to be very exciting to have a language that can be compiled to TeX for documentation purposes and also to PASCAL so the code could be executed. After 30 years we can see that was a dead end street. We do not mix programming and documentation. We rather separate them.

What is the reason for the change of attitude? Computer scientists 30 years ago were “stupid”? Were they advocating something that was and is bad? Or was that good that time and it is good now? Is there something that radically changed in the world and we live in a different world?

I was thinking about this recently and came to the conclusion that the answer is: A bit of both. The word “stupid” is a bit harsh and rude, but stating that computer scientists did not know as much as they do today is agreeable. After all that is development. If the knowledge remained the same it would mean we are at the point where we were 30 years ago. We learned a lot of things related to computer science. Many of these things are related to human science, and should belong to the area of psychology or something alike. That is one side of the dish.

30 years ago comments were demanded. Today we say that comments are bad among other reasons because they become outdated and misleading. 30 years ago the mantra was to keep the comments maintained along with the code and keep it up to date. Easy to say, but people tend not to follow that advice. For a while you can push the mantra and you can try to force people to keep their comments up to date but that is as futile as forbidding sex for a teenager. It is like trying to command gravity to stop and walk home dry while the raindrops float above your head. Human works differently and you can not alter human mankind. What is the solution we seem learned in 30 years? Adapt practice to what human can and will do.

If comments get outdated and misleading then it is better not to have any. On the other hand we need something to compensate for the loss of the feature comments provided. What we aim now is readable code. And this is the other side of the scale. This is something that changed in the world. We have new programming languages and new tools. If you were required to create readable code in FORTRAN or COBOL so that there is no need for inline comments you would be in trouble. Thus there was the strong push to comment. Those days the comments compensated for the language shortage and the outcome average was better including the misleading comments than naked code.

Today we have Java, Scala, C#, Go, Swift, Ruby, Python. All modern languages (sorry for those I missed) that make it possible to express the behavior and implementation in a readable and concise format that does not need comments. We also use unit tests, something that was unknown 30 years ago, which is more a documentation of the implementation than test. We use code to document, and ever less documentation going from waterfall towards agile. I hope that this is a good direction for some time and I look curious to the future.

Reasons to stay up-to-date and your tasks to help the senses

When you work in an enterprise environment you face many times applications implemented using outdated technology. And most of the developers agree that it is bad. It is bad not only because nobody loves to work with outdated technology but also because it is not good for the enterprise. Outdated technology is never so flexible as the new one, always has more development, maintenance and lost opportunity cost. You certainly have hard time to find an eclipse plugin for the actual version that supports struts 1.0 When there is some bug in the system you are less lucky to find a solution on open source boards. New environments produce easier to use user interface and are more flexible to develop features to follow the ever changing business needs.

All these seem evident and still enterprise environments usually contain a huge load of outdated software. Why? The reason is that change needs demand and the demand many time is lacking. A very good model for corporate change is from Kotter and it says that the first step out of eight steps for change is “sense of urgency”. If there is no sense then there is no action. There may be a need, but if people do not feel the urgency they will not change.

I recall an old story when I was working for Digital Equipment Corp. and we were requested to do a USA export training. We did not feel the urgency no matter how well it was explained why it is important for the company. On a day when the deadline was only a few days ahead I, who have not done the online training yet, got an eMail from the country manager: “Dear Peter, This training is mandatory. You or your successor will do the training. Sincerely: Ferenc” At that point I sensed the urgency.

There are other examples, like global warming, environmental pollution or me being overweight, all that will some time cost something more than just jobs or money.

Why did I tell this story? Because the situation in enterprise IT is similar. There is urgency for updating the technology, but there is a lack of sense. We pollute our environment with outdated technology, we face ever increasing (warming up) maintenance costs, more bugs that are harder to fix and many times a fix just causing other problems.

Technology people are in the position to help the senses. Albeit not exactly the same way as our country manager was doing. Those that are aware of the urgency should make documentation, presentation or any other effective way of communication to deliver the knowledge to those that should have the sense (of urgency) and to raise awareness.

If you are a good developer you should be able to communicate this to the business people. You can convince them to update the technology or else you will face dramatic change in the economy of the company. It may cost jobs and it may cost the enterprise in the long run. That is a problem. Not a tragedy, but a problem. If the company is on the decline and the shareholders decide to squeeze the last drops out of it but are reluctant to invest, the decision not to upgrade to a newer technology may be absolutely reasonable. On the other hand, as a developer you may not want to work there. On the other hand if the company is not on decline but the shareholders still decide not to invest into technology then actually the company is on decline. It is just that they are not aware of it. And again as a developer you may not want to work there.

Best Interview Answer Ever

I am not absolutely sure that this one deserves the title, but it should run for the prize. I swear it is not just made up. It actually happened during a java technical interview where the candidate applied for a senior position.

Q: When you work in a group following agile methodology and scrum what is the velocity of a team?

A: This is 6.1

Code is like public toilet

We, developers, work with legacy code. There are only two types of code: legacy or dead. Before your code dies it becomes legacy unless it was born dead. Legacy code must be dealt with and legacy code is never perfect. Was it perfect when it was created? Perhaps it was. A piece of code can erode because of change of the environment. This environment can be other code, integration interfaces, developer experience. The code that looked okay one day may seem to be disgusting next day or a year later. The code that one team created may just not seem okay to another team. There may be something “real” issue that the industry generally agrees today as bad practice like having 5000 lines god objects, or some discussable things like having many return statements in an otherwise readable and neatly written method. One group may agree to use a variable retval and have one return statement, other schools do not care so long as long other readability issues are not present.

There is one thing that all schools agree: whenever you fix some code in a legacy application you should not leave bigger mess behind you than the mess was when you arrived. What is more: you are encouraged to clean the code up. If there is a bug in a method you fix write a unit test for the fix. If there were no unit tests for the method or class then create. If the method is a mess refactor it (but before that you create unit tests). If the method uses some other methods do not be shy to modify the other method so that their cooperation is cleaner. Do not be shy to modify the argument list, method signature. And if you do that you are also obligated to clean up the mess there as well.

You see the analogy implied in the title. Sometimes when drive is not that strong I just turn around without hesitation and hope that the next place I will find will be less abominable. I am talking about code. But sometimes I just can not do that. After all I am a programmer, that is my job: create good quality code from what is available. If the source is requirement definition we have to deal with those. If we have use case definitions, or vague user stories we go agile and do the best. If the source is mess, we clean up.

That is the life of a coder.

If you do it do it right

This is a philosophical or ethical command. Very general. It is something like “fail fast”. The reason it came up to my mind is that I wanted to compile and release License3j using Java 8 and JavaDoc refused to compile during release build.

This package is a simple license manager, which has some established user base who require that I keep up with the new versions of BouncyCastle. It itself being a cryptography package should not be outdated and programs are encouraged to use the latest version to avoid security issues. When I executed mvn release:prepare I got many errors:

[ERROR] * <p>
[ERROR] /Users/verhasp/github/License3j/src/main/java/ error: unexpected end tag: </p>
[ERROR] * </p>
[ERROR] /Users/verhasp/github/License3j/src/main/java/ warning: no @param for args
[ERROR] public static void main(String[] args) throws Exception {
[ERROR] /Users/verhasp/github/License3j/src/main/java/ warning: no @throws for java.lang.Exception
[ERROR] public static void main(String[] args) throws Exception {
[ERROR] /Users/verhasp/github/License3j/src/main/java/com/verhas/licensor/ warning: no @param for expiryDate
[ERROR] public void setExpiry(final Date expiryDate) {
[ERROR] /Users/verhasp/github/License3j/src/main/java/com/verhas/licensor/ warning: no description for @throws
[ERROR] * @throws IOException
[ERROR] /Users/verhasp/github/License3j/src/main/java/com/verhas/licensor/ warning: no description for @throws

New JavaDoc Wants You DIR

The errors are there because the java doc of License3j is a bit sloppy. Sorry guys, I created the code many years ago and honestly it is not only the java doc that could be improved. As a matter of fact one of the unit tests rely on network and the reachability of GitHub. (Not anymore though, I fixed that.)

The new Java version 8 is very strict regarding to JavaDoc. As you can see on the “Enhancements in Javadoc, Java SE 8” page of ORACLE:

The javadoc tool now has support for checking the content of javadoc comments for issues that could lead to various problems, such as invalid HTML or accessibility issues, in the files that are generated by javadoc. The feature is enabled by default, and can also be controlled by the new -Xdoclint option. For more details, see the output from running “javadoc -X”. This feature is also available in javac, although it is not enabled by default there.

To get the release working I had the choice to fix the JavaDoc or to use the configuration


in pom.xml. (Source is stackoverflow.)

But You Just Won’t DIR

You can easily imagine that you will opt for the second option when you are under time pressure. You fix the issue modifying your pom.xml or other build configuration and forget about it.

But you keep on thinking about why it is the way like that? Why is the new tool strict by default? Is it a good choice? Will it drive people to create better JavaDoc?

(Just for now I assume that the aim of the new behavior was to drive programmers to create better JavaDoc documentation and not simply to annoy us.)

I am a bit suspicious that this alone will be sufficient to improve documentation. Programmers will:

  • Switch off the lint option.
  • Delete JavaDoc from the source.
  • Write some description that Java 8 will accept but is generally meaningless.

or some of them will just write correct java doc. Some of them who were writing it well anyway and will be helped by the new strictness. How many of us? 1% or 2%? The others will just see it as a whip and try to avoid. We would need carrot instead. Hey, bunnies! Where is the carrot?


Get every new post delivered to your Inbox.

Join 1,056 other followers