When Startups Fail (or Why Transparency is Paramount to Success)

One of the key tenets of both leadership and personal integrity is conducting one’s affairs from a position of honesty. Honesty, however, carries many ranging and individualized interpretations, and so perhaps transparency is a term better suited to driving this discussion. When leaders aren’t transparent and fail to include, inform, or advise their teammates of both the good and the bad, disaster is imminent. Withholding information from your team – or worse: from yourself (by ignoring reality) – handicaps your position from the very start because problems are infinitely easier to solve by group effort. That is, new ideas originate, face criticism, and evolve into eventual vetted solutions that wouldn’t have developed otherwise. This, presumably, is why most organizations hire not just those with the most talent, but also those who see the bigger picture – aren’t afraid of taking a different route to get there.

I recently found myself in a position wherein a seemingly positive startup environment suddenly turned wholly toxic. This toxicity had been brewing long before it surfaced; that incubation period represents an extremely unfortunate failure of leadership. Rather than bringing fellow teammates in to brainstorm, the co-founders in question decided to hide the fact that they had long since run out of funding and couldn’t pay to keep the team going. Moreover, one of these “leaders” was quietly attempting to oust the other. To their credit, the team worked hard and churned out a quality product – but we had no idea that our families, livelihoods, and careers were on the brink of debt-laden disaster. To those in the know, cash flow issues are no rare occurrence in the startup world. But there’s a massive difference in knowing that an issue exists ahead of time and finding out not only that your previous invoices might not ever be paid, but also you probably won’t be earning another dime any time soon. (As an aside, this is also a great example of why you should have an emergency fund). Continuing to work for equity in such an environment is a fools game: any remote chance of future success would be in spite of – as opposed to because of – chosen leadership direction.

Being a good leader means doing the right thing and empowering others to be greater than they currently are or greater than they think they can become – even if that means you don’t get what’s best for you in the end. Strong leaders guide teams through times of crises and get out in front of potential roadblocks; they take and deflect blows from reaching their followers. Likewise, teams who both believe in and trust their leaders work together to drive through hardship and don’t run in times of trouble. While I view the entire situation above all else as wholly disappointing, it has proven to be an incredible, priceless, and life-changing learning experience. Additionally, like most endings, better beginnings have sprouted from the ashes, and I’m very humbled, mindful, and thankful for that.

Positional Leaders

I’m currently reading John C. Maxwell’s “The 5 Levels of Leadership” in which he outlines, well, the 5 different levels of leadership achievement he’s encountered in his lifetime. John intuitively argues that the higher the level of leadership exhibited by members of an organization – be it business, social, or otherwise – the higher the chance of not only achieving organizational success, but also improving quality of life for everyone involved. The lowest level of leadership is derived solely from position or title, and the highest level is reserved for those who empower others to become leaders. Check out the book to get all the details in between (it’s a quick read).

I’d just finished the chapters detailing the Level 1 leader when I experienced a wave of repressed memories from past jobs. During the period of time in my life when I dropped out of school, did some serious soul-searching, and eventually worked my way into and through community college, I worked a variety of jobs in the service industry. While there are certainly exceptions, the majority of the companies I worked for exhibited the same negative symptoms – extremely high turnover rates, low morale (no one was excited to come to work), “clock-watching”, and few opportunities for advancement. Those who did move up the ladder – managers, bartenders, certified trainers – clung to their positions of (perceived) power as though they were scared they might lose it. Instead of encouraging, helping, and developing others, these Level 1 leaders intimidated,  obstructed, and distanced themselves from their teammates. These types are more interested in pulling rank and enforcing rules than including others in process improvement or serving those they were tasked to lead. However, these awful traits pale in comparison to the Level 1 leader’s worst characteristic – they fear being usurped by other up and coming potential leaders so much that they actively work to keep others down, thus dragging the performance of entire organizations down to their level of mediocrity.

Many of the companies I worked for many years ago – and certainly myriad others – succeeded in spite of themselves as demand for their respective services or products boomed. But many others failed. Moreover, these organizations deprived themselves and their employees of an opportunity to coalesce into something greater and making a real difference in their communities and the world. In contrast, companies that exhibit and encourage strong leadership foster work environments in which employees are excited and passionate, where innovation is embraced, and where new generations of leaders are groomed. In short, organizations that rely on Level 1 leaders will never reach their full potential.

