Check out our new training course on AngularJS for Flex Developers

Deconstructing the Consulting Contract

At the recent 360|Stack conference, I presented some lessons learned about various business ventures I've been in. The presentation was called How to Fail Fantastically and spoke about many of the things I've done that didn't work out perfectly.

Molly mentioned to me that most of the questions people asked about were about the legal portion of the talk and about contracts. That inspired me to dig out this article I had written back in 2007 for Fusion Authority Quarterly Update.

The article is entitled Deconstructing the Consulting Contract. At the time; this was one of the easiest articles I ever wrote; despite it being non-technical in nature. I approved the final on January 13th, 2007 if that matters.

My Hamburger Recipe

And now for something non-technical. A friend asked for my hamburger recipe. I've made this with both ground beef and ground turkey and we really like the taste. It works great for meatballs too:

Ingredients:

  • 1-1.5 Pounds of Ground Meat (Beef or Turkey). I buy the biggest package I can at BJs and split it in half.
  • 1/3 cup of Olive Oil
  • 2 Eggs
  • 1 Cup of Breadcrumbs (I use Panko Bread Crumbs which I run through a Food Processor and make very fine. The measurement of 1 cup is after they are food processed)
  • Seasonings (This is what we use)
    • 2 teaspoons of Parsley
    • 2 teaspoons of Onion Powder (or Diced Onions)
    • 1 teaspoon of Garlic Powder

Instructions:

  1. Mix all Ingredients Together. I use a KitchenAid Stand mixer; but you could also do it with your hands.
  2. Form into patties [or Meatballs]
  3. Bake in Oven at about 400 degrees for 10 minutes. This only partially cooks them; so if you want to eat right away you can bake for a bit longer.
  4. Store in freezer or fridge until ready for your meal. Often before cooking I will stab them through the center with a knife.

I've toyed around with different seasonings to mixed results. But, everything has been edible. Add Red Pepper if you want something spicy. Add oregano and/or Italian Seasonings if you want something with an Italian flair.

Creating a ViewStack with AngularJS

I've spent the past two months diving into as many JavaScript frameworks as I could find time for. I am trying to determine what I can use in a book I'm writing entitled "Life After Flex". The book will be about converting a Flex application to JavaScript. I decided that I like a lot of things about AngularJS.

This is a tutorial on how to get ViewStack like functionality within an AngularJS HTML project.  My one caveat is that I am not yet an expert in AngularJS; so my understanding of what goes on under the hood may be wrong.

What is a ViewStack?

One of the common navigator components in a Flex Application is known as a ViewStack. It allows multiple views to occupy the same the same space in an application at the same time.  Only one view is displayed at the same time.  The Flex ViewStack does not inherently include any way to navigate between views because that is usually done through user interaction, either through something in the view or through a TabBar.  In the MX Component set; the TabNavigator combines a ViewStack with a ButtonBar for us.

One use case for a ViewStack might be to show a login screen in one view; and the main application screen as another view.  When the user successfully authenticates the application will tell the ViewStack to change from the login view to main application screen.  There are a multitude of uses for this component.  

I wanted to see if I could use a similar approach in an HTML5 based apps.  I was successful and you can view the simple app.

The Index.htm page

The index.htm or index.html is often the main page of an HTML site.  That is where this tutorial starts.  The page must import the angular.js framework and our custom JavaScript Code, in viewstack.js.  It also needs to set up some special AngularJS directives so that Angular will know where to display the custom views.

First, the HTML page imports the JavaScript files:

<html>
<head>
<script src="angular.js"></script>
<script src="viewstack.js"></script>
</head>

The body tag will define the AngularJS application:

<body ng-app="viewStackSample">

The ng-app is a special directive for AngularJS that ties code in our custom JavaScript file to the elements of the HTML document.  Next, a div will contain the view:

<div ng-view></div>

The div includes a special AngularJS directive named ng-view.  Finally the HTML is closed; finishing off the page:

</body>
</html>

The viewstack.js File

The index.htm page referred to a viewstack.js file’ and this file will include our custom JavaScript code.  This code will define two custom controllers; one for each view. It will also set up a config element called a routeProvider.  A route is, basically, a URL.  Based on the URL, the ng-view in the index.htm will decide which HTML page to display.  The approach reminds me of the early years of ColdFusion’s Fusebox framework.  Based on the URL; it determines which page will be displayed.

