Grey-Bearded Geek

Random Thoughts Of A Middle-Aged Software Engineer

Apache mod_jk and OS X Lion

October 25th 2011

I just upgraded my MacBook Pro to OS X Lion, and then had to spend a little while getting my development environment working again. There wasn’t too much to fix, but I didn’t find resolutions to all of my issues in one place.

So, here’s what I had to do:

  • The Java environment is not installed by default - run 'java' from the command-line, and Lion will automagically install it.

  • The (legacy) project on which I'm currently working fronts Tomcat with Apache2 using the mod_jk module. After the upgrade, this module is missing. There's nowhere that I could find to download a binary - you have to build it yourself from source.

    • The download of the source can be found at http://tomcat.apache.org/download-connectors.cgi. Instructions for building it on Lion are at http://www.malisphoto.com/tips/tomcatonosx.html.

    • To be able to build the source, you have to install XCode from the App Store. Note that the App Store only installs the XCode installer, not XCode itself. You still have to run the XCode installer. Then (and this is the part that took me a while to figure out), you have to reboot. Otherwise you get errors when running the configure script.

  • Finally, Apache was up and running, (I could see it by running netstat), but I couldn't connect to it. Further investigation revealed that I could connect to it using my '.local' machine name, but not 'localhost' or any of the other aliases that I had in /etc/hosts. The answer, which I found at http://www.justincarmony.com/blog/2011/07/27/mac-os-x-lion-etc-hosts-bugs-and-dns-resolution/, is that Lion does not allow (or rather, does not work properly with) multiple host names per line in /etc/hosts. Putting one per line fixed the problem.

Now, all seems to be well with my development environment (we’ll see….)

Hopefully, this has helped you to get yours running smoothly as well.

Posted in: Chariot, OS X, Apache, Tomcat

Notational Velocity on Android

August 10th 2011

I’ve been using Notational Velocity for note-taking on my Mac for a while now, and can highly recommend it. It’s a wonderfully minimalistic interface, and “just works” for text. I used to use Evernote, but found that I don’t really need all of the features and multiple media types – NV feels like the right fit.

Notational Velocity syncs with SimpleNote, but until recently, I hadn’t seen a decent way to access my NV notes from my Android phone. A couple of months ago however, Notational Acceleration appeared on the scene. It syncs NV notes through SimpleNote. It’s not quite feature-complete yet, but for basic syncing, reading, and writing of notes, it has the same minimalistic feel as Notational Velocity, and “just works”. I highly recommend it.

Posted in: Android

A Beginner's Take On Git

July 29th 2011

Git, for those of you who have been living under a rock, is a a very popular distributed software revision control system.

It has been around since 2005, and has been gaining quite a bit of traction over the last several years. Git is one of those things that I’ve been meaning to try on my own time for a while, but a few months ago, I started a new project, and decided to dive in.

Even after reading all of the Git tutorials and watching the videos, it took the team a while to find a Git workflow that made day-to-day development go smoothly. The workflow that we eventually adopted works very well for us, and I haven’t seen this exact workflow explained anywhere else, so I thought I’d document it here in the hope that it well help someone else.

If you are an experienced Git user, and you see danger lurking in this workflow, or just know of a better way, please let me know in the comments.

If you have not tried Git or any other distributed revision control system, I urge you to try one. For a long time, I questioned the need for a distributed revision control system, and was relatively happy with Subversion. Now that I’ve used Git, I understand what all of the noise was about. There are many advantages to this type of system that do not have anything directly to do with whether your team is distributed or not. Now, I’d never go back to Subversion if I didn’t have to. And if I did, I’d use git-svn.

My basic goal when working out this workflow was to minimize Merge Hell. We’ve all experienced Merge Hell, especially when using either CVS or Subversion. All of the Git documentation that I read made it seem like Git could help considerably with staying out of this situation. However, as soon as a second developer joined the team, I found myself in Git merge hell. That event was the genesis for this workflow.

Before I explain the details of the workflow, let me set out a few basic suggestions that I think are a good idea no matter what kind of revision control system you are using:

  • Do all development on a branch, not on the trunk (or in Git terms, on a 'feature' branch, not on the 'master' branch)
  • Commit (and in the case of a distributed RCS, 'push') small changes frequently
  • Endeavor to make difficult merges a local problem - try not to let them affect the rest of the team

