Tips for Google Ads Keyword Matching

Running Digital Ads is a lot of fun. Many times, it’s instant feedback. If something is working you get clear results in your metrics and reporting (Right?). If something isn’t working you either see the absence of metrics or just get an “overwhelming sense of quiet” where there shouldn’t be. I sometimes get that same overwhelming sense of quiet when my two boys are playing alone.

Google Ads offers ad placement based on keywords. It’s important to know which style of keyword match is most appropriate. Editor’s Note: Insert standard disclaimer that “Google is always changing stuff so it might be different by the time you read this article.”

The success of your keyword targeting campaign is directly tied to how well you chose your keywords. Do they match how the user is searching for your product? You might be surprised how different your perception is, from the actual queries. Many of us have our own “language” for searching google and it doesn’t at all line up with how we speak or write plain English.

Google Ad Tip for Getting Best Keywords

When setting up a new google ad campaign, I’ll set up at least 2 ad groups. One contains the keywords I feel are the best match. I usually make these tight by using phrase match or exact match.  Call this group the “Money Group”.

The other Ad Group has the same keywords but in broad match. Call this the “Expeditionary Group”. Since I have less control over where these keywords match, I’ll bid lower for these.

I run the two Ad groups at the same time, looking to harvest good ideas from the “Expeditionary Group” and promote them to the “Money Group”. Also, I’m looking for negative keywords I can add to exclusion lists. Without fail, I find interesting things all the time.

Google Ads Keyword Harvesting for Improved Results

Our company, Digital Primates, has expertise in Apache Flex. This technology was popular several years ago for writing interactive applications. The underlying technology for Flex apps will be discontinued this year. As such, we have campaigns going on to find companies who need Flex App Migration help.

The Money Group had very few keywords. Here’s an example good keyword for us:

  • Apache Flex Application

The Expeditionary List had much broader matching and keywords. Here are some of the words it found that got moved to the Money List.

  • flex flash
  • adobe flex to adobe air app front end
  • apache flex sdk

There were also some duds, or cases where there exists conceptual overlap with Flex. Here’s an example of those.

  • flextime app
  • https dash iflex app
  • apps for ford flex
  • flextime facetime app
  • zizo flex watch app
  • flexpay app
  • kapuskasing flex program
  • onyx kids flex app
  • flex a bus app
  • applynowchase com flexapp
  • amazon flex application

By monitoring the Expeditionary List for a few days, I was able to pull out a fair number of keywords that made sense for our campaign, and then shut down the Expeditionary List. Think of this as planting random seeds and keeping the good stuff. As a reminder, here are the match types for Google Ads. Use Broad match for your expeditionary list and tighter matching styles (Phrase, Exact) for your higher value keywords.

Keyword match type summaries

Match type

Special symbol

Example keyword

Ads may show on searches that contain:

Example searches

Broad match

none

women's hats

Close variations of the keyword, related searches, and other relevant variations. The words in the keyword don’t have to be present in a user’s search.

  • buy ladies hats
  • women’s clothing
  • women’s scarves
  • winter headwear for women
     

Broad match modifier

+keyword

+women’s +hats

All the terms designated with a + sign (or close variations of those terms) in any order. Close variations include terms with the same meaning. Additional words may appear before, after, or between the terms.

  • women’s scarves and hats
  • winter hats for women
  • hats for stylish ladies

Phrase match

“keyword”

“women’s hats”

Matches of the phrase (or close variations of the phrase) with additional words before or after. Close variations include terms with the same meaning.

  • blue women’s hats
  • buy hats for women
  • ladies hats on sale

Exact match

[keyword]

[women’s hats]

Exact matches of the term or close variations of that exact term with the same meaning.

  • women’s hats
  • ladies hats
  • hats for women
  • hats women

The best way to develop and run NativeScript projects in an emulator

I develop NativeScript on Windows. As in most new, shiny technology, developing on Windows has it's quirks. In this post, we'll talk about 3 different ways to run your NativeScript project in an emulator, as well as the pros and cons of each method. I'm also going to use the Android platform. The iOS commands are the same, except for swapping iOS for the keyword android in the command.

All methods assume you have an emulator for your platform, with a device profile created. Additionally, at least on Android, it is necessary to start the device emulator you wish to target using the Android Virtual Device Manager, or some other mechanism.

Basic: tns run android --emulator

Run this command every time you want to push the latest version of your code to the emulator.