This is the routeProvider setup:

angular.module('viewStackSample', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/view1', {templateUrl: 'view1.html', controller: View1Ctrl}).
when('/view2', {templateUrl: 'view2.html', controller: View2Ctrl}).
otherwise({redirectTo: '/view1'});
}]);

The first line is creating an AngularJS module.  The module is named; viewStackSample which refers back to the value of the ng-app directive defined on the body tag in the index.htm. 

On the newly created module, the config method is called, and the ‘$routeProvider’ value is configured.  The $routeProvider is defined with a function.  The function has two “when” clauses and one “otherwise” clause.  This code, basically says:

  • If the URL has “/view1” in it then display the view1.html in the ng-view of the index.htm file.  Send it an instance of the View1Ctrl.
  • If the URL has “/view2” in it; then display the view2.html in the ng-view of the index.htm file.  Send it an instance of View2Ctrl.
  • If the URL has neither of those in it; then redirect the URL to ‘/view1’ and try again.

The two values View1Ctrl and View2Ctrl are defined the same viewstack.js file:

function View1Ctrl($scope) {
$scope.title = 'View 1 From Controller';
}

function View2Ctrl($scope) {
$scope.title = 'View 2 From Controller';
}

These two functions are, in essence, data stores, like a model class.  They each define a variable instance named title and put that on the $scope variable.  $scope is just a fancy way to send data into the view template.  These functions can do a lot more than just define data; they can also have functions which can call remote services or communicate with other aspects of the application. 

The view1.html and view2.html files

The view1.html and view2.html files are simple files.  This is view1.html:

<h1>{{title}}</h1>
<a href="#/view2">Go to View 2</a>

The h1 tag refers to the title variable defined in the viewstack.js file.  It uses double curly brackets, with the variable name inside it.  This is framework magic which tells the template to display the value of the title variable instead of the actual text.  It also includes a link which will change the URL to “#/view2”. 

The view2.html is almost identical to view1.html:

<h1>{{title}}</h1>
<a href="#/view1">Go to View 1</a>

The view2.html file has the same H1 tag; although a different value will be displayed.  The link goes back to “#/view1”.    

Final Thoughts

Loading this page will allow you to switch between the two views easily by clicking the link.  The code is not quite as encapsulated as the Flex ViewStack; however it is not too difficult and an approach like this can provide a lot of flexibility to an application.

Sign up for DotComIt's Monthly Technical Newsletter

360|Stack is the rebranded 360|Flex.

I am buried in my man-cave lately, focusing on writing a book about converting a Flex app to other technologies. I wanted to pop my head out for a second to let you all know that I'll be speaking at the 360|Stack conference coming up in the beginning of August.

360|Stack is the old 360|Flex conference, but it has a slightly different name.

I'll be giving an inspirational presentation entitled "How to Fail Fantastically." I'll be talking about my various business ventures, such sa The Flex Show and Flextras and DotComIt and probably some you had never heard of.

Even if that doesn't excite you there is plenty of real technical content covering everything from Google Glass to more JavaScript frameworks than you can shake a stick at.

I have an extra ticket that I'm undecided what to do with. I'm thinking maybe some type of contest?

Manually configuring ColdFusion with IIS7

I sent this email out yesterday as part of the Flextras/DotComIt newsletter. I thought I'd repost it here.

I recently had the opportunity to move some of my hosted sites to Amazon web services. The Flextras site, The Flex Show, and my personal blog, are now all hosted on EC2. It has been a few years since I've had to deal with my own production server maintenance; and I came across a weird issue with IIS7 and ColdFusion 9. I thought I'd describe the issue and explain my solution.

IIS6 Compatibility is turned on

Normally, when you create a new instance of an IIS web server, you'll need to associate ColdFusion with it. ColdFusion provides a tool named the Web Server Configuration Tool that can attach an instance of ColdFusion with an instance of IIS. If you happen to be using ColdFusion 9.02--or later--and IIS7; you may receive this error:

The Web Server Configuration Tool will not work with IIS7 if IIS6 Management Compatibility is enabled. On this particular server, the management compatibility was enabled for the FTP plugin could be managed on the server. I did not want to uninstall the IIS management compatibility if I could avoid it. How could I tell IIS7 that it should send .cfm requests to ColdFusion for processing without using the Web Server Configuration Tool?

