Blog

This is why it takes so long to "fix bugs" in code.

For 3 days now I've been going back/forth with a client over a tech issue. The new "Bootstrap Menu Bar" I added to their app wasn't appearing on her screen...but JUST her screen. All the other employees could see and use it just fine. But on HER computer, it never showed up, just blank space. The REST of the web app appeared just fine, but the navigation in the upper-left corner was gone. Didn't matter if we tried different web browsers, they were all the same.

She's in transit, staying in hotels while traveling to Minnesota, and was on a different-than-normal computer; so I'm thinking there is some sort of security/proxy setting that's messing with her internet connection. We tried everything we could think of, the problem was still there.

I made "test" pages to try 2 or 3 different variations of the Bootstrap code, seeing if I could narrow it down to a particular feature (or more likely, a particular piece of legacy code that their app still depends on). No changes. It was always broken for her...but for everyone else, it worked fine.

Today I scheduled a GoTo Meeting with her, so I could see her screen, and also take a look at the code that was rendering in her web browser (as well as possibly try a few network settings, if need be). As soon as we started up the GoTo Meeting, the Menu Bar worked! There it was on the screen, both of us could plainly see it, and no code changes had been added to the app. We both agreed that was weird, I told her to call me if it vanishes again, and we hung up.

Five minutes after the phone call, I received this email from her:
-----------
I am a weapons-grade moron...

So, I'm working at this hotelpartment off my husband's nice 27" monitor, splitting the screen in half so it feels like two screens. Keeping both email and internet screens in their half of the screen, the toolbar is missing....but when I make the internet window full screen - kablam, there it is!!
-----------
Three days of my BILLABLE time sending her test files, trying to get more info and fix the issue. The "fix" ended up being "rearrange how the windows are displayed on your screen".

The next time someone asks "why does it take so long to fix bugs in code?"...I give you Exhibit A. :)

-nolan

Readability, self-documenting code, and CFLib.org

I'm famous! Kind of! Not really! But I just got another function approved for CFLib.org. (This brings my total up to 3...I wonder how many I need before I win a prize, but I digress). This newest function is getMeridiem:

view plain print about
1string function getMeridiem(required date dateTime){
2 return timeFormat(dateTime, "tt");
3}

As you can see this UDF is not super fancy; it returns the "am/pm" portion of a datetime, and it's literally just 1 line of code. You might ask why I'd write such a small UDF, since I can clearly do the exact same thing like this:

timeFormat(dateTime, "tt");

My answer is simple: readability and self-documenting code.

The first time I submitted this UDF to CFLib.org, it actually got rejected, because the person approving code that day felt "it's always gonna be better to use a built-in function than a UDF that - for all intents and purposes - does the same as the built-in function". That of course makes a lot of sense. But then I got to thinking about another UDF I use often, also found on CFLib.org: the CharAt() function. As you can see, this too is just 1 line of code:

view plain print about
1<cfscript>
2/**
3 * Returns the character at a certain position in a string.
4 *
5 * @param str String to be checked.
6 * @param pos Position to get character from.
7 * @return Returns a character.
8 * @author Raymond Camden (ray@camdenfamily.com)
9 * @version 1, December 3, 2001
10 */

11function CharAt(str,pos) {
12 return Mid(str,pos,1);
13}
14
</cfscript>

But the big difference is, CharAt() is more readable and self-documenting than the built-in CF code. Let's look at these 2 lines:

Mid( "this is sample text", 6, 1 );

CharAt( "this is sample text", 6 );

They both do the exact same thing. If you know what Mid() and CharAt() do, I feel the CharAt() function is just a tad easier to read, making the project overall go that much quicker for me (and my team). The same thing is true here:

timeFormat( Now(), "tt");

getMeridiem( Now() );

If I know what the "tt" mask does for the timeFormat() function, these might both be equally readable. I'll be honest with you: I don't remember all the masks, I look up at least half of them whenever I use date/time functions in CF. So in that case, getMeridiem() makes the code more readable and self documenting, again making my life a tad easier and the project that much more efficient. Of course, this is only true if I remember what "meridiem" means, and I've had to Google that before as well. :)

After thinking about CharAt() and how it compared to getMeridiem(), I re-submitted my function to CFLib.org, along with a few more notes on how I felt it was the same as CharAt() in terms of what the benefits are to using such a small UDF. The same moderator that rejected my function before, now agreed with me and approved the UDF!

Sometimes UDFs don't have to solve a huge complex problem. If all they do is make the code more self-documenting, that can be enough of a benefit to the project to use a UDF over built-in code.