Pros:

  • You get to see any console output. This means you can debug your application using console.log("foo") statements and see the output.
  • You will stay up to date on your facebook feeds. See Cons below for explanation.

Cons:

  • The console logs are VERY chatty. There are heaps of measurement logging and other things not immediately relevant to the application. The sheer amount of logs, can make it hard to find your output.
  • You'll pay a 2 minute tax, at least, waiting on the emulator to get your changes. Change a single character and use this method again? Then you'll pay the 2 minute tax again. (I'm using an SSD laptop with 16GB of RAM.)
  • Because of the latency between updates, I am painfully reminded of my poor typing skills.
  • If this was the only option to write Native mobile applications, I'd probably decide it wasn't for me and go do something else.

Tip:

At this stage, I can not see a single positive reason to use tns run android --emulator that can't be achieved with one of the below options. In short, you probably don't want to use the workflow tns run android --emulator. As a stretch, perhaps you need to see the Native logs, like all of the measurement logging. Right now I don't need that, so this method is pointless and masochistic.

Interactive: tns livesync android --emulator --watch

This process watches for source code changes and will automatically build and push the latest version of your code to the emulator.

Pros:

  • The time between making a source code change, and seeing the effect of the change in the emulator, is WAY faster than tns run android --emulator. This is somewhat comparable to running a browser based application.
  • I prefer this method when I'm working on layouts, visual changes, or light work inside view-models.
  • Did I mention how fast changes are propagated?
  • If there is an error, you will get a stack trace on your emulator screen.
  • As of NativeScript 1.5, you will see console.log() outputs in your terminal window. YAY!

Cons:

  • You get NO console output. All console.log() statements are /dev/null'd.This is no longer true as of {N} 1.5. Console.log() output is streamed to the terminal, without the chattiness of the above method.

Tip:

If you want more options with how to deal with non-visual logging in NativeScript, write a custom TraceWriter and push the output you want into a frame of your application, or send it over an API or whatever. You can find out more here: tracing-nativescript-applications. Just search for Writing a Custom TraceWriter for an example of your options.

Genymotion: tns debug android --geny "Google Nexus 4 - 5.1.0 - API 22 - 768x1280" --debug-brk

This process watches for source code changes and will automatically build and push the latest version of your code to the emulator and start a debugging session in Google Chrome.

Pros:

  • Changes are propagated quickly, much like tns livesync android --emulator --watch
  • You have introspection, breakpoint and other tools using Google Developer Tools.
  • From my informal testing, the time to complete the initial build and show the app on the screen is less with Genymotion, than it is with the tns livesync android --emulator --watch process.

Cons:

  • This requires a separate account with Genymotion. There is a free personal account and several paid options.
  • No matter what I do, this doesn't work on my platform. It's the albino tiger of debugging. If you can see it working, then you have something special. However, Genymotion never comes out of the cave to perform for me.

Which one should you use?

Once your environment is successfully set up, spend some time to get Genymotion installed. If you can get it working on your system, then you have the Holy Grail of NativeScript debugging. Fast change propagation, interactive debugging, variable inspection and so on. If this does not work for you, then you are probably best served using tns livesync android --emulator --watch. Now that console.log() statements are sent into the terminal, you can debug iteratively, though without the breakpoints and introspection you'd get in a Google Chrome debug session.

Appendix: why doesn't Genymotion work on your platform?

If I knew the answer to that, I wouldn't have been inspired to write this article. I'd just use Genymotion and be happy.

On my system, I can start the Genymotion emulator, connect with a debugging session in Google Chrome and see my application successfully deployed. What does not work is the debugging session. I get the following error in my javascript console:

view plain print about
1Page.getResourceTree failed.
2ReferenceError: process is not defined

While googling for a resolution, I can see others report a similar issue, however no combination of repudiation steps makes this error go away. Thus, the debugging session is not enabled and I get none of the benefits of using Genymotion.

It is a shame, but I make do with the combination of tns run android --emulator and tns livesync android --emulator --watch as needed.

How to solve error: [Oracle JDBC Driver]Transliteration failed, reason: invalid UTF8 data

I got a strange error "[Oracle JDBC Driver]Transliteration failed, reason: invalid UTF8 data" while working on a client system. I spent a reasonable amount of time trying to work out what caused this.

The Oracle database was a restore of an Oracle 8.1.6 system onto the new Oracle XE 11.2. During the import, the character sets changed.

  • export client uses WE8ISO8859P1 character set (possible charset conversion)
  • export server uses WE8ISO8859P1 NCHAR character set (possible ncharset conversion)
  • import done in WE8MSWIN1252 character set and AL16UTF16 NCHAR character set
  • import server uses AL32UTF8 character set (possible charset conversion)

So, I'm guessing since the new database did a conversion of NCHARSET from WE8ISO8859P1 to AL16UTF16, the size of the characters threw off something. Thus, there were problems and none of the queries on certain tables worked.

The Solution

The DataDirect Oracle Driver that ships with ColdFusion 9 has an error in it. It appears the error is fixed and if you have an agreement with the provider, you can download an update. However, I don't have an agreement so I downloaded fresh Oracle JDBC Drivers to fix the problem. Here's what I did:
  • Download the drivers here: http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html
  • I used the ojdbc6.jar one.
  • Copy the ojdbc6.jar file to /JRun4/lib (or, if you wanna be fancy, put it somewhere else and update the class path in the jvm.config pertaining to the instance you want to update)
  • Restart ColdFusion
  • Enter the following in the JDBC URL field: jdbc:oracle:thin:username/password@IP.Address.Of.Database.Server:PortOfDatabaseServer:OracleSID
  • Enter the following in the Driver Class field: oracle.jdbc.driver.OracleDriver
  • Add the user name and password in the appropriate boxes
  • Save the datasource. It should verify if you did everything correctly.

If you got an error, remember these things:

  • Usernames, passwords and seemingly the Oracle SID are case sensitive
  • The JDBC Url Field is particular and must be exactly right.
  • The default port for Oracle is 1521

To The Most Courageous Woman I Know

This year has been a year of turmoil and also a year of blessings. Most years are like that, though this one has been particularly full of highs and lows. I wanted to take a moment to give a shout out to the most courageous woman I know.

My cousin, Erika Bogan was badly injured in a terrible car crash in early 2002 when she was ejected from the vehicle, suffered major damage to her spinal cord and was in a coma for 10 weeks. When she woke up, she found she was paralyzed from the waist down. Imagine for a moment, what it would be like to be riding in a car one second, awake in a hospital the next second to be told 10 weeks had gone by, and by the way, you'll never walk again.

Erika had a long road ahead of her. She had a lot of choices to make and none of them were easy. You can read more on her story on her blog.

Erika became an advocate for people with disabilities and became active helping and inspiring others. This year, Erika competed for and won the Ms. Wheelchair North Carolina 2009 title. She then competed against tough competition to win Ms. Wheelchair America 2009 title. We are all very proud of her.

The mission of Ms. Wheelchair America is to provide an opportunity for women of achievement who happen to be wheelchair users to successfully educate and advocate for the more than 52 million Americans living with disabilities. In her short term as Ms. Wheelchair America, she's:

  • Served as Participant, Mentor and Speaker at Camp Discovery
  • Learned to Surf, through Life Rolls On (Yay for surfing)
  • Honored as Guest speaker for the Real Economic Impact Tour Kick-off on behalf of the IRS and the NDI along with Robert David Hall from CSI, at the National Press Club in D.C.
  • Visited the White House

As we roll (pun intended) into the Thanksgiving holiday, I'd like to pause and give thanks to Erika for her inspiration to me and to the many people she's impacted with her life.

If you are interested in learning more about Erika, the Ms. Wheelchair America competition or advocacy for the disabled, you can:

Erika Crowned Ms. Wheelchair America

Erika Before Speaking to the IRS and the NDI

Erika with CSI's Robert David Hall

"Come to the edge, he said. They said: We are afraid. Come to the edge, he said. They came. He pushed them and they flew." -Guillaume Apollinaire

So you wanna learn Regex? - Part 4

Welcome to So You Wanna Learn Regex? Part 4. In our last exercise, we looked at a simple way to clean a whole bunch of strings. This was accomplished by making a pattern, then removing everything according to that pattern. This time we are going to add cfqueryparam to a query. Say for example, that you have a junior developer who has been turned loose on her first application and she's done a good job, except for she didn't use cfqueryparam. You just found this out and the site has to go live in 10 minutes and you have 200 queries to fix. Do you:

  • a) Download the code to your laptop then pull the fire alarm to stall for time?
  • b) Start blasting your resume out on Monster.com?
  • c) Take a fistfull of aspirin, knowing your forearms will ache in the morning?