Editing the applicationHost.config file

Under the hood the mappings that tell IIS7 how to communicate with ColdFusion are in a file named applicationHost.config. You can find this file in the 'C:\Windows\System32\inetsrv\config\' directory. This file contains a lot of configuration for IIS7.

If IIS7 was already installed when ColdFusion was initially installed, then you can find a section that references an existing IIS7 instance with your existing ColdFusion instance. Look for something like this:


<location path="iisInstanceName">
<system.webServer>
<handlers>
<clear />
<add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
<add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
<add name="AboMapperCustom-130401" path="*" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\1\jrun_iis6_wildcard.dll" requireAccess="None" responseBufferLimit="0" />
<add name="AboMapperCustom-130411" path="*.jsp" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="AboMapperCustom-130412" path="*.jws" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="AboMapperCustom-130413" path="*.cfm" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="AboMapperCustom-130414" path="*.cfml" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="AboMapperCustom-130415" path="*.cfc" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="AboMapperCustom-130416" path="*.cfr" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="AboMapperCustom-130417" path="*.cfswf" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="AboMapperCustom-130418" path="*.hbmxml" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="AboMapperCustom-130419" path="*.hbmxml" verb="*" modules="IsapiModule" scriptProcessor="C:\ColdFusion9\runtime\lib\wsconfig\jrun_iis6.dll" requireAccess="Script" responseBufferLimit="0" />
<add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
<add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
</handlers>
</system.webServer>
</location>

If you're using CF Standard, you can just copy and paste this section; then change the path name on the location to be the name of your new IIS7 server instance. Restart your IIS instance and that should be all you need. Otherwise, you'll have to create the above section manually; by copying and pasting from above and changing your paths to relate to your own CF Install.

Although I didn't have the experience of setting this up using CF Enterprise, I expect the procedure will be similar; you'll just need to point to the jrun_iis6.dll for your specific instance of ColdFusion.

How to Create a System for Caching Data

I wrote this article for the monthly Flextras newsletter, and thought I'd share it here.

I was working with a client recently and we had some performance problems while accessing remote data from within our application. The user interface, built with Flex, was accessing our ColdFusion server, and ColdFusion would relay requests onto another remote system using SOAP web services. The web service data didn't need constant updates, so we decided to create a caching system for the data to improve performance. I thought the concepts behind that would make an interesting topic for this month's newsletter.

What Type of Data to Store?

We decided it was best to create a generic system to cache any type of data. The system should handle any type of data we wanted to throw at it. To accomplish this, I created two classes a CacheManager class and CacheData class. The CacheData class is intended to be a generic object used by the CacheManager. Here is a diagram of the class:

The CacheData class is used by CacheManager to store the cached data. It has three properties: the data to store and two dates. The first date is, dateCached, which keeps track of the date and time that the data was first cached. The second element is dateLastAccessed, which keeps track of the date that the data was last accessed. The data property should be protected, or private, or something similar depending upon your language of choice. The two date properties should be publicly accessible.

The class has two methods: get() and set(). The get method returns the data and should also update the last accessed date value to the current date and time. The set method will update the internal data property, as well reset the two dates. In an attempt to keep this as platform agnostic as possible; this would be pseudo code for the class:


package{ class CacheData{
// this value stores the data
protected var data : *;
// this value stores the date that the data was initially stored
public var dateCached:Date
// this value stores the date that the value was last accessed
public var dateLastAccessed:Date
// this method can be used to retrieve the data
public function get ():*{
dateLastAccessed = getCurrentDate();
return data;
}
// this method can be used to set the data
public function set(value:*):void{
data = value;
dateCached = getCurrentDate();
dateLastAccessed = getCurrentDate();
} } }

This is a very simple class, not much more than a glorified value object.

The CacheManager Class

The CacheManager class is a bit more complicated. This is your application's window into the cached data.

This is the class diagram for the CacheManager:

The CacheManager has two properties; minutesCached and cachedData. The minutesCached property is an internal value will be used to determine when data should be flushed and deleted. The cachedData is also an internal value, but it is a bit more complicated. I created that as an associative array of associative arrays. In Flex, an associative Array would be a Dictionary; in ColdFusion that would be a Struct. The first key of the associative array is the type of data you want to store. I call this the cacheKey. This may be "products" or "orders" or something similar, depending on the data you want to store. The second associative array's key is the dataKey. Examples of this may be "ProductID1" or "Order13" or anything that can be used to uniquely identify the type of data, such as its database's Primary Key.