(I was on a C++ project once where the lead developer would wrap the assert() function in 3 or 4 different names -- he had one called "pre_condition(), another called "post_condition()" and a few others too. Each wrapper called assert() and nothing else -- but by using the different wrapper functions, when we'd go back to read the code we were able to determine a little more about when/where/why these asserts were supposed to be true, making the code that much more self-documenting which benefited all of our team.)

-Nolan

Book Review -- 97 Things Every Programmer Should Know

Earlier today (while waiting for software to install on a client's server) I finished reading "97 Things Every Programmer Should Know" (Editing by Kevlin Henney). It's a collection of different bits of wisdom, contributed from a variety of different authors.

Each "chapter" is 2 pages long, which makes the book easy to pick up and put down, reading the 97 "things" a little at a time while waiting for software to install, or other "I have 5 free minutes" kind of situations (which isn't really something I personally see in a lot of techie books, not to this degree anyway).

For the most part, the book is pretty language-independent. The advice isn't syntax specific to, say, C++ or ColdFusion (both languages that I love using); it's mores high-level information that can be applied to any project. Topics range from improvements for testing (both ideas on how to automate tests as well as how to better handle communication between developers and QA engineers) to tips on refactoring code, to thoughts on what to put in source control (everything -- yes, everything). There are a few small sections in the book that use actual lines of code or references features in a specific language (C# comes up in 2 or 3 of them), but these are all done in pretty widely accepted languages such as Java or C++, and the code samples are incredibly small (less than 5 lines of code each time), so the concepts can be pretty easily understood, even if you've never written a line of C++ before in your life (seriously).

There are also a handful of chapters that discuss different benefits of command-line tools, learning Unix toolsets, etc. In those cases, one could argue these are language-specific (or at least platform specific) but the book also includes references to Cygwin, making that a bit of a moot point (and providing yet another piece of advice, if you weren't yet familiar with Cygwin).

Some of my personal favorite bits of advice found in the book...

  • Act With Prudence -- any explanation of "technical debt" that helps explain that concept to clients is worth reading!)
  • Ask, "What Would the User Do? (You Are Not The User)
  • Before You Refactor
  • The Boy Scout Rule
  • Code in the Language of the Domain (see my earlier post about the getMeridiem() function for a small semi-example of this)
  • A Comment on Comments
  • Continuous Learning
  • Domain Specific Languages (this is becoming a huge thing for me -- I keep running into more and more problems for clients that DSLs really help to resolve, and very effectively at that!)
  • Don't be Cute With Your Test Data (there's a semi-famous story from a video game company I used to work for that provides a great real world example of this...maybe I should blog it later...just for the record, it wasn't MY code or test data! *g*)
  • Don't Ignore That Error
  • Learn to Estimate
  • The Longevity of Interim Solutions
  • Pair Program and Feel the Flow
  • Prefer Domain-Specific Types to Primitive Types
  • Put the Mouse Down and Step Away From the Keyboard

...you get the idea, there are lots of good takeaways!

The whole book is roughly 200 pages, including short bios on each contributing author (which in itself was useful, as several bios mentioned other books and podcasts that were unfamiliar to me -- like Software Engineering Radio, for example, and the book "Working Effectively With Legacy Code"). Not a huge time commitment at all, and definitely worth a quick read.

Because the book is so language-independent, it's got good reusability. Unlike say, my book on Classic ASP, this is one that I might find myself re-reading again in the future. :) Along those lines, it also reminded me of "Secrets of the Rock Star Programmers", which I'd also recommend checking out.

-nolan

New function - getMeridiem

I just submitted a function to CFLib.org and thought I'd post it here too. getMeridiem() isn't super fancy, it just returns the "AM/PM" portion of a datetime (the name of which is the "meridiem"). As you can see, you can get that information from the built-in function TimeFormat(). All I'm doing is adding a little extra whitespace housecleaning and validation (which is useful if the dates might be badly formed...a situation I ran into last week...hence my writing this function). Also, I find getMeridiem() is a more intuitive name and it's more clear what that function does than TimeFormat( theTime, "tt" )...self documenting code and all that.

The source code and examples look like so:

view plain print about
1<cffunction name="getMeridiem" returntype="string" output="false">
2    <cfargument name="timePassedIn" type="string" required="true" />
3
4 <cfset var meridiem = "" />
5
6 <cfset arguments.timePassedIn = Trim( arguments.timePassedIn ) />
7 <cfif not IsDate( arguments.timePassedIn )>
8     <cfreturn meridiem />
9 <cfelse>
10     <cfset meridiem = TimeFormat( arguments.timePassedIn, "tt" ) />
11 </cfif>
12
13 <cfreturn meridiem />
14
15</cffunction>

Examples:

<cfoutput>
#getMeridiem( "4/2/2012 14:33:00" )#
#getMeridiem( "14:33:00" )#
#getMeridiem( CreateTime( 17, 30, 00 ) )#
</cfoutput>

Feel free to add this to your own Date/Time libraries for later use. Feedback is welcome.

-nolan

Tomorrow at SACCFUG: Introduction to PhoneGap

This Tuesday at the Sacramento CFUG, Seth Duffey will be giving a demo on the basics of building and testing PhoneGap applications. More details at www.saccfug.org -- see you there!

Previous Entries / More Entries

Recent Comments

CF Camp Notes: Hidden Gems in ColdFusion 11, Charlie Arehart
Nolan Erck said: Hi Charlie, Thanks for the clarifications and extra info. ... [More]

CF Camp Notes: Hidden Gems in ColdFusion 11, Charlie Arehart
Charlie Arehart said: Hey Nolan, thanks for offering those notes to folks. Just a ... [More]

CF Camp Notes: Command Box, Luis Majano
Nolan Erck said: Thanks for the link, Brad! (It really was a great preso -- e... [More]

CF Camp Notes: Hidden Gems in ColdFusion 11, Charlie Arehart
Nolan Erck said: Hi Charlie, Thanks for the clarifications and extra info. ... [More]

CF Camp Notes: Hidden Gems in ColdFusion 11, Charlie Arehart
Charlie Arehart said: Hey Nolan, thanks for offering those notes to folks. Just a ... [More]

CF Camp Notes: Command Box, Luis Majano
Nolan Erck said: Thanks for the link, Brad! (It really was a great preso -- e... [More]



BlogCFC was created by Raymond Camden. This blog is running version 5.9.7. Contact Blog Owner