Monday, October 25, 2010

Git version control best practices

Keep commits small, they cost nearly nothing to make in git

  • Allows you to easily revert a faulty commit without reverting working code at the same time

  • You can easily get an idea of what happened to the project by simply reading the commit message titles in a history browser

  • No more of those "committed some stuff" commits

Code new features in separate branches, they cost nearly nothing to make in git

  • Allows you to easily return to the latest working state in the master branch when your client wants you to fix a bug discovered on your project's deployment day

  • You can just leave your branch to "collect dust on the shelf", if it turns out that the feature was too time-costly to implement, and continue working on it at any point later
  • Even the "minimal" tasks usually require more commits than you originally thought

Use no-fastforward when merging

  • Because the merged branch groups commits its easier to see which commits belong to the same feature when observing the source history

  • All the commits that make up the feature can be reverted in one step if the branch was found to be faulty

Use add -p to split up modifications into separate commits

  • Related to keeping commits small

Corollary to "Code new features in separate branches"

  • Don't develop directly in the master branch

Use a remote branch if you want to collaborate with other developers on a feature

  • If a feature is too big for you to tackle alone, you should push it to your "main repository". The other developers can then pull it and contribute to it and when the large feature is done it can be merged into the master branch

Tuesday, March 30, 2010

Getting used to Java's Date and Calendar classes

Today I managed to complete the createBooking method of my BookingController. At least it runs without any errors. But the page that shows the week's bookings does not reflect the added booking. I spent quite a lot of time debugging my Calendar-related code. For a while I forgot that its MONTH field's index is zero-based, which caused me a lot of confusion. I was again tempted to start using Joda Time but I would like to refrain from adding too many dependencies. I would also have needed to add joda-time-hibernate and find/create property editors for setting up the Joda Time objects. Sure, this might have been something that would have taken like 15 minutes and worked perfectly, but it could also have led to unwanted trouble.

Anyway, when I was trying to see how far my BookingController was to working, I was doing some really painful manual testing. First I restarted Jetty, then I refreshed my main page, then I had to create a new user, then I went back to the main page, then I clicked the booking time I wanted, then I clicked submit on the form and then finally I would see an exception or error. Not very agile at all. The easiest way to start looking at what's wrong would be to run a separate hsqldb process which I could connect a DB client to and see if my requests have made any changes to the DB. But a better way would be to create a test case that calls my controller instead and then verifies that the expected changes have happened to the database. It would be even better to extract some stuff from my controller so I can test the url routing and form parsing separate from the database-related activities.

Sunday, March 28, 2010

Sorting out how to use Spring Security again

It had been a while since I read about Spring Security. Now that I was trying to create a new booking I had to retrieve the currently logged in user to be able to add the new booking to that user's bookings. So I thought I'd just slap a <global-method-security secured-annotation="enabled" /> in my application-security.xml and then add a @Secured("ROLE_USER") on my method that was mapped to ("/") and Spring should pop up a login form for me when accessing that URL. But unfortunately it didn't work that easily. The page showed up just like before, with no login form in sight. So I went back to reading the Spring Security manual and looking for some posts on Spring's forums and after a while I noticed that other people had solved similar problems by putting the global-method-security element in the same xml file as the one where they set up their Controller beans. Since I use the component-scan element to automatically instantiate my @Controller-annotated classes in my servletname-servlet.xml file, I thought I'd just move the global-method-security element to that file. At first I got a long spew of exceptions and call traces, but that was just related to some incorrectly configured xml namespaces. When I sorted that out Spring Security finally worked.

The exercise also straightened out one misconception I had about spring. I thought the DispatcherServlet's servletname-servlet.xml file created a new application context that was separate from the WebApplicationContext which Spring's context loader sets up. But then I found this in the Spring manual "In the web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext." However I still don't understand why the DispatcherServlet context didn't inherit the global-method-security element from my WebApplicationContext which contained my security beans.

Saturday, March 27, 2010

Registering custom property editors with Spring MVC

Recently I've been able to concentrate much more on more normal coding tasks rather than just figuring out how to configure my application. I got to the point where I wanted to receive data entered and use that to automatically fill in property values for a business object. Fortunately Spring does have support for this. You just add a parameter of the type of your desired object and Spring will setup the properties based on their names from the encoded form values.

Spring has built-in support for conversion from Strings to a large variety of types. But if your business objects has a property of an unsupported type you need to register your own custom property editor that converts a String to that unsupported type. It took me a few tries to get it right but I seem to have gotten my custom editor set up properly now.

The mistakes I made were the following:

First I was trying to set up a CustomEditorConfigurer bean in my application context and use its customEditors property to map my class to an editor. Then I noticed that the customEditors property was deprecated in Spring 3. So I changed my setup to use a PropertyEditorRegistrar instead to register my custom property editor. This still didn't work. Then I figured out that if you just add these as beans in the application context they are probably only available for converting Strings inside that application context. If you want your property editors to be available for binding web requests to objects you need to use Spring's Controller's initBinder method to register your editor with a binder. And if you are using annotation-based controller you additionally need to use the @InitBinder annotation on that method.

Sunday, March 21, 2010

First screen shot


Finally started working more on the actual construction of views and models instead of just figuring out all the infrastructure. I have now added a table to the laundry booking system. The data for the model (times and dates) are automatically generated to show the current week. Tomorrow I'll work more on fixing the links to forms for creating actual bookings. The first version is going to be quite Web 1.0 so there will be page reloads for most actions. So I can spend all my time on working with Java EE instead of Javascript. However when I get far enough I plan to add some Javascript and try out jQuery.

Thursday, March 18, 2010

Finally got my whole Java EE stack completed

Ok just a quick update. Adding spring declarative transaction did the trick. I was now able to add a new user account through the a web form -> Spring Controller -> EntityManager and it shows up in my user list for testing purposes. I'm still gonna finish reading the Spring Transaction chapter and then I think I can finally start working on my domain model and then move on to the Controllers and views.

By the way. Annotation-based Spring MVC seems pretty good. There is a great deal of flexibility both in terms of what types of input your controller methods can take and what output they can return. Spring basically reads your thoughts and figures out what you wanted to do. Well not really, but it's very flexible. It almost feels a bit un-Java-like. Spring MVC with annotations basically fulfills the requirements that made me search for a rest-framework without the rest parts that I don't really care too much about when making a human-facing web application (such as content negotiation regarding different input and output formats, like json and xml.)

Settled on Spring MVC

Ok it wasn't as bad as I briefly anticipated to set up a url redirection scheme for getting nice URLs with Spring MVC. I found this nice answer on stackoverflow that actually linked to a sample MVC project in spring's repository that shows a really easy to use example of how to use the Tuckey url rewriting filter.

Firsty you simply map all your Spring MVC classes under a path like /controllers. Then you set up explicit redirects to all your subdirectories that contain static files like /javascript, /css and so on and anything that doesn't match that gets mapped to a url where the path starts with /controllers. After doing this I almost (but not quite yet) have figured out all the parts to be used in a simple web app. I was able to get my Spring-managed EntityManager injected and managed to get it to run some queries. But I still have to read the Spring manual chapter on transactions because I still don't feel like I know that well how they work yet. I could just follow a tutorial and just use the <tx:annotation-driven> element and annotate my classes and methods with @Transactional and everything would probably work. But like with all other technologies I've been learning for Java EE recently, I don't like using stuff without understanding how they work.