The combination of the dataKey and the cacheKey is used to retrieve the data. The use of the two key structure allows a single instance of the CacheManager to be used to cache multiple types of data. There are also two methods as part of the cacheManager: store() and retrieve(). The store method accepts three arguments: the data, the cacheKey, and the dataKey. It will create a new object of CacheData object and call the CacheData.set method to store the data. It is the simpler of the two methods.

The retrieve method is where the magic happens. It first check's to verify that the data exists. Then it checks to make sure that the data is still relevant based on the current date and the date that the data was last accessed. If the data is too old; then it can be deleted. Otherwise it can be returned. This is a pseudo code class:


package{ class CacheManager{
// this value specifies how many minutes the data should be cached
protected var minutesCached : int = 1440;
// this value contains the cached data; using a two key structure. A CacheKey and a DataKey.
protected var cachedData:Dictionary = new Dictionary();
// this method can be used to retrieve the data
public function store (data:*, cacheKey:String,dataKey:String):void{
if(!cachedData[cacheKey]){
cachedData[cacheKey] = new Dictionary();
}
cachedData[cacheKey][dataKey] = new CacheData();
cachedData[cacheKey][dataKey].set(data);
return data;
}
// this method can be used to set the data
public function retrieve(cacheKey:String,dataKey:String):*{
var cacheObject = cachedData[cacheKey][dataKey]
if(!cacheObject){ return; }
var dateToClearCache :Date = getCurrentDate() - minutesCached
if(cacheObject.dateLastAccessed <= dateToClearCache){
cachedData[cacheKey][dataKey] = null; return;
} Return cacheObject;
} } }

Although it is beyond the scope of this article, you could also create a method to automatically clear old cache data. This is probably more memory efficient than waiting until the data is retrieved to clear it out.

Putting it All Together

Now that we have the code behind our CacheManager, the last step is to put that to use. First, create an instance of it; presumably in some globally accessible variable.


public var cacheManager :CacheManager = new CacheManager();

Let's say you just loaded a bunch of products from some remote source. You'd loop over them and store them in the CacheManager instance:


For each product in productArray
cacheManager.store (product, 'products',product.id):
End For Loop

In this code, we use the cacheKey named products and use a product ID for the dataKey. I once read something that said you when you file something; you want to make sure to file it in the way that you can find it when you need it. The dataKey for your cache should follow the same suit. When you need to retrieve the data, you want it to be filed under some name that you can use to retrieve the data later.

Retrieve the data from the cache when you need it, like this:


var product : Product = cacheManager.retrieve('products',product.id);

Be sure to check that you actually got a product back from the cache before you try to use it:


If(!product){
// do something to retrieve the product data from source
// or make sure your code accommodates for a non-existent product
}
// process product

Final Thoughts

I hope you found this article interesting. I did my best to make this as conceptual as possible, so you may have to modify the code in order to work in the language of your choice.

I have two other mini-announcements that I added to the recent Flextras Newsletter. First, the code that never became the Flextras Flex Spreadsheet Component has been open sourced by the original author. It is a very impressive piece of technology. Second, if you're in the mood for interesting weird music; I recorded a full album worth of songs for February Album Writing Month. It is a nice little diversion from programming at times.

Do Marketers Care About Interacting with You on Social Networks?

An associate recently posted a question onto her Google+ wall about how marketers are using social networking. I wrote up a long winded response--for a social network--and decided to share it here too.

First, the question:

Seen on a mailing list recently:

"It's been really discouraging to see how quickly social media has taken its place next to SEM, email marketing, and all the rest as just another broadcast channel with a revenue goal and ROI attached to it."

Do you agree or disagree?

I generally agree, but sometimes it depends on the company.

Here are a bunch of random--and true--examples:

If I speak to VirginMobile on twitter; it is always canned/stock answers. Such as when I asked if they'll get any Windows Phones; the response was something like "we don't have any announcements regarding future phones". It was very formal.