If you answered d) none of the above, please keep reading.

Assume this set of declarations:

UPDATE plant
	SET 	Symbol = '#form.symbol#',
			SynonymSymbol = '#form.SynonymSymbol#',
     		ScientificNameWithAuthor = '#form.ScientificNameWithAuthor#',
     		CommonName = '#CommonName#',
     		Family = '#Family#'
WHERE PlantCode = '#form.plantCode#'

What we want, is to turn: '#form.symbol#' into: <cfqueryparam value="#form.symbol#" cfsqltype="cf_sql_varchar">

So as you know, we define this pattern in the gobbledegook of regular expressions. When read one chunk at a time, these actually make sense. We'll go through the exercise, then look at why it worked.

In Eclipse, perform the following:

[More]

On Start Ups, Developers and Equity

I skimmed a post on FlexCoders today that posed the question "If you had the chance to start up a RIA development company, How would you go about acquiring amazing developers without start up capital?". Being an entrepreneur and also being a developer, I wanted to put some thoughts out there. Keep in mind these thoughts are not directed at the original poster, but to the community at large who is constantly offered interesting and creatively worded business propositions by the non-development community.

On Entrepreneurs

Entrepreneurs are an interesting breed. They function much like a proud parent of a reasonably untalented child. I don't mean this to offend anyone, but I do want to draw a metaphor. Have you ever been forced to sit through a child singing a very clumsy, off-key, screeching song, only to have the proud parents and prouder grandparents beam at the end and ask you what you thought? Parents are often blinded by their love and their involvement in their children and often value the allure of the child (and the metaphorical singing) much more than others with less involvement. This is a natural phenomenon, and I believe vital to the continuance of the human race.

