Our Own Worse Employees

Developer's Life No Comments »

I started redoing my main personal site, An Eclectic World, awhile ago.  As in sometime in 2011, around April. The site still says a new version is coming in the Summer of 2011.  Yet it still isn't done!  I'm redoing the site from its now over 7 year old PHP/MySQL version to ColdFusion/PostgreSQL utilizing Mach-II as the framework, jQuery for pretties, and some other nifty UI stuff I've picked up over the years. 

Still, it isn't a super extensive site.  Basically an about me, a page for my pets, and databases of my books, movies, and video games.  The rest is just linking off and acting as a hub for my social networking, other blogs, and Flickr feed.  Using our base model, I'm able to rapidly create the initial models for it and have usable pages within just an hour.  Once I had the first section done, it was even easier. 

I've helped build a huge, complex app with some seriously extensive JavaScript in less than 3 months!  So why are we here at over a year later and my simple personal still isn't done?  Because I am my own worse "employee".  Working at my job, I have a schedule, deadlines, and accountability.  I put in my time, work my tail off, and get it done.  For my own sites, however, no one really gives a frack one way or another if I redo it, update it, etc.  No one is pushing me to have it ready and when it comes to deadlines, if I'm the only one setting them they are soft as butter left on the counter awhile.

From what I've seen and heard talking with other developers, I'm not alone!  Despite our own sites often being the first "portfolio" pieces potential clients and employers see, we are horrible about keeping them up to date and maintaining them to the degree we would do a work site.  We get home, we're "tired", and we give ourselves lots of excuses not to do it. 

I understand the what and the why of it, the question is how do you fix it?  How do we kick our own tushes to give our sites the time they deserve?  I know for me, I can't even make the excuse of it takes too much time.  Literally for AEW's redo, once I forced myself to work on it awhile, in 2-3 hours I had it 90% done.  All its waiting for me is to put the finishing touches on the front page and about me page and its ready for testing.  So is it just laziness? Fear of burn out?  Mental tiredness after a day coding other people's stuff?

For me, maybe it's all of the above.  I struggle the same with editing my novels, painting, editing photos, and basically doing anything that engages the creative side of my brain after a day at work.  Is it something you struggle with as well?  Have you found a way past being your own worse employee?

CFIMAGE and alt tags

ColdFusion No Comments »

Ever used CFIMAGE with the "writeToBrowser" action?  A nifty way to display an image you've read into memory, or maybe made with ImageNew.  However, you may have found yourself looking at the source code and going ARG! when you spotted that empty alt tag. 

<cfset myImage = ImageNew("", 100, 100, "rgb", "##000033") />
<cfset sText.font = "Lucida Sans Regular" />
<cfset sText.style = "bold" />
<cfset sText.size = 14 />
<cfset ImageSetDrawingColor(myImage, "white") />

<cfset ImageDrawText(myImage, "Hello World!!", 5, 50, sText) />

<cfimage action="writeToBrowser" source="#myImage#" />

Get's us:

When you view the source, you see something like:

<img src="/CFFileServlet/_cf_image/_cfimg-9138836666536180171.PNG" alt="" />

Not very good for accessibility at all.  And what if you want to add a style class or ID to that image for CSS or JS purposes? If you just look in the "official" docs, you might feel like too bad, so sad because they don't even mention it at all!

Fortunately, that isn't true, thanks to a feature of this particular tag. Similar to what you'll find with the various form tags, CFIMAGE will basically pass any "extra" parameters to stick on the tag to the resulting img src. So if you need to do an alt, a title, a style, whatever, just tack it on to your tag.  I.E. So with the same image, and using a different CFIMAGE tag:

<cfimage action="writeToBrowser" source="#myImage#" alt="I'ma saying Hello World!" title="I'ma saying Hello World!" style="border: 5px red solid" />

We get:

I'ma saying Hello World!

And the view source shows us something like:

<cfimage action="writeToBrowser" source="#myImage#" alt="I'ma saying Hello World!" title="I'ma saying Hello World!" style="border: 5px red solid" />

Nice, eh? :)

Var Scope and CFArgument

ColdFusion No Comments »

I've been developing ColdFusion applications for over ten years now. I wrote fairly good stuff. Some of my apps have pretty much just run since launch with no real issues. But they weren't the best they could be, because I was stuck behind the times. In the last three years or so, thanks to some reorganizations in our unit, attending CFUnited 2009, and I think most importantly having a great working partner, I've been working towards being a better coder and following more "best practices".

One of those best practices is to "VAR scope" variables inside functions. This privatizes the variables in each function, reducing the chance for bleed over, particularly if you use like named variables (for example, many of our functions set up a return status structure of MyResults). By VAR scoping them, each variable will only be seen by that specific function. Without the VAR scope, the variables default to the variables scope, which is open to all functions and those functions can each modify them, which can cause unexpected results.

Putting a variable into the VAR scope is pretty easy, just preface it with VAR:

<cfset VAR myVariable = 1 />