I've liked "Jakes Wayback Burgers" on Facebook because it is my favorite "fast food" burger place in my town. If they respond to interaction at all--which is rare--it usually only positive interaction. For example when I asked Wayback Burger why they were giving away an iPad 2 in a promotion instead of the "latest and greatest model" that was ignored. But, I have them respond to other queries such as "What time does X store open". Very fact based and no personality.

On Twitter, I complained about MX Energy salesman showing up at my door. Seriously, I am sick of these people. I actually posted a sign on my front door that says "no soliciting, especially from MX Energy" They ring my bell less but that sign has not curbed it completely. I didn't even know MX Energy had a twitter account until they followed me. They were was no response to my complaint, no attempt to communicate me, no apologies for the constant interruptions. In fact, I'd say MX Energy is the company I hate most in the world--although Wandisco is trying really hard for that top spot.

Since I brought up Wandisco; let me talk about them. They just bought SmartSVN from the company that owned it. I love SmartSVN and it is the best SVN client I've used. So, I've been a happy customer for many years. I did not receive promotional mailings from the SmartSVN folks--until Wandisco bought them. Now I get emails all the time. I have unsubscribed from their mailing lists using the Unsub" link in their emails. Yet, I Still get emails. I have emailed them back, complaining, but got no response. I have flamed them on Twitter and that did get a response. I have to admit that response was human and personable and swore to me that the issue was a mistake on their part and promised to get the issue fixed.

Fine, mistakes happen. But, when you tell me it is fixed; I want it to be fixed. I'm still getting emails from them; despite multiple times of being promised it would be fixed. After the my last twitter tirade; I got a personal apology emailed to me, promising that this time it was really fixed. I'm impressed they followed up. But, five days later I got another round of promo emails from them. Obviously the issue is not fixed. The point has almost become laughable now. I imagine them as a big corporate company with lots of bureaucratic overhead and no one knows what anyone else is doing. The person who is managing their twitter account (and/or emailing me) is probably promising things they can't deliver on--such as getting my email removed from every copy of their list.

Moving away from Wandisco..

If you take a look at "known" bands such as Toad the Wet Sprocket or Soul Asylum; all the communication is one way. When Dan Murphy left Soul Asylum there were weeks of speculation on their message boards before the band finally responded with a Twitter sized response.

When Wadjet Eye Games (my favorite Indy Adventure Game Publisher) posted on Facebook that they were looking to do auditions for voice overs for their next game; they did not respond to the 3-5 people who asked for more details. If they weren't going to respond; why did they post an announcement on Facebook?

When Lake Compounce--a local amusement park--asked what people liked best about their season pass; I responded with some snark about how the Halloween attractions were an extra charge. That comment was quickly deleted. Instead they could have apologized for the inconvenience.

On the flip side of things; not all companies [or bands] are bad.

The GeekDesk twitter account is amazingly personal. Pretty much any tweet I make regarding my GeekDesk is responded to directly. when I casually mentioned that the desk was making weird clicking sounds when going up and down they offered to open a ticket for me via twitter. That is not the first time they've done something similar for me. Clearly someone there gets it. I cannot recommend GeekDesk enough. It is the best desk I ever owned.

When I tweeted a "recording" of a recent Bowling for Soup show the lead singer responded from his personal twitter account to thank me for sharing. And then he followed my twitter account details to my blog and used it to email me to ask if he could re-purpose the recording. How cool is that?

So, that's my brain dump. Some good; some bad. My perception is that there is more one-way interaction than communication. It's a shame because social networking for companies had a lot of promise.

Check out the Flextras AutoComplete KickStarter

Earlier this week, I launched a Kickstarter project for Flextras. The intent is to flesh out the API of the Flextras Spark AutoComplete component, and then donate it to Apache Flex.

This is an experimental approach to fund some of the the development I want to do around Apache Flex. At the time of this writing, the project has reached over 10% of it's goal. There are a bunch of cool rewards including T-shirts, Flex Show content, and personal mentoring time with me. If you're interested in Flex, and how it is going to thrive under Apache, check out, and fund the Flextras AutoComplete Kickstarter.

Quit My Job: Twelve Years Later

While randomly surfing the Internet, I came across a blog post entitled, Quit My Job for Consulting: Two Months Later and it made me smile. It was late September in 1999 that I left my full time job. That led to the formation of DotComIt; and I am entering into my thirteenth year of being on my own. Steve Klein's post inspired me to share some of my thoughts on the experience; hopefully from a more experienced perspective.