Entrepreneurs often have the same blinded fascination and love for their own business ideas. They categorically believe in the success of their idea and will move heaven and earth to see the idea come to fruition. This often means sacrificing all else, family, social relationships, outside hobbies, etc, to further the idea of the business.

Entrepreneurs often consider their business to also be their principle hobby, effortlessly spending nights and weekends developing the idea and the business around the idea. Business is fun, for them.

Another noteworthy thing about entrepreneurs is they are perpetually short of funds, time and talent to carry out these ideas. See, ideas are cheap and any visionary can have several really good ideas per day. Ideas are easy to think of, and internal optimism and intuition can cover any potentially glaring holes.

On Ideas

Reality is, ideas actually do not matter. What matters is execution of those ideas. Actually, execution takes a back seat to getting paid for the use of the idea. Getting a check from a customer or a client is the highest form of flattery for an idea and often requires a series of efforts from a multi-disciplinary team all working in the same direction. The end reward for the entrepreneur is successful fruition of their idea.

Let's look at software for a moment. Software requires development. Selling software requires marketing, sales and legal expertise. Running a software business requires people skills, management expertise and financial acumen. Oh, and it requires an idea, but we already discussed the worthiness of ideas, didn't we.

In a start up company, the entrepreneur will probably fulfill a number of those roles. This is key as it helps the entrepreneur marshal the scant resources available to bring the idea through the phases leading to a customer writing a check. Often, the entrepreneur is not a developer, but knows he/she needs developers and developers are somewhat costly in the grand scheme of things. So the wily entrepreneur seeks to procure developers for as little expense as possible. An economy of resources is a good thing.

However, I submit to you that the original question prompting this article is near a impossibility. The question was "If you had the chance to start up a RIA development company, How would you go about acquiring amazing developers without start up capital?"

Software developers have ideas too. Many of them are creative problem solvers and gain tremendous business experience by writing software that solves real problems in business. Most of them enjoy their work and often put in extra hours working on side projects to entertain themselves. So wouldn't it seem logical to procure a few good software developers that will work for free while the business got started?

As a software developer, my time is money. If I am going to divert my attention from a steady paying job, and away from my side interests, money is going to be involved.

I don't mean future money, like "Instead of paying you, we'll give you a trainload of stock options" but today money. Today money is money that I can go to the bank today and receive the rectangular green yuppie food stamps I'm accustomed to using for groceries and gas.

On Working With No Pay and Open Source

I often work on open source software for which I receive no pay. Is this the same as working in a start up for no pay? I submit there is at least one vital difference. In open source software, there is no money. Thus there is no schedule. We may publish a schedule of our intent, and are free to move that schedule as priorities change.