Do you know any Level 1 leaders? Are you yourself a Level 1 leader in life or work? Strive to take your game – and other’s games – to the next level by working to support those around you, eliminating (as opposed to introducing) obstacles impeding others, and encouraging teammates to follow you because of who you are – not because of your title.

You talk the talk – but are you walking the walk?

If you don’t have integrity, you have nothing. You can’t buy it. You can have all the money in the world, but if you are not a moral and ethical person, you really have nothing – Henry Kravis

In light of the recent unveiling of a former colleague’s less-than-moral behavior, I first felt disappointment, then anger, and finally a tinge of sadness. But after these initial reactionary emotions subsided, I had time to think things through a bit more proactively and decided to point the examining lens inward on myself.

Am I really the person I want and present myself to be all of the time? Am I merely paying lip-service to supporting some of the causes I proclaim to care most about? How can I take actionable steps to bridge these gaps, however small or large? What can I do to actually make a positive difference? Instead of merely condemning others’ shortcomings, the massively difficult habit of (honest) introspection stands to offer the most return value for our efforts.

We all have room for improvement – the hard part is identifying what those things are, specifically. Pointing the mirror at oneself is a great starting point.

 

The Power of Positive Thinking

A pessimist sees the difficulty in every opportunity; an optimist sees the opportunity in every difficulty – Winston Churchill

Several months ago, I made a decision to consciously approach challenges in life from a perspective of optimism. As opposed to immediately focusing on the negative aspects of a particular situation, event, or obstacle, I would opt to instead identify opportunities and positive outcomes first. This isn’t to say I delude myself into ignoring the existence of the negatives – identifying potential pitfalls is essential to crafting effective solutions and avoiding repeating the mistake – just that I first consider the positives. The benefits of having done so have been overwhelming: challenges no longer appear insurmountable, deviations from “the plan” are tolerable, and once closed doors are now wide open. Most importantly, I’ve both enabled and rapidly accelerated my personal feedback loop, learning from lessons I might have otherwise stubbornly avoided.

Instead of thinking “I have nothing in common with ____” I think “what can I learn from our differences or what can I teach them?“. Instead of “this meeting is a waste of time” I think “certainly I can take one lesson from this or identify one thing I might have otherwise overlooked“. “This is a chance to double-down on my efforts and move forward” instead of “I’ve screwed this up so badly I’ll never recover”. “I can” instead of “I’m not good enough”. You get the idea.

The key to this strategy is a willingness to admit fault; check your pride and ego at the door. Every misstep represents a learning opportunity, and without admitting you screwed up or your idea didn’t work you can’t possibly learn, grow, and better prepare for the next challenge. Viewing setbacks as opportunities for a fresh start (armed with new information) both prevents wasting time by dwelling on the mistake and helps to focus your full attention on either the next task or a re-attempt of the previous. If you find your negative thoughts and doubts materializing into reality, perhaps you too can benefit from a shift in perspective towards the optimistic.

Automated packaging, building, and deployment script for iOS/Android Sencha Touch + Phonegap apps

If you use Sencha Touch + Phonegap to develop apps for multiple platforms, you’ve likely run into the issue of how to manage OS-specific files and build components. For example, I use very different SASS stylesheets for iOS compared to Android, and certainly don’t wish to include unnecessary elements in the final Phonegap packaging for either platform. Of course there’s also the matter of separate OS-specific cordova.js files. Additionally, the steps of packaging the app with Sencha Cmd, then copying the output twice to both my Android and iOS native app’s www/ folder proved quite tedious. Lastly, If you’re using the “freemium” business model and maintain both free and paid versions of your app, the previous step is doubled. As such, I created a quick-and-dirty Python script to automate the build task in it’s entirety, which I’ve copied below.

I keep a common app.json & a _base.scss with shared elements in my Sencha Touch app directory. During each build executed by the script, the appropriate files for each OS are combined with the base files and output to the final native project directory (in a separate project location). After completion, a .SUCCESS or .ERROR file is created to indicate build success or any errors encountered in the event of failure.