I wrote up this post for the monthly Flextras newsletter and thought I'd repost it here.

How Do You Define Yourself?

A favorite game in my family is Scrabble. I have siblings scattered throughout the US and it is rare that the whole group of us end up in the same room together. Some of my fondest memories are sitting around the coffee table in my parent’s living room on Christmas playing Scrabble. The games can become lovingly cutthroat and it is rare I am on the winning end. My elder brother once pointed out to me that I lost because I always looked to create cool words, without devoting thought to the point value of said words. That sentiment has become a defining factor in my life and career. I often look for cool work even though they are not always the most profitable.

Part of the life outside of a traditional paycheck is to figure out what you want to do, and then figuring out to get a way for people to pay you to do it. (That’s probably not a bad approach even if you’re after a traditional paycheck, either). The process isn’t easy, though. I think the hardest part is figuring out what you want to do.

I am a Technical Entrepreneur! To me, that means I want to create products and services that use technology to solve problems. I get high on process automation and love it when I can do things to help make my clients more efficient and effective in their respective profession.

Over the years I’ve been given many different roles. I’ve been called a small business owner, a consultant, a contractor, a subject-matter expert, and someone who will shovel shit for money. The work associated with some of those labels isn’t always satisfying. I strongly suggest you take your own time to define your identity before someone else does it for you. Then search out clients—or employers--that fit the identity you want to create for yourself; and you’ll find projects that will make you happier and more productive.

Don’t Ignore the Business!

When you’re not employed by a company, then you’re running a business. It may not feel like, especially if a recruiter had placed you as a full time consultant working on-site with a client, but even then you’re still a business. I’ve seen a lot of great programmers start consulting, only to quickly go back to being full time workers at the first opportunity. I always got the impression that they do not treat their activities as running a business; and are shocked at the amount of time the “business stuff” is taking. This extra responsibility is one of the key tenants of Steve Klein’s post. In this newsletter, I’m going to share some of my thoughts on two areas of the Business stuff: including Finance and Marketing.

Let’s Talk about Money

You’ll have to be careful when it comes to money. You will have clients that don’t pay on time. You will have clients that don’t pay at all. I made a lot of money mistakes in the early days and eventually had to institute policies to address non-paying clients. When a client is late; I stop all work for that client immediately. That may sound simple and logical, but the programmer in me finds it hard. Incomplete tasks bug me. Stopping work in the middle of a task is like trying to stop a run while in mid-stride.

The client will often assure you there are no problems and the check is in the mail, but do you want to bank on that? I don’t recommend it. More often than not; the client interprets a 30 day payment term to mean that they can start processing your payment whenever they feel like it. It is not a happy feeling to discover that it’s time to invoice a client, and you haven’t received the previous payment yet. Did you just provide the client with a full month of time you'll never see a cent for? I have, and it’s an expensive lesson to learn.

Sometimes the client will not respond to a late payment inquiry. I know people get busy and have many priorities; but I figure three calls within the span of a week or two is a good way to follow up; and it gives them plenty of time to get back to you. The fourth follow up call never goes to the client; it goes to the lawyer. For some reason, clients seem to find time to respond to a lawyer, even if they don’t have time to respond to you.

Taxes can be another issue. In the US you want to be sure to put away 40% of your income (after expenses) for taxes. Yes, it really is that much. Because you don’t have an employer to take it out of every paycheck, you’ll probably have to pay quarterly taxes to the state and federal governments. If you work full time for a company, or used to, check out one of your pay stubs. You’ll find that roughly 30% of your pay is being taken right off the top before you ever see it. The employer is paying another 7.5% to social security. When you’re on your own, you have to pay that extra yourself. Sometimes it is a shocking realization, especially if you didn’t plan for it.

Beyond the income taxes, you may also have to deal with local sales tax on the services you provide and property taxes on your business property. The sales tax will most likely vary from state to state, so you’ll want to talk to an accountant knowledgeable about local laws.

What is Marketing?

When starting out, I never had an explicit marketing plan. My first clients were achieved by a little bit of networking and little bit of luck. If your plan is to wait until the phone rings, then you’ll probably have a lot of spare time. If you do nothing to actively search for the right clients, then you’ll often be stuck with the low-hanging fruit. I’ve found that these projects are neither profitable nor satisfying.