In a start-up business, the prospective client or customer controls the schedule. If you tell a prospect a demo version will be ready on Friday, you must meet your deadline. Missed deadlines communicate untrustworthiness and unreliability to your prospects. This is anti-cool and usually means less checks. So while I'm perfectly happy to spend inordinate amounts of unpaid time writing software, I'm not willing to have my schedule controlled by those not paying for the right to set my priorities. I'd bet most competent developers feel similarly.

On Evil Investors and Entrepreneurs

Most successful entrepreneurs have been through a money-raising event, like a bank loan or venture capital. These events are usually painful for the entrepreneur because the entrepreneur is not in control and has to listen to the unvarnished opinion of sophisticated investors who deal with hundreds of business ideas all the time and aren't blinded by the vision or the visionary.

I learned everything I know about entrepreneurship from my Dad, a serial entrepreneur. His last business was a contracting company. I would never be able to imagine my Dad offering stock options or deferred payments to his workforce, in lieu of payment. If he did, none of them would show up for work, and I wouldn't blame them for it.

As an entrepreneur, I want to instill the highest confidence in my prospective clients and customers, thus, I demand the right to set priorities and schedules of any team member in my group. For that right, I pay them. Since I pay them, they consistently deliver over and above expectations. This makes us look good to our prospects and gives me confidence to reach across the desk and shake hands to close the deal.

On Bootstrapping Thoughts

So, is it possible to assemble a team without start up money? I'd say there are some ways to make it work, but only for a little while.

1) Cult of Personality. If you have a very strong community reputation as a smart person who gets things done, you can probably get some reasonably talented people to drink your kool-aid for a little while. Make sure to deliver on your promises. Missed promises=diminishing team.

2) Project Work. If your business is service related, land a big project as the way to start up the company. Developers might accept a lower rate on the first contract if promised a higher rate on future contracts. This is certainly preferable to no pay at all.

3) Get funding. Why is it you have no funding? Financial Investors are trained professionals and want to invest in businesses to earn a profit. They MUST earn a profit so if your idea has appeal and your team is competant, you can usually get some funding.

4) Grants. There are a multitude of Entrepreneurial grants and programs available. Many of these have a simple application consisting of a few pages. Working on the application will likely help you refine your idea so even if you don't get the grant, you'll get something out of it.

5) Business groups. Find business groups, like Business Networking International or the Council for Entrepreneurial Development. They can often help you find interns which might help you get over the hump.

To the entrepreneurs out there, good luck to all of you. I know the road is interesting, challenging and rewarding like no other.

-Dan Wilson

P.S. To the reader: What sorts of opportunities have you been presented with? I invite you to share your stories and ideas in the comments.

Practical Refactoring In ColdFusion - Live Example

Practical Refactoring

I've done a few presentations on refactoring in ColdFusion and in those presentations, I show a lot of code samples towards the end. No matter how eloquent I am in the first part of the presentation, the light always goes on for the audience when I show code. If you think about it, it makes sense, why try to explain concrete principles in abstract terms?

I do my refactoring in sweeps. A sweep is a cycle through the code in which I make incremental improvements. At the end of a sweep, the code should (it better) still function as well as it did pre-sweep. By breaking up the refactoring up into small sweeps, we can stay focused and keep out of the weeds.

In this article, we are going to look at some code that could use a refactor. Then we'll make a few sweeps through the code to tidy it up a bit. Along the way, I'll explain why I am refactoring out a certain piece. Keep in mind, we are all still learning. None of this is meant as Final Law of Software Design. I'm always refining my viewpoints and learning new things so I'll probably disagree with something I've done here at some point in the future. In the end, as long as this article is thought provoking for you, we've both won. Can Ya Dig?

First, here is the code sample. Scan the code and fix in your mind the general idea of what is going on. We'll pick back up on the other side.

The Original Code

view plain print about
1<cffunction name="onError" output="true">
2    <cfargument name="exception" required="true"/>
3    <cfargument name="eventName" required="true"/>
4        <cfif compareNoCase(trim(arguments.eventName),"onSessionEnd") And compareNoCase(trim(arguments.eventName),"onApplicationEnd")>
5            <cfif compareNoCase( arguments.Exception.RootCause.Type, "coldfusion.runtime.AbortException") >
6                <cfoutput>
7                <CFIF isDebugMode() is false>
8                <cfinclude template="/errortemplate.htm"/>
9                <CFELSE>
10                <h2>An unexpected error has occurred.</h2>
11                <p>Error event: #arguments.eventName#</p>
12                <p>Error details:</p>
13                <cfdump var="#arguments.exception#"/>
14                </CFIF>
15                <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
16                <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
17                </cfoutput>
18            </cfif>
19        <cfelseif not compareNoCase(arguments.eventName,"onApplicationEnd")>
20            <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
21            <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
22            <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
23        </cfif>
24</cffunction>