If you use this script, be sure to change the directories to reflect that of your own project setups. Save the script as whatever_you_want.py in your Sencha app directory, and simply execute the script. The script is currently configured for iOS and Android, but can easily be extended to incorporate any Sencha/Phonegap supported OS.

custom_js_packager.py

import os, shutil, datetime
from subprocess import call

baseDir =  r"C:\Users\Brandon\Development\git"
senchaDir = baseDir + r"\caffeine\src\main\webapp\mobile"
senchaPackageDir = senchaDir + r"\build\mobile\package"
senchaSASSDir = senchaDir + r"\resources\sass" 

androidAppJSON = senchaDir + r"\app-android.json"
iosAppJSON = senchaDir + r"\app-ios.json"
appJSON = senchaDir + r"\app.json"

androidSCSS = senchaSASSDir + r"\_android.scss"
iosSCSS = senchaSASSDir + r"\_ios.scss"
appSCSS = senchaSASSDir + r"\app.scss"

androidProjectBaseDir = baseDir + r"\caffeine-android"
androidCaffeineDir = androidProjectBaseDir + r"\com.hawkinbj.CaffeinePro.Caffeine"
androidCaffeineProDir = androidProjectBaseDir + r"\com.hawkinbj.Caffeine.Caffeine"
androidWWWDir = r"\assets\www"

iosProjectBaseDir = baseDir + r"\caffeine-ios"
iosCaffeineDir = iosProjectBaseDir + r"\caffeine-ios"
iosCaffeineProDir = iosProjectBaseDir + r"\caffeine-ios-pro"
iosWWWDir = r"\www"

SUCCESS_EXT = ".SUCCESS"
ERROR_FILENAME = "error.ERROR"

def run():
    do_android()
    do_ios()

    print "done!"

def base_do(jsonFileName, scssFileName):
    remove_previous_info_files(jsonFileName)
    clean_package_dir()
    prepare_json(jsonFileName)
    prepare_scss(scssFileName)
    sencha_package()
    create_success_file(jsonFileName)

def do_android():
    print "doing android"
    base_do(androidAppJSON, androidSCSS)
    update_android_www()
    print "finished android"

def do_ios():
    print "doing ios"
    base_do(iosAppJSON, iosSCSS)
    update_ios_www()
    print "finished ios"

def remove_previous_info_files(osName):
	delete_success_file(osName)
	delete_error_file()

def delete_success_file(osName):
    try:
        os.remove(osName + SUCCESS_EXT)
    except:
        pass

def delete_error_file():
    try:
        os.remove(ERROR_FILENAME)
    except:
        pass

def create_success_file(fileName):
    create_and_write_file(fileName + SUCCESS_EXT, "success")

def create_error_file(errorMsg):
    create_and_write_file(ERROR_FILENAME, errorMsg)

def create_and_write_file(fileName, text):
    file = open(os.path.join(senchaDir, fileName), 'w+')
    if text:	
        file.write(str(datetime.datetime.now()) + " " + text)
    file.close()

def prepare_json(fileName):
    errorMsg = "OS-specific app.json files are missing!"

    if os.path.exists(fileName):
        copy_file(fileName, appJSON)
    else:
        create_error_file(errorMsg)
        raise Exception(errorMsg)

def prepare_scss(fileName):
    errorMsg = "OS-specific app.scss files are missing!"

    if os.path.exists(fileName):
        copy_file(fileName, appSCSS)
    else:
        create_error_file(errorMsg)
        raise Exception(errorMsg)

def copy_file(src, dest):
    shutil.copyfile(src, dest)

def copy_tree(src, dest):
    try:
        shutil.copytree(src, dest, symlinks=False)
    except:
        pass

def remove_tree(path):
    shutil.rmtree(path, ignore_errors=True)

def sencha_package():
    call("sencha app build package", cwd=senchaDir)

def update_android_www():
    proAssets = androidCaffeineProDir + androidWWWDir
    regAssets = androidCaffeineDir + androidWWWDir

    base_update_www(proAssets)
    base_update_www(regAssets)