In the beginning, I was doing a lot of marketing work without realizing it. I was writing books, blog posts, and articles. I was presenting at conferences. Later I added podcasting to my repertoire, both with The Flex Show and the Flextras Friday Lunch. Project clients often have no way to judge your ability. When they can see your name in print, or as a conference speaker it gives them confidence in you. That confidence can help you land the project. It can lead to more opportunities, and sometimes higher rates.

I’ve often been troubled over my lack of a formal marketing plan. Over the years I’ve tried other marketing avenues including ads in the phone book, joining the local Chamber of Commerce, using Google Ads, and sponsoring conferences None of those things have paid off as much as the more grass roots elements, such as writing this newsletter has, though.

Be a Subject Matter Expert

One of the interesting points that Steve makes in his post is that you must become a “Full stack” developer. He is suggesting you must be able to do everything. My route has been the exact opposite. I have inadvertently marketed myself as a subject matter expert. In the earlier days it was as a ColdFusion developer. The past few years it has been as a Flex Developer. Being a subject matter expert brings lots of benefits.

  • People have already decided on the technology before contacting me. I’m rarely put in a position where I have to make a case for using one technology over the other.
  • People often assume if you have an expertise in one technology, you are also an expert in related technologies. In my earlier days, I was often hired because of my ColdFusion skill, but no one thought twice about having me do HTML/JavaScript development, database design, server setup, or whatever else needed to be done.
  • The more specialized you are, the easier it is to be found. This can lead to higher rates, longer commitments, and more freedom. If you look for a mobile developer, you’ll find thousands of people and it may be hard to choose one. If you look for an ActionScript Developer who specializes in Stage3D on iOS, then you’re going to find a smaller pool to choose from and it will be eaiser to find a suitable candidate .

Of course, being a specialist is not without its’ own limitations. Anyone looking for a Flash developer will never find the ColdFusion guy, for example. Often clients will segment you into what they hire you for and not to think to ask you for the other things which you can do perfectly fine. Being a specialist is a double sided sword. I assume the same is true for being a full stack generalist.

The Work-Life Balance

One of the challenges of being your own boss is that you can set your own hours and work when you want. It is up to you to enforce this balance. It is easy to have “five more minutes” turn into 6 hours only to find out you skipped dinner, missed seeing the sun today, and your significant other has been asleep for hours.

When I started out, I was budgeting 25-30% percent of my time for actual billable work. The rest of the time was for my business management; such as paying bills, bringing on new clients, negotiating contracts, and doing my marketing activities. This means, out of every four weeks, only one of them was billable. If I were to work 60 hours; it’d be a great month. If I were to work 80 hours; then I know next month will be devoid of billable work.

Remember it is okay to say no to projects. This is hard and not what the common logic says. You may be too busy. You may have other commitments; whether work related or not. You may not be interested in the work. I find it is always better to say no, then to say yes and the not deliver. Sometimes you may be able to negotiate deadlines and the schedule to accommodate your other commitments.

Every Sunday night I make a schedule for my week. This includes time for current clients, business stuff, social activities, and whatever else I want to do.  This makes me sure that every week I'm saving some time for the important aspects of my life, both within and outside of the business.  Getting a new project on my schedule often takes a few weeks; even after the contract is inked.

Final Thoughts

Overall, I recommend managing your career the same way that public companies manage their stock price. Make your commitments and stick to them. Public companies make their commitments in terms of revenues and profits. As a business owner, your commitments are probably around deliverables, timelines, and budgets. If you can, exceed expectations. Prepare your deliverables early. Come in under budget. Address issues head on, as they arise, and be prepared to offer a solution or two.

One thing I have come to learn is that there is no secret sauce to being a success in business. I've been lucky.  My best advice, is to figure out what you want to do and then find a way to make it happen.

In Defense of Flash - Revisited

I wrote this post for a Flextras newsletter. Before I get into details; I want to remind everyone that they should check out 360|Min coming this October. It is an unconference style event in Las Vegas by the folks who put on 360|Flex. It should be lots of fun and educational on stuff happening now.

Back in November, I wrote a newsletter entitled In Defense of Flash. There was a lot of client confusion about the future of the Flash Platform; and they were worried that all their apps would suddenly stop working; or that their investment in the platform would turn out to be a significant waste of time and money. My original post spoke about a lot of specific issues; but at the time some things were unknown. I thought it was time to revisit that post and see where things stand, 10 months later.