Summary

Ok, answer to yourself the following questions:

  • Is the code right?
  • Do you know the purpose of the code?
  • Is it easy to understand?

The first question is a bit of a slippery slope. In my book 'Right' and 'Wrong' are determined by whether or not the code works. The code above actually works just fine. Compiled down to Java Bytecode, it happily processes errors with no defects, so it is 'Right'. When dealing with fuzzy subjects like code-cleanliness and proper organization, you'll find many more opinions than hard/fast rules. Clean Code is like Good Art, you know what you like when you see it. So stay away from calling other developers' code 'Wrong'. It only makes people defensive and defensive minds are not in learning mode.

Now that we've gotten past that, did you understand the purpose of the code? If you said "this code handles errors", give yourself 2 points. (The function name helped, didn't it?)

Was the code easy to understand? Can you verbalize what the code is doing? Try... no seriously, read this code from top to bottom. Can you do it? Did you have to reread parts of it?

It is a known fact that code we write personally instintively makes more sense to us than code other people write. This holds true even months after the code has been written. Good programmers write code that can be easily be understood by others. We are going to refactor this code to be more easily read.

First Analysis

A few easy things to point out... compare() and compareNoCase() are two functions that work opposite of how we read. If you use compare() to compare two identical strings, you get a return of 0, which ColdFusion treats as false, meaning we have to reverse our boolean logic in conditionals to accomodate this. Some people will tell you that compare() is faster than using an operator like IS or IS NOT. They might be right, I'm going to refactor the use of compare() and compareNoCase() out of the code anyways. If it turns out we needed the extra 'performance' of these functions, we should have implemented this part of the site in Hardware.

Next, the case is mixed inappropriately. Some operators are lower case, some are mixed case. Some of the conditionals are upper case, some are lower case. We'll normalize this and get it all looking consistant.

Also, this code has nested conditionals. Some times the only way to represent logical flow is to nest conditionals though most often it can be simplified for better readability. In this case, it looks like we truly care about a few conditions so I'll look at untangling the nest as well.

I'll put a few comments in as well, since that will help us remember what we were thinking in the middle of the refactor. Without further preamble...

First Refactor

view plain print about
1<cffunction name="onError" output="true">
2    <cfargument name="exception" required="true"/>
3    <cfargument name="eventName" required="true"/>
4        
5        <!--- Exit conditions --->
6        <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
7            <cfreturn />
8        </cfif>
9        
10        <cfif trim(arguments.eventName) IS "onSessionEnd">
11            <cfreturn />
12        </cfif>
13        <!--- Log and Exit --->
14        <cfif trim(arguments.eventName) IS "onApplicationEnd">
15            <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
16            <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
17            <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
18            <cfreturn />
19        </cfif>
20        <!--- use error template file or print to screen --->
21        <cfoutput>
22            <cfif isDebugMode() is false>
23                <cfinclude template="/errortemplate.htm"/>
24            <cfelse>
25                <h2>An unexpected error has occurred.</h2>
26                <p>Error event: #arguments.eventName#</p>
27                <p>Error details:</p>
28                <cfdump var="#arguments.exception#"/>
29            </cfif>
30            <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
31            <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
32        </cfoutput>
33</cffunction>

Second Analysis

Ok, That is a pretty good start. We got rid of compare() and compareNoCase() so the code reads a little nicer. We got rid of the nested conditionals so we don't have to keep track of several layers of boolean logic and we cleaned up the inconsistent use of case.

Another thing that I try to stay away from is using negative boolean logic. See where we check for the isDebugMode() function? I'd much rather have the TRUE case up top and have the negative case be the ELSE portion.

Also, some of the logging is duplicated. Looks like someone was Copy/Pasting :). Let's clean that up as well.

Lastly, we are going to put in good comments all the way down the line and use appropriate whitespace for readability.

Second Refactor

