Friday, July 17, 2009
Groovy and Grails help build apps faster
Usually I am not posting links to other articles but my feeling is that this one deserves this. I didn't notice link to this articles on other grails/groovy related sites so I want to share it.
So navigate to "Groovy and Grails help build apps faster" to read the whole case.
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.
Sunday, August 17, 2008
svn: inconsistent line ending style
Today I was adding grails tutorials into SVN repository. Yes I know it should be in the repository long time ago :). And something that should be simple operation finished with the svn:inconsistent line ending style. For those who didn't still hit this problem, SVN finishes with this error if you have different line ending styles in the same file. And it will refuse to add such files into repository till it is not fixed. As there was more than one file with such problem (few hundreds of them) manual intervention was not an option. But to my surprise (after googling) I was not able to find how to fix it automatically for all the files. So I decided to write a groovy script that will fix it for me.
And without too much waiting groovy script is here:
if (!args) {
println "Usage: <path_to_directory>"
println "And: <existance of extensions.txt comma separated values file with file extensions to convert>"
return
}
Convert c = new Convert()
c.convert(args[0])
class Convert {
Set extensions = new HashSet()
public void convert(String path) {
extensions()
println "extensions to convert: ${extensions}"
File f = new File(path)
convertDir(f)
}
private void convertDir(File f) {
def sum = 0
def filesFound = 0
def filesVisited = 0
f.eachFileRecurse{File file ->
filesVisited = filesVisited + 1
if (shouldConvert(file)) {
filesFound = filesFound + 1
if (filesFound % 100 == 0) {
println "Files checked: ${filesFound}"
}
if (replaceLines(file)) {
sum = sum + 1
if (sum % 10 == 0)
println "Replaced eol in files: " + sum
}
}
}
println "Files converted: ${sum}"
println "Files checked: ${filesFound}"
println "Files visited: ${filesVisited}"
}
private boolean shouldConvert(File f) {
return extensions.contains(extension(f))
}
private String extension(File f) {
int idx = f.getName().lastIndexOf('.')
if (idx != -1) {
String result = f.getName().substring(idx + 1)
return result
} else {
return null
}
}
def replaceLines = {File f ->
String text = f.text
if (text.contains('\r\n') || text.contains('\r')) {
text = text.replaceAll('\r\n', '\n')
text = text.replaceAll('\r', '\n')
f.write(text)
return true
}
return false
}
private void extensions() {
File f = new File("extensions.txt")
String content = f.text
String[] str = content.split(",")
Set extensions = new HashSet(Arrays.asList(str))
extensions.each{
it = it.replaceAll('\r\n','')
this.extensions.add(it)
}
}
}
To be able to use this script you have to install groovy. Then in the same directory where you have your file you need to create extensions.txt file that contains list of file extensions that should be checked. Extensions should be comma separated without spaces in between.
Then run the script with groovy convert.groovy <path_to_directory>.
Now what is visible in this simple script is how groovy extensions to the java.io.File help us to work with files and directories. Actually if you go through code you will see that following methods have been used:
- f.eachFileRecurse - will recursively traverse of files in the directory structure
- f.text - will return you content of the whole file as String
- f.write - will write string as a context to the file
Well you can use this script if you have the same problem but you know that script is provided as is and in the case of damage I will not feel responsible any way.
Thursday, August 7, 2008
Grails, Groovy, XML
Last few days, while working on grails tutorials, I needed to translate some Grails domain objects to XML. I thought it should not be so hard as there is lot of articles about Groovy and XML. But what I found out is that most of the articles present only the simple usage of Groovy XmlSlurper. One of the examples would be:
def xml = new groovy.xml.MarkupBuilder()
xml.person(id:99){
firstname("John" )
lastname("Smith" )
}
And what I need is to traverse recursive structure of domain object. I know it is not so hard but anyway I decided to describe it here. At the end, as you will see it is very simple. But, by the way I will also explain how Grails supports XML transformations.
Let start with Grails support. If you don't request special structure of XML but it is enough to directly transform domain object to XML then Grails is excellent solution for you.
Domain object to translate is:
class LearningArea {
String title
String description
Date dateCreated
Date lastUpdated
List tutorials
List subAreas
static hasMany = [tutorials: TutorialLink, subAreas: LearningArea]
static constraints = {
title(blank:false, minSize:3, maxSize:500)
description(blank:false, maxSize:3000)
}
public String toString() {
return title
}
}
In Grails you can translate object to XML as in following example:
LearningArea learningArea = LearningArea.get(1)
String xml = render learningArea as XML
But interesting thing to notice is that render can be imported from two packages:
grails.converters.XML and grails.converters.deep.XML
And of course there is difference which package you use.
If you use deep package complete domain objects tree (with all sub areas's, sub areas and so on...) will be generated with all the properties. So in the case of LearningArea complete tree of all subAreas and all tutorials will be translated to XML including all properties.
If you use just converters.XML package, top level object is fully translated but referenced objects are translated only to the level of ids. This means that XML generated will be much smaller but to obtain additional information you need to retrieve additional data later.
Unfortunately for me, I couldn't use this Grails XML magic because I didn't want tutorials in the XML but I wanted full tree of subAreas only with titles and without description properties. So I had to use Groovy XmlSlurper. Important thing to notice in the above example of XmlSlurper is that when using XML builder, you can also provide closures. So all I needed was to recursively traverse the tree of the subAreas. And the code to do that is very simple:
def generateXML= {
def writer = new StringWriter()
MarkupBuilder xml = new MarkupBuilder(writer)
LearningArea lr = LearningArea.findByTitle("Groovy")
toXml(lr, xml)
String str = writer.toString()
}
private void toXml(LearningArea la, def xml) {
xml.learningArea(name: la.title, id: la.id) {
la.subAreas.each {
toXml(it, xml)
}
}
}As we can see all the logic is in the toXml method. This method accepts instance of LearningArea and MarkupBuilder, writes element learningArea to XML with attributes name and id, and the as subelements recursively writes all sub learning areas. This way the complete XML tree is generated in few lines of code and I got example that is little bit more complex than most of the examples on the web.
And if you didn't visited grails tutorials yes, you can do it now :)
Saturday, June 28, 2008
Book Review: Groovy Recipes
If you are Java developer and want to jump on Groovy wagon fast this book is excellent start. You will get introduction into Groovy and be able to use Groovy immediately as you finish with the book or related chapter of the book.
For those who have no knowledge about Java or Groovy I would not recommend this as a first book about Groovy. Even it is not stated that way, I believe that book expects at least some knowledge of Java.
The main minus for the book are poorly described closures. I believe that closures are really important part of the Groovy language and would expect better explanation. If you have no knowledge about Groovy closures, read some articles on the web to gain more knowledge about them.
Book is divided into 12 chapters.
Chapters 1 and 2 are introductory chapters describing in general what is Groovy, how to install it and how to integrated with the most popular IDEs.
Chapter 3 is dedicated to "special" (no Java like) constructs of language where you will learn about autoboxing, operator overloading...
Chapter 4 describes how to integrate Java and Groovy and vice versa. You will learn how to compile Groovy code to Java classes and how to solve some possible tricky dependencies issues.
In Chapter 5 you will see how you can use Groovy from the command line.
Chapter 6 is very interesting and you will see how easy it is to work with files within Groovy. This chapter is very useful for Java developers because they would ask themselves why Java file handling cannot be as easy. In Groovy you can read content of the file, you can list content of the file literally with the line of code.
Chapter 7 and 8 are even bigger "wows" for the Java developers. These chapters describe how Groovy handles XML. You will learn how to read XML file with XmlSlurper and XmlParser and how to create XML with MarkupBuilder and StreamingMarkupBuilder. For those that are used to to work with XML in Java this chapter will be proof that working with the XMLs need not to be painful.
Chapter 9 is devoted to web services and there is very nice introduction to different types of requests like: http get, post, SOAP request, XML-RPC request and others.
Chapter 10 is about metaprogramming. Metaprogramming is dynamic part of the Groovy language and the Groovy language option that make Grails so good web development framework. This is the chapter I liked the most.
Chapters 11 and 12 introduce Grails, web development framework based on Groovy.
Monday, June 16, 2008
Tag Cloud Added to Grails Tutorials
The main difference between tag cloud on grails tutorials compared to tag cloud on other sites is that it is enough to be logged in to change (add/remove) tags on any tutorial.
So far there is no possibility to add new tags, you have to reuse precreated set, but if there will be interest I plan to add this possibility too.
For tag cloud implementation I used Act As Taggable Plugin
This plugin give you boost at the beginning but from my point of view still misses lot of support functionality that I had to implement. I hope that in next days I will be able to organize code I implemented for tag cloud features and provide it to 'act as taggable plugin'. This way everybody can reuse what I had implemented and don't have to reimplement the same thing again.
If time permits me for sure I will write at least one post about tag cloud implementation on grails tutorials.
If you have any ideas or proposals for grails tutorials please let me know. I would be happy to have more responses from those who visit grailstutorials.com
Thursday, June 5, 2008
GrailsTutorials.com now supports RSS, Star Rating and Click Count
During development of RSS feeds and star rating I have hit some not too complicated but interesting problems and challenges. I will write separate posts about those challenges.
And as usually, just to remind you, register and post interesting links.
In the case of any feature requests, bugs or just comments do not hesitate to comment to this post.
Tuesday, May 27, 2008
Grails Tutorials
For me it is only alpha version but I believe it can be useful already. You are able to register, to post link and to search among posted articles. I hope that in the near future there will be much more features like tags, rating, hierarchical search...
As you find interesting article, just paste link to that article here so the all community of Grails and Groovy practicioners can benefit from it. This way our knowledge will be focused and the Grails and Groovy community will be able to grow even faster.
To understand how I see future development of www.grailstutorials.com just visit vision section.
And don't be lazy and post some interesting links :)
Monday, January 21, 2008
grails excellent web framework
I have downloaded grails, opened tutorial and had hello world example in 60 secs. I couldn't believe it. With JSF combined with Facelets, RichFaces, MyFaces (what is advisable as technology stack) for hello world you need hours of configuration. Sometimes even when you use RAD tools like Red Hat Developer Studio.
This increased my courage and I continued reading some advance tutorials. Tutorial is nice and it seemed to easy to be true. So I gave it a try. I downloaded the book from infoQ and followed instructions from the book (the whole book). I didn't use tutorial because I wanted to try much wider approach than one covered in tutorial. Everything worked smoothly. For me this is excellent discovery. After using JSF and lot of surrounding technologies, I got framework with which it is really easy to create web applications. So far it seems that with grails web application development is as it should be: easy and fun.
I am sure I will continue to investigate grails and as I have some decision possibilities I hope that maybe we will do some commercial project with it.
My advice:
If you didn't try grails yet, try it right now, you will be pleasantly surprised.