The following workflow assumes that you are following the three suggestions above. So, from start to finish on a feature, here’s the basic ten-step workflow:

  1. make sure that your master branch is up to date with the remote repository (git pull master)
  2. either create a feature branch (git checkout -b feature_branch) or switch to an existing feature branch that has been fully merged with the master branch (git checkout feature_branch)
  3. do your work on the feature branch, add the changes to git (git add .), and commit them to the feature branch (git commit)
  4. switch back to the master branch (git checkout master)
  5. make sure that your master branch is up to date by pulling any new changes from the remote repo (git pull)
  6. switch back to the feature branch (git checkout feature_branch)
  7. merge any new changes from the remote master into your feature branch with 'rebase' - this is the 'magic' part (git rebase master)
  8. switch back to the master branch (git checkout master)
  9. merge the feature branch into the master branch (git merge feature_branch)
  10. push your changes to the remote repo (git push origin master)

Ok, so that sounds a bit complicated. Fortunately, some of the steps can be skipped some of the time, and even when you have to do them all, I’ve found that it becomes second nature once you understand the reason for each of the steps, and what each does.

So, here’s a step-by-step explanation:

Step 1 is to simply make sure that you have a current copy of the remote codebase before you start work on a new feature. A no-brainer.

Step 2 is set up the branch on which you are going to do your work. If it already exists, make sure that it’s fully merged into master to make sure that you don’t have to merge it later while you are merging your new changes

Step 3 – do your work

Steps 4 and 5 ensure that your master branch is up to date with the remote repo – this pulls in any changes that have been pushed to the remote master branch while you were doing your work. If there are changes pulled, they will merge cleanly, as you haven’t made any changes directly on your local master (this is why we work on a feature branch). If there were no changes on the remote master (‘git pull’ reported no changes), you can skip steps 7 and 8.

Step 7 merges new changes from the remote master with your work on the feature branch. The magic here is the ‘git rebase’ command. Rebase effectively shelves (temporarily rolls back) the commits that you have made on your feature branch, applies the updates from the master branch to the feature branch, and then ‘replays’ your commits back on top of the feature branch.

The first part, shelving your feature commits and updating the feature branch with the updates on master, when used this way, will always happen cleanly. The second part, replaying your commits, is where you will potentially encounter one or more merge scenarios.

There are some very advantageous things about this step. First, because your local commits are put ‘on top of’ the merged commits from the remote master, it is a ‘cleaner’ merge. Generally, it effectively results in a two-way merge instead of a three-way merge – i.e. merges tend to be easier to do. Second, once you are done, the timeline is easier for everyone to understand. Even though two or more developers may have interleaved commits, it comes out looking one developer committed all of their changes, and then the other developer committed all of theirs. To me this is both magical and invaluable.

Step 8 simply puts you back on the master branch

Step 9 merges your local feature branch into your local master branch. Again, if you have followed the plan, this will be a clean, ‘fast-forward’ merge. Your feature branch and your local master branch are now identical.

Step 10 pushes your local master branch to the remote master branch. Also a fast-forward merge, unless someone else has pushed to the remote master after you did step 5. Unlikely, but possible. Solution left as an exercise for the reader.

Rinse and repeat.

There has been much discussion on websites everywhere about how ‘rebase’ is evil because it rewrites history. I think that it’s important to note that using rebase on commits that have already been pushed to the remote repo is evil. Here, however, we’re rewriting local history, because that’s what makes the ultimate timeline make sense, and we’re not altering any history in the remote repo.

Ok, that’s it. Let the discussion ensue!

Posted in: Chariot, Git

Testing Grails Controllers with Spock Part 2

May 19th 2011

My previous post showed how to get around some of the shortcomings of testing Grails Controllers with the ControllerSpec provided by the Spock testing framework.

I also found that ControllerSpec is a subclass of UnitSpec, so it does not provide transactional rollback. This makes ControllerSpec somewhat undesirable for an integration test.

So, I merged the code for ControllerSpec and IntegrationSpec to create ControllerIntegrationSpec. It works just like ControllerSpec, but executes each test method in a transaction, and rolls the transaction back at the end of the method.

Here is the Groovy source, which can also be found at https://github.com/rfreedman/spock-integration-controller-spec/

Posted in: Chariot, Java, Groovy, Grails

Testing Grails Controllers with Spock