def base_update_www(path):
    remove_tree(path)
    copy_tree(senchaPackageDir, path) 

def update_ios_www():
    proAssets = iosCaffeineProDir + iosWWWDir
    regAssets = iosCaffeineDir + iosWWWDir

    base_update_www(proAssets)
    base_update_www(regAssets)

def clean_package_dir():
    remove_tree(senchaPackageDir)

run()

if you have any questions, leave a comment and I’ll get back to you. Hopefully others find this useful or are inspired to roll their own solution. Cheers!

Requirements are Sencha Cmd (environment variable must be set) and Python.

How to Access Resource Files in Packaged Spring + Maven Project (WAR/JAR)

Maven is quite clear about both expected resource directory structure and the resulting directory in which they’ll appear after deployment:

“The default resource directory for all Maven projects is src/main/resources which will end up in target/classes and in WEB-INF/classes in the WAR. The directory structure will be preserved in the process.”

What’s not so clear, however, is that these resources are in fact added to the root classpath relative to the WAR/JAR. What’s still less clear is the proper way of accessing these dynamic resources – both for testing and in source code – as the directory path changes upon deployment. If your resources are external references, the task is trivial with the help of Java’s getClass().getResources(), which returns an URL. Unfortunately, if your resource file name contains spaces, the resulting url will include “%20” characters in their stead. You could parse this resulting string and replace infringing characters, but why re-invent the wheel?  Spring provides a fantastic utility – ResourceUtils – that allows for a more elegant solution:

 

private static final String MY_RESOURCE_FILENAME = "test.txt";

File myResourceAsFile = ResourceUtils.getFile(getClass().getResource(MY_RESOURCE_FILENAME));

 

 

Implement iAd Banner Ads without Covering UIWebView in Phonegap

Image

Recently, I was interested in adding ads – specifically iAds – to a Phonegap-wrapped iOS application. There are several tutorials out there, Scott DeSapio’s being far and away the best, however myself and a few others ran into a confounding problem:

Phonegap applications are (essentially) composed of a single view, thus subviews (like a banner ad) lay right on top of actual app content.

Not good. Another user managed to give the banner ads a separate space below the webview, but then click events on the ad were lost. After quite a bit of trial and error, I’ve come up with a solution. If you’re starting from scratch, I recommend following the link above to Scott’s blog and coming back when you’re ready to clean up.

This solution hinges on implementing the ADBannerViewDelegateProtocolReference. Full documentation can be found here.

This gives us access to several useful event methods, though the one we’re most concerned with is bannerViewDidLoadAd – which will be our cue to resize the webview.

First, you need to further modify MainViewController.h MainViewController interface by adding <ADBannerViewDelegate>:

@interface MainViewController : CDVViewController <ADBannerViewDelegate> 
{
    ADBannerView *adView;
}
@end

Now you need to implement this interface in MainViewController.m. Add this line in your webViewDidFinishLoad method:

adView.delegate = self;

I also added this line to hide the banner space until an ad is actually received and loaded, but it’s completely optional:

adView.hidden = YES;

Next, declare these two (new) methods. The first lets us know that an ad was received successfully and that we should both resize the webiew and show the ad banner. The second method – didFailToReceiveAdWithError – hides the ad banner and resizes the webview if somethings goes wrong or the ad clears from view. As a bonus, this solves any complaints xCode might spew in relation to the proper handling of ad-receive failures. The bringSubviewToFront:adView line is the linchpin here, allowing banner ad click events to bubble up to the main view controller. The complete implementation is as follows :

- (void)bannerViewDidLoadAd:(ADBannerView *)banner 
{
    CGRect resizedWebView = [super webView].frame;
    resizedWebView.size.height = adView.frame.origin.y;
    [super webView].frame = resizedWebView;
    [self.view bringSubviewToFront:adView];
    adView.hidden = NO;
 } 

- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
 {
     CGRect resizedWebView = [super webView].frame;
     resizedWebView.size.height = self.view.frame.size.height;
     [super webView].frame = resizedWebView;
    adView.hidden = YES;
 }