Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Wednesday, November 12, 2008

Public Methods Should be Like Stories

I believe that most of the developers try to write code to be readable as much as possible. I will try to explain how I try to achieve this. From my point of view one of the most important things is to write public methods as stories. This means when somebody is reading your public method its implementation should tell with the sentence like methods what it tries to achieve. This way one can concentrate on the business logic that the method tries to achieve and not how that is achieved.

So I try to follow few short rules:

  • Instead of code within public method call number of private methods
  • Avoid loops
  • Try to minimize if statements
  • If private method is hard to read apply this rules to private method

Following this rules your public methods are easy to understand. It is easier to test if you are doing black-box testing. What may happen to your code is that you will have number of private methods if you implement mentioned rules also on private methods. But I don't consider this to be bad because in that case even private methods are easy to understand so if one should change your code it will be easier.

As opinion is easier to understand through example, I will show one method from my http://www.flexiblefeeds.com site.

Although example is in groovy I believe it will be easily understandable for all developers. Currently method looks like this:

def currentUserVote(Long articleId, boolean upVoting) {
boolean canVote = canCurrentUserVote(articleId)

if (!canVote) {
return
}

vote(articleId, upVoting)

registerVoting(articleId)
}

I believe that is is easy to understand what the method does from the code itself. But to be sure, first it is checked if current user can vote. If user cannot vote method returns. If user can vote voting is done and then voting is registered.

Now let us see how this method can look like if the code would be embedded into this public method.

def currentUserVote(Long articleId, boolean upVoting) {
// decide if user can vote
if (!loggedInUserIsAdministrator()) {
return
}

// logged in user can vote if he didn't voted
if (userIsLoggedIn()) {
return !voted(loggedInUser().id, articleId)
}

// not logged in user can vote if he didn't voted and data is stored in session
if(votedInSession(articleId)) {
return
}

// perform voting
try {
String sql
if (upVoting) {
sql = "SQL_FOR_UP_VOTING"
} else {
sql = "SQL_FOR_DOWN_VOTING"
}
Article.executeUpdate(sql, [id:articleId])
} catch (Exception ex) {
log.error("Failed to vote up for article ${articleId}", ex)
throw ex;
}

// register voting
if (loggedInUser()) {
def a = Article.get(articleId)

try {
ArticleVoting voting = new ArticleVoting(user:loggedInUser(), article:a)
voting.save(flush:true)
} catch (Exception ex) {
log.error(ex)
throw ex;
}
} else {
if (!session().votedIds) {
def votedIds = [] as Set
session().votedIds = votedIds
}
session().votedIds.add(articleId)
}
}
Having look at this method you can notice it is possible to understand what is method doing. But beside understanding what is method doing you are reading code. It means you are doing two things at the same time. Trying to understand business logic and trying to understand how this business logic is achieved.

Therefore in all cases I would recommend to refactor such code and to extract parts of the public methods into private methods.

Thursday, October 9, 2008

javax.faces.el.PropertyNotFoundException

This is another interesting bug we had in just two days. Again one of those "this is not happening to me" bugs :)

We have JSF project and on JSF projects you are creating managed beans and setting values to those beans within faces-config.xml file.

Well for one of the new managed beans we got javax.faces.el.PropertyNotFoundException. In the first moment it seemed like one of standard typo errors but after verifing the code everything seemed ok but JSF was just refusing to set value of the managed been. Again, after some googling we found solution in this post.

Well shortly, this problem occurs if you have variable in the managed bean that starts with lower-case character after which immediately follows upper-case character. So variables with the names like: xCor, xStreamConverter or similar cannot be found by JSF and finish with the
javax.faces.el.PropertyNotFoundException exception.

java.util.MissingResourceException

These days we had two very strange errors during build of project. Our build configuration is CruiseControl with Maven.
When building project locally everything worked fine while on CruiseControl we got this error:
java.util.MissingResourceException: Can't find resource for bundle com.sun.tools.doclets
.formats.html.resources.standard, key doclet.malformed_html_link_tag
First surprise was why everything works fine locally but fails on the build server. But answer we found quickly. On build server project was build with mvn clean site but locally we are mainly using mvn clean package. After using mvn site locally we got the same error. And then we started with investigation. After hours of investigation we found solution and the problem is described with this Jira issue.

Shortly, with some build versions of Java 5, generation of javadoc will fail if there is <a somewhere in java doc.

So when writing java doc avoid <a characters sequence.

Thursday, July 3, 2008

Jasper Reports and JDK vs JRE

Although it was clear to me what happened immediately as I saw stacktrace, I was surprised that it didn't came to my mind during development. One of the tasks I had was to create report in the very simple application. As I wasn't sure about structure of the report and all the fields that should appear in the report I have decided to use jrxml file. jrxml file is XML definition of report and to display it you have to compile it during runtime. The code to do this is actually very simple:

JasperReport report = JasperCompileManager.compileReport("report.jrxml");
When you have instance of the report it is enough to use JasperFillManager to fill it with data.Another possibility is to compile jrxml file to jasper report. This will generate jasper, binary version of the report. When you have compiled report of course you don't have to compile it during runtime.Well, more or less I had XML version of the report, created installation using Null Soft installer, installed it on my computer and everything worked fine. I could create domain objects and display and print reports. So I was happy and delivered the installation to customer (in this case my mom). She installed application without problems, entered necessary data and tried to open report. And then to my surprise report didn't opened but there was message about unexpected error. As soon as I saw the stacktrace it was clear that actually she does not have java installed with JDK but as JRE.And of course JRE is not delivered with compiler and therefore application was not able to compile report. As soon as I changed application to read compiled report everything worked fine. So if you plan to deliver Java application to standard user computers, don't forget to test application on computers where only JRE is installed.