May 13th 2011

I’m starting a Grails project, and decided to use the Spock testing framework. Spock is a very nice way to write tests, and I recommend it highly.

Unit tests with Spock are very easy to write, and Spock’s UnitSpec class provides all of the mocking methods that you would expect to find in a Grails-centric testing framework, including mockDomain, mockForConstraintsTests, and friends.

Here’s one of my simple Spock unit tests for a domain object:

class CompoundInstanceSpec extends UnitSpec {

    def "finding the compound instance's primary name"() {
        setup:
        mockDomain(CompoundInstance.class)

        expect:
        !compoundInstance.primaryName
        compoundInstance.setupPrimaryName()
        compoundInstance.primaryName == name2.name
        compoundInstance.compoundNames.remove(name2)
        compoundInstance.setupPrimaryName()
        !compoundInstance.primaryName

        where:
        name1 = [name: 'name1', primary: false]
        name2 = [name: 'name2', primary: true]
        name3 = [name: 'name3', primary: false]
        compoundInstance = new CompoundInstance(compoundNames: [name1, name2, name3])
    }
}

When it came to integration-testing a Grails Controller, however, I ran into some problems. The first problem was that my Grails-generated controller code used the ValidationTagLib’s message() closure to place internationalized messages into flash scope. Unfortunately, neither Grail’s integration test environment nor Spock’s ControllerSpec class wire the messageSource object into the application context, so the test failed when the controller tried to place a ‘success’ message into flash scope:

flash.message = "${message(code: 'default.created.message',
    args: [message(code: 'compound.label', default: 'Compound'), 
        results.compoundInstance.primaryName])}"

The simple solution (assuming that you don’t need to test the content of the message) is to use MOP programming to override the controller’s message() closure in the test’s setup. The following example always returns “mockMessage” for the value of the message, and allows the test to proceed normally:

setup:
controller.metaClass.message = {args -> "mockMessage"}

A more complete solution would actually wire up the messageSource.




The second problem that I ran into was that the service called by my controller needed to access the currently logged-in user (I’m using the spring-security plugin). When this is being done in the scope of a test, there is, of course, no currently logged-in user, and of course, the test would fail.

The simple solution for this problem is to wrap the body of the test with the SpringSecurityUtils' doWithAuth closure, specifying the username of the user under whose authorization you wish to run the test. Of course, you’ll have to make sure that you either create the user and authorizations (roles) in BootStrap.groovy, or in the test setup.




Here, then, is my integration test with both issues handled:

Notice the ‘message’ fix at line 8, and the ‘security’ fix beginning at line 15


Posted in: Chariot, Java, Groovy, Grails

Premature Optimization

April 8th 2011

We’ve all heard, ad nauseum, that, as Donald Knuth opined over 35 years ago, premature optimization is the root of all evil.

Of course, Knuth was talking about prematurely optimizing code for runtime throughput.

The problem is that it’s almost impossible to know what will need to be optimized unless you actually profile the code under real conditions. When you are first writing the code, time spent optimizing performance will likely be wasted, because the code that you optimize will likely not be an actual bottleneck at runtime.

This doesn’t mean that you should intentionally write poorly-performing code, just that you should generally write it in the most straight-forward, readable manner possible, using reasonable, well-understood algorithms and data structures. When you do this, you wind up with maintainable code (because it is easy to read and to understand), and there is a very good chance that your compiler will optimize your code for you. Virtually all modern compilers, including javac and the Java JIT compilers are optimizing compilers, and JIT compilers optimize on-the-fly at runtime.

I’ve agreed with Knuth’s advice ever since I heard it years ago, and like most folks, have had occasion, especially in the beginning of my career, to find out how correct he was, by optimizing code before bothering to profile it, only to eventually discover through profiling that the performance problem lay elsewhere, in some totally unsuspected bit of code.

So, what’s lost when you optimize code prematurely? What’s the downside? I mostly assumed that the major downside was lost developer time. The time that you spend doing the possibly un-needed optimization is time that you’re not spending adding features, or writing tests, or refactoring the code. Recently, however, I was the recipient of someone else’s prematurely-over-optimized code, and it struck me that premature optimization can have a large negative effect on the stability and maintainability of the codebase.

