In this example I will show how templates and taglibs can be used to create components.
Imagine that you are creating application for managing projects. When working with an application you are always working within a scope of project. So all the time you need to be able to change project you are working with. So excellent place for selection would be top of the each page within application. So lets go through steps creating such application.
To create project in the command line type:
grails create-app project_manager
Then create Project domain class:
grails create-domain-class Project
Change the code of Project class so it looks this way:
class Project {
String title
String description
static constraints = {
title(blank:false, unique:true, nullable:false)
}
}
To generate controller and views for Project class use:
grails generate-all project
This should be enough to be able to start application with "grails run-app" and then open http://localhost:8080/project_manager
Well, my intention is only to place combo box somewhere on the top of the page so you can select project with which you want to work. To find out how to remember selection within session scope take a look at my post. That part will be skipped here.
Se lets return to the problem. We want to have possibility to display combo box that will enable user to select project with which she wants to work.
Let start with the simplest solution.
I will change the grails-app/views/layouts/main.gsp by adding before <g:layoutbody> following :
<g:form controller=\"project\">
<g:select name=\"project.id\" from=\"${Project.list()}\" value=\"${session.projectId}\">
<g:actionsubmit class=\"edit\" value=\"Select\" action=\"selectProject\">
</g:actionsubmit>
</g:select></g:form>
Simple enough and solves my problem. But later on, if I change my mind and don't want to have possibility to select project on each page but only from some pages, I will have to copy/paste given code to all pages. It is not so complicated, but may be a problem if I want to change something within those 4 lines of code. In that case I would have to change it in lot of places. It means something has to be changed.
Let create template from given code snippet.
Luckily, creating templates with grails is simple enough.
Create file _projectSelectionTemplate.gsp and place it to e.g. grails-app/views/common.
Code within this template is the same as one added to the main.gsp
Now it is time to update our main.gsp file. Old part of project selection exchange with following line:
<g:render template="/common/projectSelectionTemplate"/>
This is for sure simplier and easier to understand than the first version of project selection.
But still, this structure with <g:render.... looks little bit strange.
So let simplified it even more :)
Let create tag lib that can be reused.
So create grails-app/taglib/ProjectSelectionTagLib.groovy file.
Content of this file should be:
class ProjectSelectionTagLib {
def selectProject = {attrs, body ->
out << render(template:"/common/projectSelectionTemplate")
}
}
This way we have defined tag selectProject that will render template _projectSelectionTemplate.
Now, I can even more simplify main.gsp.
Change <g:render... part with the following:
So the final result is:
<g:selectProject/>
This is now very simple, we have tag that can be reused in any place where we need it and it is easy understandable.
Lot of things can be accomplished this way and it is obvious that grails is good web framework because everything seems to be so easy :)
Wednesday, February 13, 2008
Tuesday, February 5, 2008
Daily Scrum - (Wrong) Order of Questions?
Daily scrum meeting is time boxed meeting held on the each day of the sprint. This meeting is short (should not take more than 3 minutes per person), is informative and should help team to organize. Daily scrum is for developers and only developers are allowed to speak during daily scrum. All others are welcomed but they are not allowed to speak.
During daily meeting each developer, one by one, answers to three questions:
1. What did you do yesterday?
2. What will you do today?
3. Are there any impediments?
Simple enough. Short enough. Very important.
The main goals of the daily scrum can be summarized as:
- everybody are informed what is happening
- everybody are aware about possible risks
- team can organize what will implement up to the next daily scrum.
The second question (what will you do today) and the third item of daily scrum summary (team can organize work) leads me to the point that order in which questions are asked is wrong.
If the user stories are small enough, everybody can promise what they will implement up to the next daily scrum. But very often that is not a case. Features are bigger, contain number of tasks, and having more than one developer on a feature in lot of cases can increase overall productivity.
So it seems to me that in the first round, all developers, one by one, should be asked two questions: "Whad did you do yesterday?" and "Are there any impediments?"
When everybody answers these two questions, team all together should discuss and decide who will implement what up to next daily scrum. This way, team selects the best possible way to achieve the final result, sprint goal. Also this way daily scrum gives you even better satisfaction of rule: team can organize work for the next working day.
Up to recently, we have been doing daily scrums by the book. Everybody had to answer three questions asked. But very often, it happened that after daily scrum, when we started with implementation, we changed our promises of what we will implement because we noticed there is much better path to increase productivity.
Because of that we changed order of questions as described above. And now, at the end of daily scrum we decide who will participate on which feature. To me this seems as better approach. After some time, when we have used to this approach, our daily responsibilities are better organized and we have feeling that we are doing it right.
What I would like to mention one more time is that I am aware that if user stories are small enough this approach need not to be necessary, but when user story is bigger and contains number of tasks, organizing developers to work on one feature can increase productivity. Even when user stories are small enough, and they are more or less independent, very often there is indirect dependency between them (e.g. architectural), and when this dependency is noticed by the developers having them work together on these user stories can increase productivity (in the worst case you will need less refactoring)
During daily meeting each developer, one by one, answers to three questions:
1. What did you do yesterday?
2. What will you do today?
3. Are there any impediments?
Simple enough. Short enough. Very important.
The main goals of the daily scrum can be summarized as:
- everybody are informed what is happening
- everybody are aware about possible risks
- team can organize what will implement up to the next daily scrum.
The second question (what will you do today) and the third item of daily scrum summary (team can organize work) leads me to the point that order in which questions are asked is wrong.
If the user stories are small enough, everybody can promise what they will implement up to the next daily scrum. But very often that is not a case. Features are bigger, contain number of tasks, and having more than one developer on a feature in lot of cases can increase overall productivity.
So it seems to me that in the first round, all developers, one by one, should be asked two questions: "Whad did you do yesterday?" and "Are there any impediments?"
When everybody answers these two questions, team all together should discuss and decide who will implement what up to next daily scrum. This way, team selects the best possible way to achieve the final result, sprint goal. Also this way daily scrum gives you even better satisfaction of rule: team can organize work for the next working day.
Up to recently, we have been doing daily scrums by the book. Everybody had to answer three questions asked. But very often, it happened that after daily scrum, when we started with implementation, we changed our promises of what we will implement because we noticed there is much better path to increase productivity.
Because of that we changed order of questions as described above. And now, at the end of daily scrum we decide who will participate on which feature. To me this seems as better approach. After some time, when we have used to this approach, our daily responsibilities are better organized and we have feeling that we are doing it right.
What I would like to mention one more time is that I am aware that if user stories are small enough this approach need not to be necessary, but when user story is bigger and contains number of tasks, organizing developers to work on one feature can increase productivity. Even when user stories are small enough, and they are more or less independent, very often there is indirect dependency between them (e.g. architectural), and when this dependency is noticed by the developers having them work together on these user stories can increase productivity (in the worst case you will need less refactoring)
Sunday, February 3, 2008
How to remember selection with grails
I am new to the grails web framework and coming with intermediate background on JSF. That may be the reason why I needed so much time to find out how to remember selection within tag.
The scenario is following:
When application starts, from the combo box user selects context in which he wants to work and then all queries on domain objects are restricted to this context.
E.g. You select an author, and then when searching for book you always get only books from selected author.
So this selection should be remembered as long as it is not changed. After all, of course, solution is very simple. Just place your selection into session context and then before executing any action read selection from the session.
(This is obvious now but need not to be so obvious to somebody with JSF background as for the most of the time you need not to place explicitly into session when working with JSF)
So let make very short and not full example.
Selection tag may look like this:
g:select name="author.id" from="${Author.list()}" value="${session.authorId}" optionkey="id" noselection="['':'--select author--']"
Action in controller may look like this:
def list = {
if(!params.max) params.max = 50
params.sort = "priority"
params.order = "desc"
def list
//PART WHERE WE TAKE CARE ABOUT AUTHOR BEING CORRECTLY PLACED INTO //SESSION
boolean authorIdInParams = params.author && params.author.id
boolean authorIdInSession = session.authorId
if (!authorIdInSession && !authorIdInParams) {
println "author id unspecified"
[bookList:list]
return
}
// if author is within params it means we have reselected another author
if (authorIdInParams) {
session.authorId = params.author.id
}
// if we are here author is definitly within session
def author = Author.get(session.authorId)
def result = Book.findAllWhere(author:author)
[ authorList: result ]
}
The scenario is following:
When application starts, from the combo box user selects context in which he wants to work and then all queries on domain objects are restricted to this context.
E.g. You select an author, and then when searching for book you always get only books from selected author.
So this selection should be remembered as long as it is not changed. After all, of course, solution is very simple. Just place your selection into session context and then before executing any action read selection from the session.
(This is obvious now but need not to be so obvious to somebody with JSF background as for the most of the time you need not to place explicitly into session when working with JSF)
So let make very short and not full example.
Selection tag may look like this:
g:select name="author.id" from="${Author.list()}" value="${session.authorId}" optionkey="id" noselection="['':'--select author--']"
Action in controller may look like this:
def list = {
if(!params.max) params.max = 50
params.sort = "priority"
params.order = "desc"
def list
//PART WHERE WE TAKE CARE ABOUT AUTHOR BEING CORRECTLY PLACED INTO //SESSION
boolean authorIdInParams = params.author && params.author.id
boolean authorIdInSession = session.authorId
if (!authorIdInSession && !authorIdInParams) {
println "author id unspecified"
[bookList:list]
return
}
// if author is within params it means we have reselected another author
if (authorIdInParams) {
session.authorId = params.author.id
}
// if we are here author is definitly within session
def author = Author.get(session.authorId)
def result = Book.findAllWhere(author:author)
[ authorList: result ]
}
JSF does not call action in managed bean
In the few previous days I had the same problem more than once. For some reason, action in managed bean was not called from JSF page. I was searching through the Internet but couldn't find any real help although more than one person had the same or very similar problem.
Here is situation I had. There is JSF page with the form, some input fields and button that should call action on managed bean. When you click the button action should be called but nothing happens. There is no error displayed nor you can find out where the call is lost. After some investigation it turned out that this appear each time when JSF does not succeed to map values form page to values in managed bean. But there is no clue which values are not binded correctly. I know this is validation and conversion problem and in some cases immediate="true" should solve the problem but in my case even that didn't help.
So how do I solve such situations. There is no straightforward solution for this but following should work in the most of the cases:
Remove field by field in your JSF page. Then redeploy application and try if your method works. Maybe even you need to remove combination of fields to make your action being called.
When you find out which field(s) are cause of the problems you can concentrate on those fields and solve the problem.
What I found out in my cases was:
Here is situation I had. There is JSF page with the form, some input fields and button that should call action on managed bean. When you click the button action should be called but nothing happens. There is no error displayed nor you can find out where the call is lost. After some investigation it turned out that this appear each time when JSF does not succeed to map values form page to values in managed bean. But there is no clue which values are not binded correctly. I know this is validation and conversion problem and in some cases immediate="true" should solve the problem but in my case even that didn't help.
So how do I solve such situations. There is no straightforward solution for this but following should work in the most of the cases:
Remove field by field in your JSF page. Then redeploy application and try if your method works. Maybe even you need to remove combination of fields to make your action being called.
When you find out which field(s) are cause of the problems you can concentrate on those fields and solve the problem.
What I found out in my cases was:
- Once setter I used was not of void type but returned some value. JSF didn't accept this return value
- Once setter I used was throwing RunTimeException that was not handled correctly
Friday, February 1, 2008
The Car Engine on Compressed Air
I am aware that cars and engine cars have nothing with agile software development or any kind of software development but this seems to be very interesting. Very nice, cheap car that you can drive up to 200km on compressed air. Then you compress air again and so on. When it will be available I will probably buy one. Imagine that most of the car in the city work on compressed air.
For more information visit http://www.theaircar.com/
For more information visit http://www.theaircar.com/
Subscribe to:
Posts (Atom)