All VAR scoped variables must be immediately after the last tag of your function. You can put comments in, of course, but no other sets or the like can go in until you are done. So I do it in all my functions. When while working on a new project, particularly as I began implementing our first service layer, I had an error come back that I was trying to declare a local variable twice! What? I checked the code again and again, but I was still confused.

<cffunction name="saveCoordinator" access="public" output="false" returntype="struct">
        <cfargument name="Coordinator" type="Coordinator" required="true" />

        <cfset VAR Coordinator = variables.coordinatorsDAO.save(Arguments.Coordinator) />
        
        <cfreturn Coordinator  />

</cffunction><cfset VAR myVariable = 1 />

Some of you are already probably going "well duh, idiot" but it took me a few frustrating minutes to realize my error. Despite my years of experience, I hadn't run into it before because it just wasn't something that had happened before because it wasn't something I'd ever done, until I tried this service layer. The problem?

All cfargument variables are automatically VAR scoped! So with that code, I might as well have had something like:

<cffunction name="saveCoordinator" access="public" output="false" returntype="struct">
        <cfset VAR Coordinator = Arguments.MyCoordinator />
        <cfset VAR Coordinator = variables.coordinatorsDAO.save(Arguments.Coordinator) />
                <cfreturn Coordinator  />

</cffunction><cfset VAR myVariable = 1 />

Now obviously this was a simple example with a simple solution, namely redoing the function like so:

<cffunction name="saveCoordinator" access="public" output="false" returntype="struct">
        <cfargument name="Coordinator" type="Coordinator" required="true" />
    
        <cfreturn variables.coordinatorsDAO.save(Arguments.Coordinator) />
</cffunction>

I am honestly surprised it hadn't happened before, particularly some functions I've built with 20 some arguments coming in. Conflict would seem to be inevitable, but maybe that's because most were built before I started VAR scoping and just haven't been updated yet. Suffice to say, if you get that error about local variables declared twice, but don't see a repeat in your set of VAR variables, make sure you don't have a repeat of that variable in the CFARGUMENT group.

cf.Objective 2012 Wishlist

ColdFusion , Conferences No Comments »

Since the ending of CFUnited, cf.Objective() seems to have stepped up to become the premiere ColdFusion conference. It's held each May in Minneapolis, has many of the same sponsors, and seems to be continuing to grow and expand each year. The cost is about comparable as well, at $949 for the three day event (with the usual early registration and various discounts available). Flights there will be about the same cost as it was to CFUnited's Maryland location, at least for us since we are in Texas. The venue, the Hyatt Regency, has a negotiated room rate of $169.

Unlike with the CFUnited folks, cf.Objective()'s organized have negotiated with the venue hotel to also have government rates for applicable attendees. For those not in state/federal jobs, the government rate is basically the max a state or federal entity will pay per night for a hotel room in that particular city/region. In this case, its $121 a night. So if the venue's rates are higher and they won't honor government rates, you either have to stay elsewhere or pay out of your own pocket. When my partner and I attended CFUnited, we had to stay at a cheaper hotel nearby, though the event sponsors did have shuttles going back and forth around the hotels which helped. Still, being able to stay in the venue hotel is nicer, especially if there are after session events. But I digress a bit.

I have yet to attend cf.Objective() myself. Before the end of CFUnited, it was too small, too focused, and honestly gave off a bit of a snobbish vibe. Since then it has really upped its game and showing itself to be more open to all levels, filling the gap CFUnited left behind. So I'd rather like to go. Last year, however, we only had the funds to send one person, after the scholarship program we used to cover the actual cost of the conference changed their policy to only cover one person per unit per event. After lots of discussion, we decided my partner would be the one to go. This year, I'm hoping we can both go, particularly as we will finally be moving to ColdFusion 9 in 2012.

Which brings us by long prosy degrees to my actual post topic: cf.Objective() has released their session and speaker list for 2012! This year they have 65 sessions spanning five tracks (nice!): Architecture & Design in Software, Integration & Tools, Process & Performance, Security & Front-End Development, and JavaScript (cutely named js.Objective()). No word yet on whether they will be holding any pre-conference events. Some of the usual names seen in ColdFusion conferences will be there, as will some new folks.

So if I do get to go to cf.Objective(), what tracks would I want to attend (the point!), not taking into account what the actual room schedules will be?

There was also an ORM deep dive, but I don't feel ready for that yet. What about you? Going to cf.Objective() this year? What sessions have you interested?

Query Within A Query

ColdFusion 1 Comment »

When we moved over to doing all of our development using the Mach-II framework, it really forced us to separate our code into "layers". So we have views, which display the content, listeners which tie the Mach-II framework to the rest of our application, the gateways and DAOs which interact with the database, etc etc. One part of this separation of code and display, is that your views for the most part should not have queries in them. They should have, at most, basic logic such as conditionals or formatting, but nothing heavy duty and certainly not queries.

However, sometimes what you need to display involves multiple queries, for example, cascaded content or related content. Now you can get complicated and a bit nasty with it. For example, for some infinite-level cascading categories, we use recursive functions to build a structure of structures of structures with each one tied by ID back to the parent. Yeah, it is messy, but it works for our purposes. For something such as simple cascaded content, however, this can be a pain and not necessarily the best way to do it, at least IMHO.