The code in question was somewhat time-critical, and went to great lengths to avoid storing a single object in HashMap and then looking it up in the HashMap, under certain special conditions. Since both insertion and lookup in HashMap are, on average, O(n), it is possible that the fairly complex nest of ‘optimized’ if/then/else statements might have actually performed worse on average than a simple HashMap put() and get().

What really struck me, however, was the increased complexity, and the decreased readability of the code due to the optimization. Indeed, I was looking at this code because it contained a bug. If the optimization had not been done, the simple put() and get() would have left virtually no room for a bug, and the code would have been vastly more readable, and therefore more maintainable. It would likely have also have had slightly better throughput at runtime.

Particularly for those of us working in corporate enterprises, the bottom line is, well…the bottom line. It’s ultimately all about cost/benefit ratios. The reason that we should be writing clear, maintainable code, writing unit tests, writing clear documentation, and otherwise listening to our Uncle Bob, is because in the long run, it costs less. Doing these things improves the cost/benefit ratio. Premature optimization, when it increases complexity, makes the cost/benefit ratio worse. Therefore, it truly is the root of all evil.

Posted in: Chariot, Java

bash completion for maven

February 14th 2011

Based on a blog post by John Hitchings on the WealthFront Engineering web site, I started looking into bash completion.

As a Java developer, I use Maven from the command-line quite a bit, so I decided to add bash completion for the ‘mvn’ command.

The following script works great on OS X, and should work in bash on other systems as well.

Happy completion!

_mvn() 
{
    local cur prev opts
    COMPREPLY=()
    cur='${COMP_WORDS[COMP_CWORD]}'
    prev='${COMP_WORDS[COMP_CWORD-1]}'
    opts='clean compile package install'

    if [[ ${cur} == * ]] ; then
        COMPREPLY=( $(compgen -W "${opts}"  ${cur}) )
        return 0
    fi
}
complete -F _mvn mvn
Posted in: Chariot, Java, Linux, Mac, Maven

Running Multiple Instances of Mule 3.0

December 6th 2010

I’m working on some Mule services, with the new 3.0.1 version, and need to run multiple instances of Mule on the same physical server.

With Mule 2.x, this was done by running the provided setup_local_instance.sh script to copy some of the Mule directories, and then using the MULE_BASE environment variable to point to the new location.

With Mule 3.0, the script still exists, but deploying multiple instances in this manner does not work correctly.

After some experimentation, what worked for me was to copy the entire Mule installation directory, and set the MULE_HOME environment variable for each new instance.

Posted in: Chariot, Java, mule, SOA

Deploying Services to Mule with maven-mule-plugin

November 15th 2010

I’m still working on the Mule project that I mentioned in a previous post, and am using the new Mule Maven plugin, maven-mule-plugin to package a project for deployment in Mule. It works well for a simple Mule application, however, in my case, I’m providing the mule-config.xml in a jar file on which the project depends.

By default, the maven-mule-plugin looks for mule-config.xml in src/main/app. I’m using the maven-dependency-plugin’s unpack goal attached to the prepare-package phase to extract mule-config.xml from the jar dependency just before the package phase runs. This works, but presents one problem – I have to extract the xml file to the project’s source directory. This is unsatisfactory because it could easily lead to someone checking this file into the version control system – which I’d like to avoid.

I couldn’t find any documentation to this effect, but found by reading the source code to the maven-mule-plugin that the location of mule-config.xml can be configured. I added the following configuration to the plugin, and now have mule-config.xml extracted to the target directory.

<plugin>
   <groupId>org.mule.tools</groupId>
   <artifactId>maven-mule-plugin</artifactId>
   <version>1.2</version>
   <extensions>true</extensions>
     <configuration>
       <appDirectory>${basedir}/target/app</appDirectory>
     </configuration>
</plugin>
Posted in: Chariot, Java, Mule, SOA

Java on OS X - Breathing A Sigh of Relief

November 12th 2010

TechCrunch is reporting this morning that Apple has joined the OpenJDK project, and will be open-sourcing the OS X implementation of Java. They are apparently continuing to support Java SE 6 on Snow Leopard, and will support it on Lion as well. Java SE 7 (when it finally arrives) will be available from Oracle.

As a new convert to the Mac as a Java development environment (just switched a couple of weeks ago) in a shop full of Java developers working on Macs (http://chariotsolutions.com), I think that I speak for all of my co-workers when I say that this is very welcome news.

Posted in: Chariot, Java, Mac