Hopping the Tracks

“It’s time to move on, time to get going
What lies ahead, I have no way of knowing
But under my feet, baby, the grass is growing
It’s time to move on, it’s time to get going”

“Time to Move On” – Tom Petty

Effective July 1st, 2012, I will be joining the Digital Library Services Department at the Hesburgh Library at the University of Notre Dame.

Over the past three years, I have assumed primary development and maintenance of Conductor and worked on several other projects – most notably the ND Campus Map and the OIT Site Redesign implementation.

I am stepping away from a team of remarkably creative, passionate, and professional friends.  During the past three years, I have had the wonderful privilege of watching a team grow and further develop into creative leaders on campus and beyond. We have all pushed ourselves to continually improve what it is we do.

I am stepping into a team that is growing and shifting focus as they work to guide Library Services into an emerging highly digitized and cross-referenced environment. I will be working at process improvement amongst the developers, mentoring, and contributing to Open Source projects (i.e. https://github.com/projecthydra/).  I’m certain there will be other interesting projects that I will work on as well.

I am excited about the opportunity to work day-to-day with several other developers…many of whom I’ve worked with before at my previous job – as of July 1 there will be 4 Lightsky alums working at the Hesburgh Library. In working with other developers, my goal is that we all grow our craft and become passionate and pragmatic programmers.

An interesting bit of trivia, the day that I started at AgencyND was they day that I was scheduled to have my first face-to-face interview at the Hesburgh Library – there were a lot of vacations and conferences that pushed my initial Library interview back.  Instead of taking a chance that I would get the Library position, I opted to take the position at AgencyND – a decision that was right for me at the time.  Instead, my former and soon to be again co-worker, Dan Brubaker-Horst got the position.

What I’m Reading…And Why

Books that I’ve Been Reading

  • “Clean Code: A Handbook of Agile Software Craftmanship” by Robert Martin
  • “The Clean Coder: A Code of Conduct for Professional Programmers” by Robert Martin
  • “Domain Driven Design: Tackling Complexity in the Heart of Software” by Eric Evans
  • “Working Effectively with Legacy Applications” by Michael Feathers
  • “Objects on Rails” by Avdi Grimm
  • “The Cucumber Book: Behaviour-Driven Development for Testers and Developers” by Matt Wynne and Aslak Hellesoy
  • “Crafting Rails Applications: Expert Practices for Everyday Rails Development” by Jose Valim
  • “Rails 3 in Action” by Ryan Bigg and Yehuda Katz

Much like a doctor practices medicine, I practice coding.  That isn’t to say I’m an amateur, as I take my profession very seriously.  I want to get better at.  The above books are a lot to ingest in a short period of time, but I find that reading multiple different sources at the same times helps to better sew the seeds.

This isn’t to say I’m just now picking up software books and reading them.  I’ve read plenty of other software related books prior to this recent “binge” – The Pragmatic Programmer, Refactoring, Smalltalk Best Practice Patterns, Test Driven Development, Implementation Patterns, The Rails Way, and several more.

In looking at my pattern of learning, I tend to go the path of assimilating lots of information in short bursts of time; Some times this is triggered by an emerging issue or problem-set, but more often as inspiration and guidance for improvement.

Keeping One Constraint Salient Instead of Ten

“While teaching programming, Matt observed that giving the children the single rule that they shouldn’t have methods longer than 10 lines resulted in the children writing code with SRP, encapsulation, and other positive attributes. Matt argued that beginning with a simple rule that could get you 80% of what you want is likely better than 10 rules that, if followed correctly, could get you 100% of what you want.” – Jay Fields http://blog.jayfields.com/2012/03/when-to-break-apart-your-application.html

The above concept, write software with one constraint, is excellent advice.  There is a tremendous amount of literature concerning best practices, methodologies, and principles; all of which can be challenging to internalize.

I can safely say that any methods I’ve ever worked with, or written, that were more than 10 lines were inevitably difficult to test.  Or, in the case of my pre-automated testing days – The Dark Days – those long methods were inevitably the cause of the most bugs.

In fact I would wager that the probability of bugs in a method is N log(N) where N is the number of lines in the method.  In other words, as the size of a method grows, the probability of bugs grows faster.  This is based on experience and conjecture, nothing more.

This single constraint is in tension with reading numerous books…after all how can I hope to possibly internalize all of the information I’ve been reading.

Abstraction

“The TDD community has been recently buzzing with the realization that code becomes more general as tests become more specific, revealing that test-driving code alone will push it to a more appropriate level of abstraction. It is still up to the human(s) at the keyboard to change the class and method names to match.” – Tim Ottinger and Jeff Langr http://pragprog.com/magazines/2011-02/abstraction

In someways, each of the books I’m reading are tests against the mental model that I’ve built up in my 14+ years of programming practice.  In many cases, the tests reveal issues in my underlying modus operandi. I work through those ideas and attempt to push towards more general solutions.

Case in point, I recently wrote a small command-line application based on a problem domain that I understand – the Diaspora RPG Cluster Creation rules/algorithm.  I used Avdi Grimm’s “Object on Rails” as a general template for what I would do.  I wrote about this experience on my personal blog.

By writing my tests, and testing my mental model of “what is programming”, I was able to personally reaffirm that Avdi’s suggestions are in fact a good practice. Namely that small classes, small methods,  unit tests, and acceptance tests are all integral for making software flexible and maintainable.

Intelligence and Wisdom

“Intelligence is the ability to learn from your mistakes. Wisdom is the ability to learn from the mistakes of others.” - Anonymous

I don’t work with cutting edge technology, however I do work with yesterday’s cutting edge technology. So I look to the experiences of others and try, as best I can, to apply them to my day to day software practice.

To also best learn from others, I’ve been helping out with the Rails pull requests…examining the code and testing the patches, as well as participating to some small degree in conversations concerning the code.

Shooting the Trouble

Yesterday, Conductor users began reporting errors with the Paste functionality of the CKEditor, the rich text editor used by Conductor.  The problem manifested on some browsers, but not all – Chrome 17 appeared immune, but there were reports of problems from Firefox 3.6, IE 9, IE 8, Chrome 16.

<Quasi-Religious-Diatribe>

loathe, despise, and detest Paste from Word for HTML content.  It just doesn’t work well.

You would never rely on Google Translate or Babelfish to convert your English brochure to Spanish and then give that brochure to native Spanish speakers.  Did you translate that to  Castillian, Cuban, Mexican, or some other Spanish dialect?  So why would you write your content in Word then paste it into a browser and expect a high fidelity copy?

This is a complicated problem that I wish were resolved.  I understand that HTML can be intimidating…especially when you bring CSS and browser compatibility into the mix…but even the “best translation service” is fairly terrible to a native speaker.

So roll up your sleeves and get comfortable with the HTML.  If you are writing anything for the web, you need to understand it.

And hats off to those few people around the world who maintain the Rosetta Stone for Paste from Word functions.  It is a thankless job that requires working with some truly horrific ever shifting data and attempting as best you can to map that to an ever shifting landscape of browser implementations of HTML.

</Quasi-Religious-Diatribe>

deep breaths…count down from 10, 9, 8, 7, 6, 5, 4, 3, 2, 1…

Okay, I’m back.

The Initial Problem

The problem I was trying to solve was a pernicious Chrome and Safari paste from Word bug. First, lets follow the steps below to see the initial problem.

Step 1: Copy some simple text from Word

Nothing fancy, just a paragraph with a bulleted list.

Copy from Microsoft Word 2008 for Mac

Copy from Microsoft Word 2008 for Mac

Step 2: Paste Text into Chrome

Things look reasonable, though I don’t like the copied bullet. At this point, most people save their page and go about their business.  Its a reasonable thing to do. But step 3 reveals the problem.

Paste to Chrome Step 1

Paste to Chrome Step 1

Step 3: Toggle into Source View Mode

In the source view, there is a <p>&nbsp;</p> that “just appears”.  As it turns out, that little bit of HTML is present in Step 2, but is for some reason invisible in the CKEditor.

Paste to Chrome Step 2

Paste to Chrome Step 2

Step 4: Toggle out of Source View Mode

And the paragraph appears.

Paste to Chrome Step 3

Paste to Chrome Step 3

The Initial Yet Problematic Solution

As always, go to Google when you encounter a coding problem.  And as it turns out the CKEditor paste error is a known problem…without an elegant solution.  What was happening is the Paste action in CKEditor was wrapping the content in a P-tag.

If I were to copy from Word “Simple Paragraph”, the pasted content would be something like  ”<p><p>Simple Paragraph</p></p>”.  Chrome would resolve that by created “<p>&nbsp;</p><p>Simple Paragraph</p>” but not before the CKEditor had rendered Step 2 from above.

CKEditor provides a hook for the Paste event.  So I implemented a solution, but unfortunately it wasn’t adequate for all browsers.  So, I spent a good portion of yesterday investigating what was going on.

Painful Discovery

While I was working on the solution, I discovered something truly horrific.  Each browser receives different pasted values from Word.  And likewise handles this paste differently.

Chrome on OSX

…60+ lines of XML declarations then…
<!--StartFragment-->

<p class="MsoNormal">This is a paragraph</p>

<p class="MsoListParagraphCxSpFirst" style="text-indent:-.25in;mso-list:l0 level1 lfo1"><!--[if !supportLists]--><span style="font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:
Symbol">·<span style="font-family: Times New Roman; font-size: 7pt; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span><!--[endif]-->Item one</p>

<p class="MsoListParagraphCxSpLast" style="text-indent:-.25in;mso-list:l0 level1 lfo1"><!--[if !supportLists]--><span style="font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:
Symbol">·<span style="font-family: Times New Roman; font-size: 7pt; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span><!--[endif]-->Item two</p>

<!--EndFragment-->

Firefox on OSX

…170 lines of style declarations then…
<p class="MsoNormal">
  This is a paragraph
</p>
<p class="MsoListParagraphCxSpFirst" style="text-indent:-.25in; mso-list:l0 level1 lfo1">
  <span style="font-family:Symbol; mso-fareast-font-family:Symbol; mso-bidi-font-family: Symbol">
    <span style="mso-list:Ignore">·
      <span style="font:7.0pt &quot; Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
    </span>
  </span>
  Item one
</p>
<p class="MsoListParagraphCxSpLast" style="text-indent:-.25in; mso-list:l0 level1 lfo1">
  <span style="font-family:Symbol; mso-fareast-font-family:Symbol; mso-bidi-font-family: Symbol">
    <span style="mso-list:Ignore">·
      <span style="font:7.0pt &quot; Times New Roman&quot;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span>
    </span>
  </span>
  Item two
</p>

And all of the other browsers receive comparably different information from Microsoft Word.

Final Pasted Value That Is Saved in Conductor

And here we have the “final” pasted value of several different browsers.

Chrome 17 on OS X

<p>This is a paragraph</p><p>·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Item one</p><p>·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Item two</p>

Firefox 10 on OS X

<p>This is a paragraph</p><ul><li >Item one</li><li >Item two</li></ul>

Safari 5.1.1 on OS X

<p>This is a paragraph</p><ul><li   >Item one</li><li  >Item two</li></ul>

Opera 11.6 on OS X

<p>
  &nbsp;</p>
<p class="MsoNormal">
  &nbsp;</p>
<p class="MsoNormal">
  This is a paragraph</p>
<p class="MsoListParagraphCxSpFirst" style="text-indent:-.25in;mso-list:l0 level1 lfo1">
  <span style="font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:
Symbol"><span style="mso-list:Ignore">&middot;<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>Item one</p>
<p class="MsoListParagraphCxSpLast" style="text-indent:-.25in;mso-list:l0 level1 lfo1">
<span style="font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:
Symbol"><span style="mso-list:Ignore">&middot;<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>Item two</p>

Chrome on Windows

<div>This is a paragraph</div><div>•<span class="Apple-tab-span" >  </span>Item one</div><div>•<span class="Apple-tab-span" > </span>Item two</div><div><br></div>

IE8 on Windows

This is a paragraph<BR>•&nbsp;Item one<BR>•&nbsp;Item two<BR>

As you can see, the above content varies wildly.  It is the result of three different programs negotiating the Copy/Paste behavior: Microsoft Word, the browser, and CKEditor.  And in many cases, the pasted HTML is quite terrible – I’d say only Firefox and Safari are proper HTML given the source Word document.

The Current Solution to the Paste Issue

Below is the code that I have settled on for fixing the original paste from Word problems for Chrome and Safari. Below is the code that I tried to use but failed. But keep reading after the solution:

CKEDITOR.on("instanceReady", function (ev) {
  ev.editor.on("paste", function (e) {
    if (e.data["html"]) {
      // Strip lang, style, size, face, and bizarro Word tags
      var input = e.data["html"].replace(/<([^>]*)(?:lang|style|size|face|[ovwxp]:\w+)=(?:[^]*|""[^""]*""|[^\s>]+)([^>]*)>/gi, "<$1$2>");
      var output = ;

      // The Paste action in CKEditor was wrapping the content in a p-tag;
      // By only using the innerHTML of the first element, the auto wrapping
      // of a p-tag instead wraps the first element in a p-tag.
      // So pasting: <p>Hello</p><p>World</p>
      //   Was Pasted as <p><p>Hello</p><p>World</p></p>
      //   Resolves as <p>&nbsp;</p><p>Hello</p><p>World</p> AND
      //     the <p>&nbsp;</p> was invisible
      //   Paste as Hello<p>World</p>
      //   Resolves as <p>Hello</p><p>World</p>
      // I have trepidations about this, but it appears to work in a
      // relatively general case.

      // Internet Explorer may not paste well-formed HTML, but instead
      // paste innerHTML
      if ($(input).html() == "" ) {
        output = input;
      } else {

        // Iterate over the top-level DOM elements
        $(input).each(function(key,value){

          // For the first top-level DOM element, we want the innerHTML, so
          // that it can be wrapped by a P-tag…either in the Browser or in
          // the CKEditor
          if (key == 0) {
            output += value.innerHTML;
          } else {
            // outerHTML exists in some browsers as a native property
            // It is likely more reliable than the html method (in fact
            // in Chrome, $(<div>Bob</div>).html() returned Bob)
            if (value.outerHTML == undefined) {
              output += $(value).html();
            } else {
              // Likely more reliably than html(), as it is a native browser
              // method in some "modern" browser
              output += value.outerHTML;
            }
          }
        });
      };
      e.data["html"] = output;
    }
  });
});

Eventually, I opted to clean the HTML on the server side using the following regular expression:

text.sub!(/\A(\<p[^\>]*\>[\t\s]*\&nbsp\;[\t\s]*\<\/p\>)*/m,"")

HTML Emails Inserting Spaces in Odd Locations

About two weeks ago, my team received a report of a problem in one of our system generated emails.  A small handful of the words in longer paragraphs were being split.

For example, there was a long paragraph (200 words or so), and the word “condition” was split into “condit ion” – a strange problem but one related to a previously discovered limitation in the venerable yet pervasive sendmail program which we used for delivering the emails.

The Challenge

Sendmail splits long lines after the 998th character.  It does this by adding a carriage return (like hitting Return on your keyboard).  What was happening is the “t” in “condition” was at the 998th character.  Further muddying the water, was the fact that we are dealing with escaped HTML, so a quote (“) is actually represented as &quot; And there were also tags which are invisible to a human.

The Fumbling

I was aware of the 998th character issue of sendmail, but didn’t know of a good work around.  I started chatting with Jaron, a fellow Notre Dame programmer and good friend of mine, about the problem.

Both of our initial understandings of HTML emails was that they simply worked.  Which clearly was not the case.

Important Sidebar

Instead of starting the chat by stating the root cause, I solicited a request for help with my proposed solution – a regular expression to add a carriage return after every period, so long as it wasn’t part of an attribute of an html-tag.

Thankfully, I only spent a four minutes going down that path before I stated the root cause – carriage returns were being injected into an HTML email and it was breaking words.

When looking for help with a problem, don’t ask for help on a problem related to your proposed solution. Instead clearly state your understanding of the initial problem.  Then state your proposed solution for correcting the problem.

The Solution

After a lot of trial and error, we eventually settled on setting the email’s HTML part’s Content-Transfer-Encoding to base64, and encoded the HTML part in base64.

Below is our Rails 3.0.11 solution, it hasn’t been “cleaned up” but it highlights the key take-aways:

# Rails.root/app/models/notifier.rb
class Notifier < ActionMailer::Base
  def general_email
    # important configuration stuff
    # setting @object for template access
    mail { |format|
      format.text
      format.html(:content_transfer_encoding => base64)
    }.deliver
  end
end

# Rails.root/app/views/notifier/general_email.html.erb
<%= Base64.encode64(%(<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>#{@object.subject}</title>
</head>
<body>
  #{ @object.body.html_safe }
</body>
</html>))%>

And Now for Something Completely Different

In November I took over the account management of one of our clients on campus.  I say clients somewhat hesitantly, as our department has a cost recovery model in which we bill other departments for work.  Not everyone on campus operates this way, so we have a very interesting ecosystem.  But I digress.

I haven’t set aside my other responsibilities, but am instead adjusting the load to account for these changes.  And what I’m finding is moments of insight while traversing the maelstrom of my new and old responsibilities.

Lesson #1 – Clients are Demanding

While this may sound terrible, it is actually great.  Imagine if Mozart’s father hadn’t been demanding?  Without the external pressure to deliver, complacency is just around the corner.

I used to work for a small insurance agency, and one of my friend’s father was a very demanding client.  He would have all kinds of wild requests that seemed technically unfeasible.  Many people bemoaned his demands, but without him our company’s sales would have flattened.

He demanded that we all go to the moon, and our job was to help him build the spaceship.  Oh wait, that’s John F. Kennedy.

Lesson #2 – Clients Are Wrong

…then again so am I. A client understands their problem space, but may not understand the best steps towards the appropriate solution.  With an external lense, which my team can provide, we provide a different perspective on the problem.

There is a lot of potential for misunderstanding, as both sides are crucial for delivering the solution that will be an amalgam of all those involved.

And I know this can be frustrating.  Developers are notoriously cynical and often full of hubris.  I know I’ve fallen into the trap of thinking I know something as well as a client – or even better than them.  When in reality they have an abundance of nuanced knowledge that is never immediately obvious.

So if I think someone is wrong, I need to listen again, because they are saying something that is very likely right, but maybe they are not saying it in a way that I’m expecting to hear it.

Lesson #3 – Clients Want Regular Updates

And this is a good thing, it keeps us accountable for delivering their solution. I’ve found that transparent conversations are both appreciated and truly build a team. And, as an added benefit, our regular updates can help others be accountable for their part.

And this all boils down to practicing basic communication.  Yes people will be upset if their site isn’t done on time but it is better to find out about an issue early. Then the entire team, which has built trust (see Lesson #2), can rally and address those issues.  The resulting conversations may not be pleasant, but it’s better than the conversation you may have had later down the road.

Lesson #4 – I’ve Only Got One Head

And it’s really hard to wear more than one hat.  I’m working really hard to serve the needs of our client, but this is coming at a cost.  I’m not able to wear my developer hat as often as I used to – it’s a comfortable old hat that I’ve grown quite fond of.

I’m not the best developer, though I think I’m pretty good.  I’ve learned many of the lessons that I’d like to have learned, but I see other lessons to be learned that have nothing to do with machine compiled code, and I look forward to incorporating that into my personal and professional development.

 

 

 

Multiple SSL Certificates on One Apache Server

Conductor serves many different sites at the University of Notre Dame, however, not all sites in Conductor are under the nd.edu umbrella – www.holycrossusa.org is one of them.

SSL Error in Chrome on www.holycrossusa.org

SSL Error in Chrome on www.holycrossusa.org

One problem that arose is that non-administrative users needed to securely access the site.  As it was configured, anyone going to https://www.holycrossusa.org/ using the Chrome browser would see the following SSL certificate warning.  Other browsers would give even more pessimistic notifications.

What was needed was a separate SSL certificate on the Conductor for www.holycrossusa.org. The big gotcha is that most other documentation I found says to set the NameVirtualHost to the server’s IP address.  And that means the internal, or Local-IP address, as provided by the %A custom log format directive of Apache.  If you use your server’s Public-IP address, things may not work.

Below is the relevant /etc/httpd.conf entries.

# Configuration for conductor.nd.edu
NameVirtualHost [LOCAL-IP-ADDRESS-1]:80
NameVirtualHost [LOCAL-IP-ADDRESS-1]:443

<VirtualHost [LOCAL-IP-ADDRESS-1]:80>
	ServerName conductor.nd.edu
	ServerAlias *.conductor.nd.edu
	Include conf/apps/conductor.common
</VirtualHost>

<VirtualHost [LOCAL-IP-ADDRESS-1]:443>
	ServerName conductor.nd.edu
	ServerAlias *.conductor.nd.edu
	Include conf/apps/conductor.common
	RequestHeader set X_ORIGINAL_PROTOCOL https

	SSLEngine on
	SSLCertificateFile /path/to/conductor.crt
	SSLCertificateKeyFile /path/to/conductor.key
	SSLCACertificateFile /path/to/conductor.intermediate.crt
</VirtualHost>

# Configuration for www.holycrossusa.org
NameVirtualHost [LOCAL-IP-ADDRESS-2]:80
NameVirtualHost [LOCAL-IP-ADDRESS-2]:443

<VirtualHost [LOCAL-IP-ADDRESS-2]:80>
	ServerName www.holycrossusa.org
	ServerAlias www.holycrossusa.org
	Include conf/apps/conductor.common
</VirtualHost>

<VirtualHost [LOCAL-IP-ADDRESS-2]:443>
	ServerName www.holycrossusa.org
	ServerAlias holycrossusa.org
	Include conf/apps/conductor.common
	RequestHeader set X_ORIGINAL_PROTOCOL https

	SSLEngine on
	SSLCertificateFile /path/to/holycrossusa.org.crt
	SSLCertificateKeyFile /path/to/www.holycrossusa.org.key
	SSLCACertificateFile /path/to/holycross.intermediate.crt
</VirtualHost>

 

Updating Framework Versions – A Leisurely Stroll

I’m presently the primary application developer for conductor.nd.edu, map.nd.edu and a few other limited scope applications.  When I started working at the University of Notre Dame back in May 2009, I inherited these applications.

Fortunately, all of the applications I inherited had an automated test suite — a collection of programs that can be run to verify system behavior.  In the case of these applications, the test suites are developed and maintained by the application developer.

The test suites are a vital component of each of the applications I maintain.  Without them, I’d be lost.  Some test suites are better than others, but as I work on each application I also work to continually improve the test suite.

Recently, I just completed the process of migrating map.nd.edu’s authentication system from LDAP to CAS.  The advantages of CAS are pretty straightforward — I do not have to worry about maintaining the authentication component of each application.  This means I can remove code from the application — always a good thing. And the application doesn’t process user credentials, which eliminates one potential security hole from the application.

While performing this update, I also decided that I would update the underlying Ruby on Rails framework.  We were on version 2.3.5 and needed to increment to a more recent version — more recent versions of applications typically squash some bugs and close any discovered security holes.

The steps to increment the version were fairly simple, here is the script I followed:

10 increment version number
20 run tests
30 commit changes if tests were successful
40 update broken code and goto 20 if tests were unsuccessful
50 goto 10 if application's current version number is not latest version number

 

The key concept is that I walked from version 2.3.5 to version 2.3.14 by making sure 2.3.6, 2.3.7, etc. all passed their tests.  Never once did I open the browser during this process.

Once that was done, I began working on the CAS implementation.  Adding this feature went very smoothly.  When all of it was done, I began kicking around the application in the browser, making sure that things were working as expected.  I could automate these tests with Selenium, but have yet to invest the time in this tool.

I didn’t find any problems, but in an alternate universe, I’m sure there were issues.  After all, I had just incremented 9 minor versions of the application and implemented a whole new feature.

Enter Bizarro World

Let’s pretend for a moment that I did find problems.  It is possible the problem was untested from the beginning, introduced in the version update, introduced with the CAS feature, or something else entirely.

My first step is write a test that verifies the problem exists (i.e. the test fails).  With that automated test, I can begin to unravel what has happened. The first thing to do is go back to before any recent changes were made.  After all I want to know did my changes introduce the problem.

Given that I always use source control, it is easy to step back to a previous code state.

With the repository in it’s original state (i.e. before I incremented the Ruby on Rails version), I then run the test.  Did it still fail? If so, the changes likely had no effect.  If the test passes, then changes that I made broke the application.

Since we are still pretending, let’s pretend the test passed.  I now know that somewhere in my changes, I broke something.  At this point, I begin walking the repository one commit at a time to it’s most recent state (i.e. CAS has been implemented).  At each step, I run the test.  If it still passes, then I move to the following commit.  If it fails, I have found the commit that introduced the problem and can work to fix it.

Since we use git as our source control, I can automate the above process with the `git bisect` command.  I run `git bisect` by indicating where to start, finish, and what test to run at each step.  Then, I sit back and let my computer do the work. Note the test program that you are running will likely need to reside temporarily outside of the repository, as `git bisect` will checkout each version of the code.

Fortunately, in this universe, I didn’t encounter any of these problems, and instead was able to CAS-ify my first Rails application without breaking anything that I know of.

 

 

 

Presentation at HighEdWeb 2011

Erik Runyon and I presented at HighEdWeb 2011 on Feeding the Beast: Fostering a Culture of Sharing (source code can be found at https://github.com/erunyon/HighEdWeb-2011).  This was my first conference presentation and it started with some technical difficulties. Note to self, we probably shouldn’t have used an HTML 5 slide presentation.

We outlined the various cases in our department and on campus where we providing access to data and are using easily accessible data.  It was not a definitive list, but we did talk about the various challenges we face in our distributed work environment.

We kept the presentation short, wrapping up in 25 minutes, then opened up for questions.  And it was full of questions.  A common theme amongst the questions was:

“How can I get others to share with me?”

This is particularly challenging when faced with the fact that several departments at a University might be on a cost recovery model.  My answer was perhaps a little discouraging:

“You can’t. However, if you work to build relations and share with others, then they will hopefully be more likely to share with you.”

In fact, think back to your days on the playground.  If someone had something that you wanted to play with, you may well have said to your mom, dad, or teacher “They aren’t sharing!”  What you really meant was “I want to play with that.”

I know for me, my parents would say “Why don’t you play with that over there.” What I learned since my early childhood and from being a parent is that the simple sentence has two more unstated sentences.

“Why don’t you play with that other toy. Show the other kid that you are having fun.  Then they will want to play with your toys and you can play with their toys.”

Pretty simple concept, if you want others to share with you, make sure you have something worth sharing.

I’m hoping that a video will surface, as there were other questions and discussions that I believe were very valuable.  I hope the answers that we gave to those questions were also valuable.

Trying to Juggle Only One Thing at a Time

I am the primary maintainer of Conductor.  As such I am responsible for implementing new features, squashing bugs, tuning it’s overall performance, and improving the code’s maintainability.  It is very easy for these tasks to blend.

As I was working on adding a new feature to Conductor’s custom database, I found areas in the code that could be reworked for better clarity.  In rather short order I went from writing new code to adjusting existing code.   And I quickly grew to regret it.

The problem was that I had crossed from one task into another. The code base, in it’s current state, was juggling two incomplete concepts.

I am not a juggler.  However, I can quite easily juggle one ball.  I can even, to a lesser extent, juggle two balls.  The third ball is beyond me.  In fact, I find that juggling two balls is more than twice as difficult as juggling one ball.

So my changes were now unnecessarily complicated.  Not insurmountably so, but inconveniently so.  Instead of each task taking 10 minutes a piece, together they would take 30 minutes to resolve.

Programming is the art of transforming thought into instruction.  It is therefore easy to drift along a stream of consciousness and find the changes in your code to be unduly complicated.

Red, Green, Commit, Refactor

If I can follow the above 4 words of advice, I can reduce the potential for over-complications.

Red: When working on resolving the problem, I need to come up with the test (ideally automated) that will fail until the problem is resolved.

Green: Write the code to resolve the problem and verify the problem is resolved.

Commit: Update the code repository with the changes.

Refactor: Now go in and clean things up so it is either more legible or understandable.

More on Red-Green-Refactor

Content is King and the King needs to Move

It appears that Marketing Communication’s message concerning “Content is King” is taking hold.  Our copy writer, Mike Roe is completely booked for the July 2011 to July 2012 fiscal year. (In fact I suspect he’s overbooked.)

Lets Talk about Chess for a Moment

I’ve played quite a bit of chess, though strangely never in a tournament.  My 9th grade son has been involved in chess since kindergarten so I’ve been to my fair share of tournaments.

One of the unique moves in chess is castling your king; It serves two purposes.  One as a protecte protective measure to get your king out of the volatile middle columns of the board, and two to bring your powerful rook into play.

Now Back to Our Regular Programming

Creating content takes time and that is one precious resource you are not getting more of. Your website is a window into your world and your message.  Email, Twitter, Facebook, LinkedIn, and at some point Google+ are other windows into your world.

The message you are conveying is completely and entirely dependent on the content pieces you produce.

Think of these pieces of content as pieces on a chess board.  As those pieces are developed and pushed into the field of play, you should also be thinking about castling your king…content.

But be wary as your defensive positioning can easily become a liability.  If you fail to advance one of your pawns that is guarding the king, an enemy rook or enemy queen on your first rank can quickly spell checkmate.

So as you are working with your content think about it’s portability, in part because you don’t want to write it again, but also because the technology platform of today may be gone tomorrow (I know my VCR doesn’t work anymore, how about yours?).

Blogging platforms, such as WordPress and Blogger provide easy tools for piping data out of your blog and into another blog. Google+ and Facebook are also behind the idea of data liberation, providing a means of downloading everything you’ve done (Scary right?).

Conductor, Marketing & Communications CMS, also provides a means of getting the information out of your website (the documentation is a little sparse, but it’s one of my goals for the year to flesh it out). And up until now, getting content into Conductor was not nearly as easy.

The Big Reveal

For the past few weeks, along with launching Notre Dame Philosophical Review‘s new site, I’ve been working on a data migration tool to move webpages from outside of Conductor into Conductor.  The tool is intended for developers (those with an understanding of HTML markup) and greatly assists in moving content into Conductor.

This data migration tool is in it’s alpha stage, having only successfully moved content onto my local machine.  But it will evolve over time.