view plain print about
1<cffunction name="onError" output="true">
2    <cfargument name="exception" required="true"/>
3    <cfargument name="eventName" required="true"/>
4    
5    <!--- We don't want to deal with the cflocation as an error, so bail --->
6        <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
7            <cfreturn />
8        </cfif>
9    <!--- Lets deal with events next. --->
10        <!--- We don't want to deal with the onSessionEnd as an error, so bail --->
11        <cfif trim(arguments.eventName) IS "onSessionEnd">
12            <cfreturn />
13        </cfif>
14        
15        <!--- From this point onward, we want to log the errors --->
16        <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
17        <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
18
19        <!--- Log as Information and Bail --->
20        <cfif trim(arguments.eventName) IS "onApplicationEnd">
21            <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
22            <cfreturn />
23        </cfif>
24    <!--- Now, let's deal with explicit types we want to handle... --->
25        <!--- If we get here, we have something to handle --->
26        <cfif isDebugMode() is true>
27            <!--- print the error to the screen --->
28            <cfoutput>
29                <h2>An unexpected error has occurred.</h2>
30                <p>Error event: #arguments.eventName#</p>
31                <p>Error details:</p>
32                <cfdump var="#arguments.exception#"/>
33            </cfoutput>
34        <cfelse>
35            <!--- use the nice error handler --->
36            <cfinclude template="/errortemplate.htm"/>
37        </cfif>
38</cffunction>

Final Analysis

That looks even better. Now that our conditionals use positive boolean logic they are much easier to read. We also were able to remove duplicate logging calls. Not all code duplication is bad, of course, but when we can get rid of it and improve the clarity and readability, we all win.

The comments are also very descriptive and tell us the intent and reasons for the code. This way, other developers can quickly understand what we were trying to do, even if it isn't working properly.

Just for fun, I'm going to paste the finished code below without comments and whitespace. Read through the code and notice how it reads more like English language.

Final Code - No Comments/No Whitespace

view plain print about
1<cffunction name="onError" output="true">
2    <cfargument name="exception" required="true"/>
3    <cfargument name="eventName" required="true"/>
4        <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
5            <cfreturn />
6        </cfif>
7        <cfif trim(arguments.eventName) IS "onSessionEnd">
8            <cfreturn />
9        </cfif>
10        <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
11        <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
12        <cfif trim(arguments.eventName) IS "onApplicationEnd">
13            <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
14            <cfreturn />
15        </cfif>
16        <cfif isDebugMode() is true>
17            <cfoutput>
18                <h2>An unexpected error has occurred.</h2>
19                <p>Error event: #arguments.eventName#</p>
20                <p>Error details:</p>
21                <cfdump var="#arguments.exception#"/>
22            </cfoutput>
23        <cfelse>
24            <cfinclude template="/errortemplate.htm"/>
25        </cfif>
26</cffunction>

Not to shabby, yeah? The code works just like the original sample, but it is much easier to understand the flow of the function. Also, by doing our refactoring in sweeps, we simplified the code in stages, reducing the chance we'll miss something. Now go to the last sample and read it aloud. Notice how it feels natural when you read it? This code will definitely be easier to maintain in the future, won't it? There are lots of other principles to keep in mind when refactoring. We'll look at a few more in the next article.

Agree? Disagree? Tell me all about it in the comments.

P.S. Do you have code you'd like to see refactored?

If you have a code sample you would like me to refactor, send it to me using the Contact Form on this blog. Please try to keep the code chunk below 100 lines as that seems to be the limit of clarity for a blog article.

How to grow the ColdFusion community. What YOU can do to help.

Every day, a whole lot of useful information about ColdFusion is created and delivered over the airwaves. ColdFusion developers are passionate about their platform of choice. We know better applications are built quicker using the only commercially supported platform offering Image manipulation (by the people who make Photoshop, nonetheless), RIA, Server-side printing/PDF forms, Charting, Integration, Reporting and other libraries/frameworks. So why the occasional bad press?

After looking at the issue for some time, I've had some relevations. The majority of the developer promotion and information about ColdFusion is spread inside the ColdFusion community. Yes, friends and neighbors, we preach to the choir a bit more than we should.

Where do you get ColdFusion news from? I'd bet you answer either MXNA, Feed-Squirrel, FullAsAGoog.com or ColdFusionBloggers.org. Am I right? Those are great community resouces. I use them myself. As a matter of fact, most ColdFusion developers worth their salt use those aggregators for news. The problem is, Java developers, Perl developers, .Net developers and Ruby developers do not use those sources for their news. Thus, a tree falls in the forest, but no one is there to hear it.

What the heck is dzone?