For example, on the redo of my personal site, I'm building a table of book series. One of the columns is a list of the genres the series' titles spans. Now I could just value list it into a string and pop it in, but I wanted each genre to be linked to its genre list page. User friendly navigation and all. I could have thrown the link around the code when I did the string, but that's mixing my display into my gateway - big no no there. I could have done the aforementioned structure of a structure thing but ugh, what a mess! And for this, it would have meant a lot of repeating data and possible corruption because we aren't dealing with a bunch of unique values, just a small handful. And for this sort of display, it would have been a pain to deal with. I could have also taken the id + genre, made it a value, thrown it into a list, then did list of lists for each one. Again, it would work, but messy.

So my solution? A query within a query. Yes, within, not be confused with query of queries. Basically, in the gateway, I loop through my series, get the genres for each (ordered nicely by most prominent even), then add the entire query as a value with the query. On the output side, as I'm outputing the main query, I loop over the subquery, without having to actually break my model by putting a query within my view. What would such a beast look like? Well, if you cfdumped it, something like this:

Now, there are some catches do doing this trick. One, you can't just add a column to your query, then do query set cell to put it into your table. For whatever reason, it just doesn't work. It only works if you build an array of the queries then append it as a new column to the query. So in my gateway, I cannot use:

<cfquery name="qSeries" datasource="#variables.dsn#">
            SELECT seriesid, seriesname, numberoftitles, isongoing, serieswebsite, 0 AS numberheld, NULL as qGenres
            FROM mylibrary_series
            ORDER BY seriesname
        </cfquery>
        
        <cfloop query="qSeries">
            <cfset qBooksInSeries = booksGateway.getBooks(WhichSeries = seriesid) />
            <cfset numHeld = qBooksInSeries.RecordCount />
            <cfset QuerySetCell(qSeries, "numberheld", numHeld, currentRow) />
            
            <cfquery name="qGenres" dbtype="query">
                SELECT genres_genreid, genre, COUNT(bookid) as NumInGenre
                FROM qBooksInSeries
                GROUP BY genres_genreid, genre
                ORDER BY NumInGenre DESC
            </cfquery>
            
            <cfset QuerySetCell(qBooksInSeries, "qGenres", qGenres) />
        </cfloop>


Instead, I must use:

<cfset var aGenres = ArrayNew(1) />

        <cfquery name="qSeries" datasource="#variables.dsn#">
            SELECT seriesid, seriesname, numberoftitles, isongoing, serieswebsite, 0 AS numberheld
            FROM mylibrary_series
            ORDER BY seriesname
        </cfquery>
        
        <cfloop query="qSeries">
            <cfset qBooksInSeries = booksGateway.getBooks(WhichSeries = seriesid) />
            <cfset numHeld = qBooksInSeries.RecordCount />
            <cfset QuerySetCell(qSeries, "numberheld", numHeld, currentRow) />
            
            <cfquery name="qGenres" dbtype="query">
                SELECT genres_genreid, genre, COUNT(bookid) as NumInGenre
                FROM qBooksInSeries
                GROUP BY genres_genreid, genre
                ORDER BY NumInGenre DESC
            </cfquery>
            
            <cfset ArrayAppend(aGenres, qGenres) />
        </cfloop>

        <cfset QueryAddColumn(qSeries, "qGenres", "VARCHAR", aGenres) />

Second, in the view, before I can look our query within the query, I must "rename" it.

<table class="listTable dataTable">
    <thead>
        <tr>
            <th>Name</th>
            <th>Genre</th>
            <th># I Have</th>
            <th># In Series</th>
            <th>Release Status</th>
            <th>Collection Status</th>
        </tr>
    </thead>
    <tbody>
        <cfoutput query="qSeries">
            <tr>
                <td><a href="#BuildURL("viewSeries", "WhichSeries=#seriesid#")#">#seriesname#</a></td>
                <td>
                    <cfset qMyGenres = qGenres />
                    <cfset thisRow = 1 />
                    <cfloop query="qMyGenres">
                        <a href="#BuildURL("myLibraryBrowseBooks", "WhichGenre=#genres_genreid#")#">#genre#</a><cfif thisRow NEQ qMyGenres.RecordCount>, </cfif>
                        <cfset thisRow = thisRow + 1 />
                    </cfloop>
                </td>
                <td>#numberheld#</td>
                <td>#numberoftitles#</td>
                <td><cfif isongoing>On-Going<cfelse>Finished</cfif></td>
                <td><cfif isongoing AND numberoftitles EQ numberheld>Current<cfelseif numberoftitles EQ numberheld>Complete<cfelse>In-Progress</cfif></td>
            </tr>
        </cfoutput>
    </tbody>
    </table>

When we meet those two caveats, then we can do our trick to get the results we want, as seen in this screen snippet of the page displaying my series with multiple genres:

Nice :-)

Powered by Mango Blog. Design and Icons by N.Design Studio
RSS Feeds