Sunday, January 25, 2009
Favorites Section on Grails Tutorials
The new section is favorites.
Now when you find interesting article on the grails tutorials you can add this article into your favorites. Later on you can access favorites and browse articles. Further on you can browse favorites of other users. Favorites of each user are also exposed as RSS feed so if you like somebody's collection of favorites you can follow it via RSS feed.
"Unfortunately" implementation of this feature was more or less straightforward so there is nothing I could really blog about.
More or less if you created your code with enough templates and custom tags, implementing new feature in most cases is actually adding one or more domain classes, reusing existing services and templates and using dynamic gorm methods.
Well and this is the part I really like about grails. Adding new features usually is more or less matter of hours (not days).
Tuesday, January 13, 2009
Don't forget to ask "why"
Question that raised my interest was:
"What you don't like in agile development?"
And the answer with the most votes started with: "I don't like seeing people focus on "what" and missing "why"."
You can have a look at the full thread here.
And actually asking "why" is one of the main attributes of the agile software development. But as hype was created around agile methodologies everybody are happy with the fast delivery and smaller number of bugs. And some agile teams had adapted to this style. They are developing everything that is thrown on them for the given iteration. Sometimes request does not give sense but it is implemented anyway.
But we should not forget that idea of the agile methodology is to help customer build better software. And we can build better software only if we ask customer "why?".
So next time when you meet strange requirement ask the customer "why?". And keep asking "why" as long as you don't get to the core of the problem. And don't expect that you will get easy to the core of the problem. But when you are at the core of the problem there is big probability that you will be able to propose better solution and thus help customer to build better software.
Don't forget that software development should be fun.
Tuesday, December 2, 2008
Grails Integration Testing - Some Tips and Tricks
As stated in the Grails documentation "Integration tests differ from unit tests in that you have full access to the Grails environment within the test". This actually means that you have access to database, you can inject necessary services into the test class.
All integration tests have to extend GroovyTestCase class.
Database
By default, integration tests use in memory HSQLDB. You can change this by updating DataSource.groovy.
Next important feature to remember is that integration tests run within transaction that is rollbacked after the test. So if you want to have data within database after the testing, in the test specify boolean transactional = false.
Services
To use default injection of specified service classes within test all that is necessary is to specify service as a field in the test class. For the rest magic of the Grails will take care. E.g. example would be FeedService feedService
Domain Classes
Within integration test you can use domain classes same as you would in the regular code. The main difference is that in the most cases methods on the domain classes should be called with the flush:true parameter.
Knowing all these it seems that integration testing with grails is really easy. And it is the case but there are some additional features to take care (some of them are valid also for the production code).
Some Tips
Tip: Saving domain object can fail without any error
Yes this can happen and happens often when you forget about some validation rule. And when you are not aware that your object was not saved your test results cannot be correct.
So for example following code snippet will not save the object but also no exception will be thrown:
FeedSource feed = new FeedSource(feedLink:"http://abc.com", title:"abc")
feed.save(flush:true)
Article article = new Article(title:"afaf", articleLink:"http://abc.com", source:feed)
article = article.save(flush:true)
Reason is that there is 'description' field that is mandatory for the article. To ensure that you don't get such surprises I use following code:
private Object save(Object object) {
validateAndPrintErrors(object)
Object result = object.save(flush:true)
assertNotNull("Object not created: " + object, result)
return result
}
private void validateAndPrintErrors(Object object) {
if (!object.validate()) {
object.errors.allErrors.each {error ->
println error
}
fail("failed to save object ${object}")
}
}
To check that there are no errors in the domain object you need to call method validate(). If there are validation errors you can get them through errors property of the domain object.
Next thing to notice is that method save() of the domain object returns instance of created object if it is correctly saved. So you can check if returned object is different than null.
Code for saving and validating can also be implemented as extension to domain classes using some nice groovy magic. Further on, this methods also works only thanks to groovy magic.
So initial code snippet should be changed to following.
FeedSource feed = new FeedSource(feedLink:"http://abc.com", title:"abc")
feed = save(feed)
Article article = new Article(title:"afaf", articleLink:"http://abc.com", source:feed, description:"asbfasfd")
article = save(article)
In this case there will be no surprise that domain object was not created within database without any exception thrown.
Tip: In some cases you need to reload domain object from database
As base for the GORM magic is hibernate, and we know that hibernate uses cache, there are cases when you need to reload object from database to ensure that it is in correct state. So for example if the rule is that when feed is deleted source of the article should be set to null, following code may fail.
feedService.deleteFeed(feed)
// we are sure that this article exists
article = Article.findByTitle("afaf")
assertNull("Article source should be null but is ${article.source}", article.source)
Reason is that deleting feed will not update source field of the article in the hibernate cache and the last line will fail. To ensure that you really have latest object from the database you should call refresh method on the article.
feedService.deleteFeed(feed)
// we are sure that this article exists
article = Article.findByTitle("afaf")
article.refresh()
assertNull("Article source should be null but is ${article.source}", article.source)
Tuesday, November 25, 2008
Even Agile Projects Need Vision and Concept
So you have heard about this strange word - 'Agile' . After some googling, reading some blogs and maybe some books you hear only promises how you will implement majority of your projects easily, in time and within budget. All you need is to put some team together, write some user stories, estimate them and start doing iterations. You track your velocity, write unit tests and more or less follow best agile practices while coding. And somewhere in the middle you find out that you are lost and not sure what is happening. Then you start to ask your self what had happen?
This is happening probably more often than we would expect. And the reasons are different. I will not try to find those reasons as lot of them are already described and you can find out how to prevent them.
I will concentrate on one that is for unknown reasons rarely mentioned in blogs and even agile books.
Even when you are doing agile software development (XP, Scrum) what you need is concept or vision for the project. But not only in the head but also on the paper. This needs not to be hundred pages document but document that clearly states what are the goals of the project.
In the number of agile posts, your project is starting with writing epics, stories and/or roles. But it is little bit confusing how to get those user stories. Advice you find the most often is to make user stories writing session where moderator guides meeting and the goal is to write as many user stories as possible. But how you can write user stories if you are not aware what is the main goal of the project? To be able to write good user stories (even epics) you must have clear idea what is the vision of the project.
To be able to write good user stories you must have vision document.
Some of the attributes of the good vision document are:
- It is short
- It clearly states goals of the project
- It is read and understood by the software development team (and all other interested parties)
- It is always up to date (changing with the project)
I believe these attributes state that vision document is agile.
So if you are planning new project and want to do it right way I believe correct order of steps would be (note that very often the first step is left out and I believe it is the first mistake in the project):
- Write vision document and communicate it to all interested parties
- Write epics and user stories based on the vision document
- Create your product backlog
- Start with iterations
- After few iterations review the project
- If necessary change user stories
- If necessary change vision document
- Communicate changes in the vision to all team members so they are aware of the new course of the project
So vision document must reflect all the time your current goal of the project and this goal has to be clearly communicated to the team.
Be careful, doing agile project without clean vision and without adapting during the path is impossible.
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.
Tuesday, November 11, 2008
It is very expensive to work with Grails
This post is more advertisement then real post. So if you don't want just don't read it.
Small ad. One of my latest expenses, please have a look at http://www.flexiblefeeds.com.
So lets go to the point. Some time ago I discovered Grails. I tried to write few simple applications. Then I tried to write more complex applications. Then I was investigating advance features.
And very soon, less than a month after discovery, I realized that one is able to write real web applications with Grails more or less within minutes.
But if writing web applications is so easy, why not create real web application and put it on line. And there came the first idea. I wrote http://www.grailstutorials.com, payed subscription 20$/month and put it online. Visitors are coming, site is I believe well known within Grails/Groovy community so it stays online and I am still paying 20$/month. But these money can not be compared with satisfaction having real, visited web site online.
But writing web applications with Grails is still easy. So why not try another application. I implemented (actually still implementing) http://www.flexiblefeeds.com, payed subscription 20$/month and put it online.
Now I have two Grails based applications online, still trying to improve both of them. More or less I have idea about two or three more projects that I want to implement with Grails. What I am missing is time.
So why is it expensive to work with Grails:
- You develop web applications very fast so you will need lot of money to pay web hosting
- You develop web applications very fast so you will need most of your free time just to try all ideas you get
- Grails is growing so fast that you will need lot of free time just to read all the blogs and nice things you can do with groovy/grails
Sunday, November 9, 2008
Flexible Feeds Launched
On this site you can register RSS feed of your blog or feeds of your favorite blogs or web sites. Each feed is registered in different category so you can navigate articles by categories. To help others to decide if it is worth to read article you can vote for articles.
You should give a chance to this site and you will see it can be excellent source of news in the blogging sphere.
Why this site? If you are at least a little bit like me your RSS reader is full of feeds. Feeds are probably added to different folders but you need lot of time only to navigate through all new articles. What I am missing in readers is possibility to have kind of unique view and social aspects like voting on articles and tags on articles.
All that I miss in classic readers is supported in the first release of flexible feeds.
But I don't plan to stop here. I would like to have flexibility with feeds. Maybe I want to have different views for the same category. Or I want to combine different feeds. All this and much more is planned for the next version.
And for the end, I would be glad if you register RSS feed of your blog or feeds of your favorite sites.