Dzone.com consists of a variety of internet properties all focused on meeting the needs of developers. As of late, dzone.com added a ColdFusion tag to their dzone.com link sharing website. The fine folks at dzone.com also added a special zone for ColdFusion. You can see this zone at the aptly named coldfusion.dzone.com. These two websites are for you, the passionate ColdFusion developer, to get the message out. ColdFusion is the best tool on the market for quickly building feature rich web based applications.

How Dzone.com Works

At dzone.com, you can submit links of interesting posts into a pool where developers from all sorts of backgrounds can find them. Backgrounds like Java (Natural ColdFusion Converts), Perl, PHP, Python and .Net, anything really. If you come across a helpful or interesting article somewhere in your Internet travels and the link will benefit your fellow developers, add the link into the system. When others read the article you have submitted via link, they may vote it up, or down. Links with a high number of positive votes will be shown more often. This concept is sort of similar to digg. As a matter of fact, if you took out all the whining close-minded users and focused the content on only developer-centric topics, you would have a pretty good idea of what dzone.com is.

How ColdFusion.dzone.com Works

ColdFusion.dzone.com is a targeted portal for ColdFusion information. It is managed and organized by members of the community. Content on this site will remain an open community resource. From time to time, there will be interviews, special articles, announcements and other items of interest. I expect this resource to evolve as time passes.

ColdFusion.dzone.com has a few Zone Leaders. Rey Bango is one. I am another. There will be one or two more additions in the upcoming future. The responsibility of the Zone Leaders is to moderate discussions, be a point of contact for ColdFusion related matters and to review articles submitted by community members.

My Vision

It is my vision that coldFusion.dzone.com will be a resource for the ColdFusion community by providing a place to share information. We encourage quality submissions by members of the community. While not every article can be posted, we encourage those of you who want to share your experiences and lessons with the rest of the community. This is a great way to help others, get more traffic for your blog and increase your community visibility.

It is my vision that ColdFusion.dzone.com will be a resource for other communities. ColdFusion is a great language and a great platform. Not enough people know that. By having a zone full of good ColdFusion content as well as by submitting good content from the zone and from community blogs, we can help bring the reality of ColdFusion to the masses.

How You Can Participate

http://coldfusion.dzone.com/ is yours. Bookmark it now. Come here often and read the information and post content you want to share with the developer community at large. As always, feel free to add a link back to your own blog. You deserve the recognition and the traffic.

The queue of ColdFusion related content on dzone.com is something you should check often (Don't worry, there is an RSS feed). As I said before, submitted articles get votes and rise to the front page where tens of thousands of developers from all backgrounds can see, read and learn. When you see a good article in the queue, give it a vote.

The most popular ColdFusion content on dzone.com is another page to watch (RSS Feed Too). Articles that have made it to this page have proven popular and have garnered visibility for the ColdFusion community in general and the author in specific. You might want to read these articles because your peers have already voted them worthy. If you agree, give it a vote.

By sharing our love and passion for ColdFusion among other communities, we will grow the ecosystem at large. Please consider these resources as your personal way to engage the developers of the world.

Are you using ColdFusion with Java? I'd like to interview you.

There exists untold billions of lines of Server Side Java code running in production environments today. Java is a fine language, widely adopted and used by companies both large and small. One of the drawbacks in Java development is that Java is not a rapid development environment. Adding functionality, screens and new applications on top of an existing Java based SOA requires manpower and time.

ColdFusion is built on J2EE underpinnings. The deep Java heritage offers tremendous power and functionality. ColdFusion objects are Java objects. A ColdFusion Array is actually an instance of java.util.Vector thus you can run Vector methods directly on a ColdFusion array. It is just that simple. ColdFusion can easily create or consume SOAP webservices. ColdFusion can knit together disparate subsystems to make a unified SOA. All without fundamentally changing platforms or languages.

[More]

What tools do use to design websites?

Being part of the Kalendar UI Design team was a very enlightening process. One of the things I learned is that some people are truly gifted. Another thing I learned is that Designers are very particular about their choice of tool. Another thing is Designers do not often agree on which tool is the best. Upon reflection, none of this is surprising.

It has awoken a desire to be more proficient in Design tools. I have previously used Fireworks and Photoshop to modify images. I have played with filters drop shadows, layers and the like with mixed results. I have also lost my temper trying to make simple graphics. Thus, I am a confessed n00b.

Mainly, my work is for the web. Thus, I want to learn a tool that creates web based layouts quickly. If you have experience with creating and working with web ready assets, I would like your opinion. Which tool do you recommend for making web layouts? Why do you prefer that tool?