Flash Player on Android

The ball that started the “Flash is Dead” bandwagon rolling was that Adobe announced it would cease development on Flash Player for Android devices. This made sense to a lot of people. Although, it was nice to have a Flash Player in mobile browsers; no one was building browser based Flash Applications with mobile devices as the target. The fact that the iOS browser did not support Flash in any way decreases the ubiquity that the platform used to offer on desktop devices.

With the release of Android 4.1, Jelly Bean, Adobe has removed the Flash Player from the Android store.
There will be no certified implementations of Flash Player for Android 4.1

Beginning August 15th we will use the configuration settings in the Google Play Store to limit continued access to Flash Player updates to only those devices that have Flash Player already installed.
Source

Although, this is sad to see; it is not a surprise. It is interesting to note that a few days after the app was pulled, the BBC pressured Adobe to return the app to the Android UK store; as they do not have another technology solution in place for browser based streaming on mobile devices, yet:
Adobe's mobile Flash Player has returned to the Google Play store in the UK. According to BBC News, Flash's encore is the result of pressure from the BBC and "strategic partners" that rely on Flash for their Android apps
Source

It’s weird that an app with over 500,000 ratings, and a 4.5 star average could be considered a failure. Most of us independent developers can only dream of having that many people try out something we built. 

Despite the news about Flash Player, I still believe that Adobe AIR, especially with captive runtime, is still a fantastic choice for building cross platform native mobile applications.

Long Live Apache Flex


In the original post, I spoke about Flex and how Adobe planned to donate Flex to the Apache foundation. At the time, details were very sketchy. We have plenty more information now. Adobe has successfully donated Flex to the Apache Foundation. They have contributed the Adobe Flex 4.6 code base, a testing framework named Mustella, and the Text Layout Framework used in many Spark controls.

In a few weeks, Adobe is expected to donate a new ActionScript compiler, named Falcon. The Falcon compiler will be included in Flash Builder 4.7; which was recently released on Adobe Labs. But we’ll have the code, and hope to get it integrated with Flex in the future.

In addition to the Adobe donations, there is a lot of new code and bug fixes done by the community. The Apache Flex team has released Apache Flex 4.8. I wrote about building Apache Flex 4.8 from the source last month.

Since an Apache release must be source only; they have also put together an installer Application which will allow you to easily prep Apache Flex for use in Flash builder. Flex has a lot of dependencies, such as the AIR SDK and BlazeDS, which Apache cannot distribute due to licensing terms. This installer takes care of that downloading and setup for you.

Flash Player on Windows 8


Another pressing issue is the Flash Platform support on Windows 8. As I stated in my original post, the “Windows 8 UI”—previously Metro—browser will not support plugins. This affects all plugins including Silverlight and Flash. However, Microsoft and Adobe have worked together in order to support Flash in the metro style browsing. Flash Player will be included as part of the browser.

I’m going to quote the Flash Platform runtime whitepaper, as the source here:
Flash Player release and debug players will be available and supported for Windows 8 Desktop and Metro style experiences on both x86/64 and ARM platforms.
This was a happy surprise to many in the developer community, including myself. Flash Player will be supported on all variants of Windows 8. We’re still waiting for the formal notice that Adobe AIR will be supported on Windows 8; but for the moment we have to believe the Flash Platform Whitepaper:
Adobe is committed to adding both Windows 8 Desktop and Metro as supported platforms for Adobe AIR.
I’m looking forward to converting Igor Knots, my mobile game, to a Windows 8 experience with Adobe AIR.

Final Thoughts


Two years ago, when a client approached me about building an application with Flex and Flash, I think we made the right decision.  Ten months ago, when we decided not to abandon our project, or rebuild it in a different technology, I think we made the right decision.  Today, if I were to start a new project, there are very specific questions I’d ask about the user base. 

Does your app have to run in a mobile browser?  If so; then don’t use Flash!  However, if your target is multiple desktop browsers spread across multiple operating systems in your Enterprise; then Flash can suit your needs.  

Do you want to run on multiple platforms?  If so, then AIR allows you to deploy your app to Mac and Windows desktops; and as Native Android or iOS Application.  AIR can help your app run on a multitude of devices and desktops.  It may be a good choice.

More Entries

All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.