I have been programming computers professionally for over 25 years.
I have over 20,000 hours of experience creating applications for the iPhone and iPad. Over the last 5 years, I have also worked professionally creating Node.js web services and building and maintaining cloud infrastructure in AWS.
My consulting career spans more than 30 successful engagements for 22 Fortune 500 clients. I have created many successful software products. I have worked an average of 3,500 hours annually since 2000.
With solid experience in the dual roles of developer and DevOps engineer, I am able to offer holistic solutions which result in scalable and highly-available products and services.
I have expert-level knowledge and experience with Objective-C, Swift, Node.js, Python, CloudFormation, and Terraform. I have strong experience with many other skills and tools.
I have delivered over 300 applications to the iOS App Store. Five of my applications were available in the App Store when it opened in July 2008. One of my apps - AccelaStudy - has over 12 million downloads and almost 200,000 active cloud users. AccelaStudy was featured in an Apple television commerical in China (at 0:04). My application iPhraseBook was selected by Apple as iPad App of the Week.
Years ago, one of the Windows products I created - UDC Care - was a featured case study in Paradox Informant magazine.
I have a Bachelor of Science degree in Computer Science from DePaul University.
Over my long career, I’ve acquired experience and certifications in many “legacy” technologies.
I prefer Swift over Objective-C. I recently converted AccelaStudy and associated internal frameworks from Objective-C to Swift, about 30,000 lines of code. The new Swift code is easier to extend and debug; I’m glad I ported it over. It takes forever to compile, though.
Swift’s guard statements are the new assertion and I use them all over the place. I love Swift’s support of map and reduce. I miss C# async and await so I use then which combines promises with async/await.
I am aware of the Swift Evolution proposal for native Swift support of async and await. That the proposal is written by Lattner himself gives me high hopes that it will be a part of Swift in the near future.
I prefer SQLite databases for persistent storage in iOS apps. I never use CoreData but have some affection for Realm. I use GRDB for SQLite access. I use KiteKit with Kite Compositor or Lottie from Airbnb for creating complex animation sequences. I use RazzleDazzle from IFTTT for full-screen animated intros. The socket.io client and Starscream work well for socket programming. I use CleanroomLogger for logging.
I use SwiftLint to clean up my Swift source code. I like source code files to all adhere to the same coding conventions. I haven’t published my own coding conventions but they pretty much look like this.
I primarily do my work in Xcode but often switch over to AppCode from Jetbrains. AppCode’s plugin architecture allows linting to be done in realtime and features like highlighting code issues such as “unused import” are very helpful.
While I am not a hardcore Test-Driven Development afficionado, I do write a lot of unit and integration tests and do so in Xcode for iOS apps. I use Xcode’s built-in code coverage tool to measure code coverage. I always have at least 70% code coverage and strive for 100% coverage, though this is a challenge. I try to write my code using Dependency Injection and other similar design patterns to enable high code coverage using mocks and fakes. I’ll give a shout out to Michael Primeaux for making me a believer in automated testing.
I aggressively update any open source code that I use. Having a lot of automated tests and a high code coverage gives me the “safety net” in which to do this. I try to keep up with the latest version of Swift but refuse to adopt the latest version of iOS until a month or so before the shipping version is released. On the “bleeding edge” I’ve spent more time debugging Apple’s defects than resolving my own.
I’ve used Fabric (previously Crashlytics) and HockeyApp for crash reporting. Since Microsoft bought HockeyApp and made it free for all applications, I now use it exclusively. I’ve used mixpanel and Amplitude for application analytics but now directly use AWS services (Kinesis and Athena).
I keep all source code under Git for version control. I use GitHub for personal projects and AWS CodeCommit for Renkara projects. I’ve used Visual SourceSafe, Team Foundation Server, and Subversion in the past but Git is easily the best choice now. I tend to follow GitFlow for managing branches. While I sometimes use the command line, I more often use SourceTree, Tower, or GitHub’s desktop client for managing Git repos.
I use TextExpander to store snippets of code which I insert with a simple keybinding. Most of my Swift keybindings start with the letter x. For example,
xtable pastes in an entire UIViewController implementation with a UITableView and UITableViewDataSource and UITableViewDelegate extensions.
I have some talent as a graphics designer and use a combination of Adobe Illustrator and Photoshop to create screen mockups, icons, and other app-related artwork. I have been an Adobe Creative Cloud subscriber since it became available. I use Asset Catalog Creator Pro to quickly turn icon source artwork into the various icon sizes required by the App Store.
I create app demos and other animations using Adobe After Effects.
I use bunyan for logging and use bunyan-cloudwatch when running in AWS to log events to CloudWatch directly. I use the AWS SDK for Node.js to connect to various AWS services like SQS. All of my Node.js web services or microservices use MySQL as a backend database.
I use web sockets heavily for facilitating real-time data synchronization. socket.io has worked well for this in Node.js. To ensure messages are broadcast to clients across all instances, socket.io-redis is used.
As with iOS code, I write a lot of unit and integration tests for my Node.js web services. I use a combination of mocha and chai for writing tests and istanbul for code coverage. Again, this gives me the ability to safely update package dependencies more aggressively than would otherwise be possible.
In addition to normal web services, I also use Node.js to write microservices which run in AWS Lambda and are fronted by API Gateway. If I can, I use Swagger to document the API and to autogenerate the endpoints.
I used to use SendWithUs to create email templates, merge them, and send them out using SendGrid. I’ve since replaced all of the SendWithUs functionality with SQS and Lambda. SendGrid’s Event Webhook sends email-related events back to the web service so their events can be aggregated with other application and service events.
I’ve used a similar architecture to deliver several Alexa skills.
I used to write everything in CloudFormation but now write everything I can in Terraform. The original reason was to have templates which allow provisioning resources other than just AWS, i.e. Azure, Google Cloud, Akamai. However, I have never really needed anything outside of what AWS provides but continue to use Terraform because I like the template syntax better and I find its variables and modularization easier to work with (as opposed to CloudFormation’s nested stacks).
I write both CloudFormation and Terraform templates in WebStorm because WebStorm has built-in support for YAML and a Terraform plugin which provides syntax highlighting and other goodies. I can also set up a WebStorm configuration which runs
terraform apply on the current template with a keybinding.
I am also a proponent of Immutable Servers where compute instances / servers / containers are deployed once and, essentially, never patched or updated, avoiding Configuration Drift. Rather than apply a patch, new instances are deployed, traffic gradually moved to the new instances, and the old instances terminated. I have done Green/Blue deployments using either load balancers or a Weighted Round-Robin routing policy with Route 53 DNS to gradually move traffic. CodeDeploy has also recently gotten built-in support for Green/Blue deployments and I am actively exploring that option.
With Immutable Servers, I don’t make a lot of use of Chef, Puppet, or Ansible. I don’t care for Chef and Ansible because they are procedural vs. declarative and I don’t like Puppet because advanced tasks require writing Ruby code. And, for the most part, I don’t like any of them because they default to a client/server architecture which actually just adds more infrastructure that needs to be managed.
Instead, I’ve become a huge fan of containerization with Docker being my primary solution. I combine Docker with Hashicorp’s Packer to create Amazon Machine Images (AMIs) which are, currently, the final artifact deployed to production.
I’m looking into using AWS Elastic Container Service or AWS Elastic Kubernetes Service to manage elasticity of container clusters in production. Containers are the future and managed elasticity is the way to go. The new AWS Fargate also provides some interesting new capabilities.
Sandbox, development, and QA environments use very small MySQL instances in RDS or local instances of MySQL. Production uses a highly-available Aurora cluster spread across multiple Availability Zones (AZs). I used to use DynamoDB for writing events and triggering Lambda functions but found Aurora to be more cost-effective in production and Aurora now also has the ability to trigger Lambda functions. I’m not the only one to notice how cost-effective Aurora is.
I’m also comfortable setting up a Continuous Integration / Continuous Deployment (CI/CD) workflow with Jenkins, CircleCI, or CodeBuild using GitHub or CodeCommit triggers. AWS CodePipeline pulls the code from CodeCommit and invokes AWS CodeBuild to build the app, run tests, and integrate with Packer to create an AMI. CodeDeploy can then apply a CloudFormation or Terraform template to spin up an EC2 instance with the AMI.
I make liberal use of CloudWatch alarms along with SNS notifications to monitor for problems in production. I’ve recently been introduced to New Relic and am finding it very helpful analyzing metrics and identifying problematic areas.
Logging is always a challenge in production environments. CloudWatch logs do the job for the most part but I’ve started working with 3rd party tools like PaperTrail for real-time offsite logging and Logstash and Elasticsearch for log analysis.
I’ve worked with VictorOps to manage on-call schedules and integrate with other services like Slack. I’ve tinkered a bit with it’s transmogrification feature to make AWS alarms more readable and actionable.
I use CloudTrail to track user activity and API calls within the environment. It also comes in handy when you need to roll something back to a previous value that no one wrote down before changing it.
I proactively monitor and analyze costs with Cost Explorer to find opportunities to reduce AWS expenses. I use spot instances whenever possible for batch jobs, CI/CD, and other intermittent activities.