Customizing UIWebView for PDFs in Swift

UIWebViews are a handy way to show web content in an iOS app. They are especially useful for showing PDFs that are stored remotely. Apple largely treats UIWebViews like a black box: Documentation warns that they should not be subclassed. So what if you want to customize how they show PDFs? Recently, I went after two customizations to change the default UIWebView behavior.

  1. Scale the PDF so the entire thing fills the view–whether or not it is a landscape or portrait PDF.
  2. Get rid of the default drop shadow around the PDF.

They both required some tinkering, so I’m sharing them in case others need to do something similar.

Customizing How the PDF is Scaled

Default behavior

There’s a property on the UIWebView called scalesPageToFit. If you set it to true, the PDF will start off scaled so that its width fills the width of the view. You can set it to true in your code or in the UIBuilder. And right out of the box, you get pinch and zoom. It’s great!

Desired behavior

Well, it’s great until you have a tall and skinny PDF and you want the whole PDF to show up when the user gets to that view. In other UIViews, you can set the contentMode property to AspectToFit to do this. However, the UIWebView actually has a couple of layers in the view hierarchy between it and the PDF we’re scaling.


After a lot of poking around in the subviews of my UIWebView, UIBuilder, and StackOverflow, I ended up writing a little function to scale the PDF so that the whole PDF is visible if it’s too tall and skinny to fit with the scalePageToFit default zoom. Here it is:

func updateZoomToAspectToFit(webView: UIWebView) {
        let contentSize: CGSize = webView.scrollView.contentSize //PDF size
        let viewSize:CGSize = webView.bounds.size
        let extraLength = contentSize.height - viewSize.height
        let extraWidth = contentSize.width - viewSize.width
        let shouldScaleToFitHeight = extraLength > extraWidth
        let zoomRangeFactor:CGFloat = 4
        if shouldScaleToFitHeight {
            let ratio:CGFloat = (viewSize.height / contentSize.height)
            webView.scrollView.minimumZoomScale = ratio / zoomRangeFactor
            webView.scrollView.maximumZoomScale = ratio * zoomRangeFactor
            webView.scrollView.zoomScale = ratio

All this does is check if the view is more overly-tall than overly-wide compared to the view’s content size. If it’s overly-wide, we don’t have to do anything because the scalePageToFit property magically takes care of that situation. If it’s overly-tall, we find the ratio of the view’s height to the content (a.k.a. the PDF I care about). That ratio is then assigned to the zoomScale. That zoomRangeFactor is a magic number that you can play around with. It needs to be greater than one to allow the user to pinch and zoom.

For this to work, updateZoomToAspectToFit needs to be called from the webViewDidFinishLoad(webView: UIWebView) callback. For webViewDidFinishLoad to be called, the UIWebView needs to be its own delegate: myWebView.delegate = self

Hiding the Drop Shadow

Default behavior

I was surprised to see that there was a drop shadow around the PDF in the UIWebView out of the box.

Desired behavior

The designer I was working with was not only surprised, but displeased. So my mission was to get rid of the drop shadow. I tinkered in UIBuilder to no avail. I dissected the view hierarchy in debug mode. StackOverflow suggestions were full of code that goes below Apple’s documentation and could break with the tiniest update.


Long story short, I found that I could legally (according to Apple’s documentation) traverse the subviews of the UIWebView and set the shadowOpacity attribute on all of them:

func removeShadow(webView: UIWebView) {
    for subview:UIView in webView.scrollView.subviews {
        subview.layer.shadowOpacity = 0
        for subsubview in subview.subviews {
            subsubview.layer.shadowOpacity = 0

Like updateZoomToAspectToFit, in order for this to work, removeShadow must be called from the webViewDidFinishLoad(webView: UIWebView) callback. That’s because the subviews won’t be available until after the PDF has loaded. For webViewDidFinishLoad to be called, the UIWebView needs to be its own delegate: myWebView.delegate = self.

The Bigger Picture

Figuring these two customizations improved my fluency with iOS’s UIKit. I enjoyed the challenge of figuring out how to go just underneath the hood but not hack it so badly that it becomes fragile and susceptible to silently break in updates. This is what I love about making software at Atomic–we can take the time to do things right, and share when we figure out how to accomplish something.

The post Customizing UIWebView for PDFs in Swift appeared first on Atomic Spin.

Handling Bad Feelings at Work

Atomic Object employs a group of smart, high-performing, passionate, diverse, and flawed human beings. It’s inevitable that each of us will occasionally experience “bad feelings” at work. As a company, we’ve put a lot thought into how to handle the bad feelings that occasionally arise during our time at work. One of the steps we’ve taken is extending the acronym FUD to “FUDA” as a shorthand for bad feelings and a prescription for how to handle them.

Handling FUDA at work

In this post, I’ll share some of our thoughts on FUDA, how we work to resolve it when it comes up, and my perspective on it as a managing partner at Atomic.

What is FUDA?

FUDA is an acronym that stands for fear, uncertainty, doubt, and anger. The term itself is nothing too innovative–we just added “anger” to FUD. Nor are the feelings different from what I’ve experienced working for other companies in my career. What’s different is how we talk about what FUDA means, and how we, as individuals and as a company, are expected to handle it.

At Atomic, individuals have a lot of control over projects and our work environment. However, each letter in FUDA rears its head from time to time:

  • Fear: “The economy is crashing. Will AO go out of business?”
  • Uncertainty: “I’m starting on a new project and I have no idea what’s going on! What are we doing here?!”
  • Doubt: “I don’t think my colleague is pulling his/her own weight.”
  • Anger: “The new [company policy] is some unfair bullshit!”

Hard feelings. They can quickly turn an office into a toxic work environment if not resolved.

At Atomic, we believe:

  1. It is OK, and even expected occasionally, for Atoms to be in a state of FUDA with respect to work.
  2. It is not OK to remain passively in a state of FUDA.
  3. Atoms should offer to help resolve a colleague’s FUDA when they observe it.

Whose responsibility is it to clear FUDA?

In a word, everyone’s. We expect Atoms who are feeling FUDA to actively seek help from a person in a position to help. Depending on the situation, that person is often not a manager, but another fellow Atom who has experienced a similar situation and can offer support.

We expect those who observe others having FUDA to speak up about it. As a company made up of people who care about each other, we all need to look out for these situations and lend a hand.

How does handling FUDA reflect our values?

Atomic Object has six core values. Three of the values speak directly to how we handle FUDA: Own It, Give a Shit, and Teach and Learn.

Own It: The individual who is feeling FUDA should own his or her problem and take active steps to clear it. It’s one reason we require all our employees to read Crucial Conversations when they join Atomic–the book describes tools that are incredibly useful in the hard (crucial) conversations that come up when clearing FUDA.

Give a Shit: We expect Atoms to watch for signs of someone struggling with FUDA and proactively reach out, taking steps to resolve it. Long-term, unresolved FUDA has a corrosive effect on culture and workplace environment.

Teach and Learn: Probably the most common scenario is run-of-the-mill uncertainty and the need to get advice from someone more experienced in the company. I feel very fortunate that I work at a company where asking for help is welcome, and I am surrounded by so many bright, experienced people.

More recently, we have focused on adding additional support to project teams and individuals by creating Senior Strategist and Delivery Lead (Jason, Matt, and Brittany) roles within the company. We also offer access to an anonymous, external employee assistance program as a benefit to our employees.

My Perspective as a Manager

We sometimes joke (tongue-in-cheek) that we are “good managers of self-managing people.” However, there is some truth to that statement–it’s reinforced by the responsibility we expect and the empowerment we give to individual Atoms when it comes to handling FUDA.

We believe unresolvable FUDA is almost always due to an irreconcilable mismatch of values or goals. In such cases, we strive to avoid “right/wrong” judgments and move forward with integrity and honesty to pursue separate paths.

As a manager, I have found empathy to be an important part of dealing with FUDA, especially when helping people who come to me with problems. In these situations, empathy cuts both ways. It can be hard to avoid feeling bitter as a manager when people come to you with FUDA–especially if you feel like you’re becoming a dumping ground for problems–so we need to pause and put ourselves in their shoes.

Conversely, an employee feeling FUDA should empathize with his or her manager, who often has goals that are at odds with each other (e.g., making individuals happy in the moment vs. doing what’s right in the long term for the company).

Ultimately, there is no silver bullet for FUDA, but we have found success handling it by feeling empathy and remembering our shared values.

The post Handling Bad Feelings at Work appeared first on Atomic Spin.

Elm and Express: A Simple Client-Server Implementation

When I do a side project, I usually want to spin up something quickly, and most of my projects have some sort of client talking to a server. Recently, I’ve been exploring Elm, so I decided to find a quick way to put together a simple client and server using Elm and Express. Here’s what I’ve come up with.

The Express Server

I decided to use Express to build the server. Express is a lightweight framework for Node.js applications, so it does not take a lot of code to get something up and running. For client-server communication, I chose WebSockets. They’re easy to use with Elm, and so far, they have been pretty pain-free.

To get started, you need to install Express and the WebSockets module for Express in your project’s directory using npm:

npm install express

npm install express-ws

Now we can set up the skeleton of our Express server. Create a file server.js with the following code:

var express = require('express');
var app = express();
var expressWS = require('express-ws')(app);
var portNumber = 1234;
app.listen(portNumber, function() {
  console.log(`Listening on port ${portNumber}`);
// more to come here...

You can now run the server with this command:

node server.js

Back in the console, you should see a message telling you what port the server is listening to:


Now let’s set up a WebSocket that clients can connect to. In server.js, add the following code:'/hello', function(websocket, request) {
  console.log('A client connected!');
  websocket.on('message', function(message) {
    console.log(`A client sent a message: ${message}`);
    websocket.send('Hello, world!');

And that’s all we need for our server to send and receive messages.

The Elm Client

The server is finished, so now we can start creating our Elm client. If you haven’t already, check out the Elm tutorial. It’ll go through how to install Elm. Since we’ll be following the basic architecture described there, it may be helpful to quickly read it over.

Create a new file client.elm and add the following code:

import Html exposing (..)
import Html.App as App
import Html.Events exposing (..)
import WebSocket
main : Program Never
main =
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
type alias Model = List String
type Msg
  = Send
  | Receive String
init : (Model, Cmd Msg)
init =
  (["Welcome!"], Cmd.none)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Send ->
      (model, WebSocket.send "ws://localhost:1234/hello" "Hello, server!")
    Receive message ->
      ((List.append model [message]), Cmd.none)
subscriptions : Model -> Sub Msg
subscriptions model =
  WebSocket.listen "ws://localhost:1234/hello" Receive
view : Model -> Html Msg
view model =
    renderMessage msg =
      div [] [ text msg ]
    div []
      [ div [] ( renderMessage model)
      , button [onClick Send] [text "Send message to server!"]

There’s nothing too fancy going on here. To interact with our server, we just needed a few things:

  • The Send action, which is triggered by clicking the button, sends a message to the specified route.
  • A listener to the WebSocket in our subscriptions, which will watch out for incoming messages and trigger the Receive action.

Before you can run this, you have to install the WebSocket library with the following command: elm package install elm-lang/websocket.

With that, our application should be ready to run. Assuming the Express server is running, fire up your Elm client with elm-reactor and open up http://localhost:8000/client.elm on a browser. You should be able to see the button we created. Clicking on that button will send a message to the server, which will respond to the client and add a message to the list.



That’s all there is to it! Any time I’m working on a side project that requires a client-server architecture, I tend to start off with something like this and continue building on it. Hopefully, this helps you get started using Elm and Express.

The post Elm and Express: A Simple Client-Server Implementation appeared first on Atomic Spin.

Working with iOS Image Filters in Swift

I have always found image processing interesting and fun. However, despite having a decent amount of experience with it, I had never worked much with the tools for iOS. I decided to play around with them a bit, and to my delight, most of the iOS image processing libraries are incredibly simple to use. This topic has a lot of surface area, so I won’t be able to do it justice in a single post. However, this post should be enough to allow you to get started with image processing in iOS.

A Simple Filter

Let’s start with the pillar of image processing–image filters.

Image filters are responsible for taking an image, manipulating it, and producing a different output image. Fancy filters might be able to take in multiple images as input, but for the most part, it’s one image in, one image out.

The iOS image processing functionality lives inside of the Core Image framework. It turns out that Core Image comes with over 150 different image filters out of the box. You can query a list of all of them via:

let filterNames = CIFilter.filterNames(inCategories: nil)

Most filter functionality is centered around the CIFilter Core Image class. CIFilter has static methods such as filterNames (above). However, to apply an image filter, you instantiate a CIFilter instance and pass in a filter type. Filter types are defined by Strings constants, which is very un-Swift-like as it allows for run time errors.

Let’s look at an example that creates a blur filter and applies it to an image:

func simpleBlurFilterExample(inputImage: UIImage) -> UIImage {
    // convert UIImage to CIImage
    let inputCIImage = CIImage(image: inputImage)!
    // Create Blur CIFilter, and set the input image
    let blurFilter = CIFilter(name: "CIGaussianBlur")!
    blurFilter.setValue(inputCIImage, forKey: kCIInputImageKey)
    blurFilter.setValue(8, forKey: kCIInputRadiusKey)
    // Get the filtered output image and return it
    let outputImage = blurFilter.outputImage!
    return UIImage(ciImage: outputImage)

This is what applying the above filter looks like:


For some strange reason, there are a few different approaches for instantiating filters and applying them to images. The above example is just one approach. It’s a bit ugly and has forced unwrapped optionals, but it is easy to understand and walk through. Both the input image and any filter parameters can be set via the setValue function, where you pass in a value and a parameter type constant (defined here). Some filters have several parameters; some have none. Usually you can omit them and a default parameter value is used.

Below are some other interesting filters that are provided out of the box with Core Image.

CICMYKHalftone filter

The CICMYKHalftone filter adds a nice halftone effect, simulating what printed media might look like.

let filter = CIFilter(name: "CICMYKHalftone")!
filter.setValue(inputCIImage, forKey: kCIInputImageKey)
filter.setValue(25, forKey: kCIInputWidthKey)

CICrystallize filter

The CICrystallize filter quantizes the image into uniform colored polygons.

let filter = CIFilter(name: "CICrystallize")!
filter.setValue(inputCIImage, forKey: kCIInputImageKey)
filter.setValue(55, forKey: kCIInputRadiusKey)

In addition to these, there are many other filters provided by Core Image out of the box. For a more complete reference, refer to the docs.

Combining Filters

One way to produce effects that aren’t captured by one of the provided filters is to combine filters. You might imagine applying a set of filters in sequence, feeding the result of one as the input to the next. Core Image has special support for this and allows you to combine filters in such a way that the amount of processing required is minimized (e.g., it doesn’t necessarily have to compute a full output image for each filter applied).

Suppose you want to apply a CICrystallize filter, and then a CICMYKHalftone filter. You could achieve that via:

let outputImage = inputCIImage
        withInputParameters: [
            kCIInputRadiusKey: 50
        withInputParameters: [
           kCIInputWidthKey: 35

The above filter produces an image that looks like this:


Notice how this time, we instantiated and applied the filters differently than we did in the first example. Instead of creating a CIFilter instance, we called applyingFilter directly on the input CIImage instance. This is another way you may want to write your filtering code. I think this approach is nicer, but it isn’t obvious that a CIFilter instance is being created, so I opted to use the other approach in the earlier examples.

Custom Filters

If the provided Core Image filters (or some combination of them) doesn’t produce the effect you’re looking for, you can write your own custom filter. This functionality was new in iOS 8, and it’s pretty slick. This topic can get very complex quickly, so I’ll just touch on the basics. I may write a more detailed post on writing custom filters in the future.

In order to write a custom CIFilter, you need to write a custom CIKernel. The kernel tells the filter how to transform each pixel of the input image. There are three different types of kernels that you can write: color kernels, warp kernels, and general kernels. I’ll briefly cover color kernels in this post, as they are the easiest to understand.

To write a custom color kernel, you create an instance of CIColorKernel and provide it with the custom kernel code. It’s a bit strange because the kernel code must be written in GLSL, an OpenGL shading language. You provide your GLSL code as a string to the CIColorKernel constructor. This is, again, kind of terrible because it will blow up at runtime if your GLSL code has any errors.

Let’s look at an example. Suppose we wanted to write a custom kernel that removed the red color channel and divided the blue channel by two. First, we would need to subclass CIFilter, and override the outputImage property to return our custom processed image. That would look like this:

class CustomFilter: CIFilter {
    var inputImage: CIImage?
    override public var outputImage: CIImage! {
        get {
            if let inputImage = self.inputImage {
                let args = [inputImage as AnyObject]
                return createCustomKernel().apply(withExtent: inputImage.extent, arguments: args)
            } else {
                return nil

Notice the call to create our custom kernel: createCustomKernel. This function needs to return our custom CIColorKernel kernel with our custom GLSL kernel code. Here is what our implementation might look like:

func createCustomKernel() -> CIColorKernel {
    let kernelString =
        "kernel vec4 chromaKey( __sample s) { n" +
            "  vec4 newPixel = s.rgba;" +
            "  newPixel[0] = 0.0;" +
            "  newPixel[2] = newPixel[2] / 2.0;" +
            "  return newPixel;n" +
    return CIColorKernel(string: kernelString)!

Notice the GLSL function defined as a raw String. This function takes in a single pixel, represented by the __sample variable, and it must transform the input pixel into its output value. In our example, we wanted to remove the red color channel and divide the blue channel by two. That is what the above GLSL code is doing. This function will be executed for each pixel of the input image.

Invoking our custom filter looks like this:

let inputCIImage = // get CIImage from somewhere
let filter = CustomFilter()
filter.setValue(inputCIImage, forKey: kCIInputImageKey)
// Get the filtered output image and return it
let outputImage = filter.outputImage!

The resultant output image looks like this:


Further Reading

This post just scratched the surface of what’s possible using Core Image. If you’re interested in learning about it further, I recommend picking up this eBook. The material in it is excellent.

The post Working with iOS Image Filters in Swift appeared first on Atomic Spin.

Making Ember Objects More Strict: Only Access Defined Properties

Ember.Object provides a flexible starting point for creating models in a single-page web application. It can hold simple data members, define computed properties that automatically update when dependencies change, run a callback when properties change, and extend parent “classes” to create new types with additional members.

That said, I think Ember can be a bit too flexible at times.

How Much Flexibility is Too Much?

Let’s say I create a model for a blog post using Ember Data:

export default DS.Model.extend({
  author: DS.hasOne('author'),
  text: DS.attr('string'),
  likes: DS.attr('number'),
  comments: DS.hasMany('comment')

Then in code later on, I can do the following:

const post ='blog-post', { 
  author: jim, likes: 5, comments: [] 
post.set('text', "Lorem ipsum dolor sit amet...");;

That’s all well and good. But what if later on, I want to set the body of the post, forget I called it ‘text,’ and think I called it ‘body’?

post2.set('body', "Ain't goin' nowhere");
// a new property 'body' was created and has the set value;

My tests (automated and manual) will probably fail because the post content is not being updated properly, but it may not be immediately clear what the problem is. This issue is further exacerbated by many-word property names:

const data = this.get('reallyLongPropertyNameEtc1');

or when you are dot-chaining in property gets or sets:

const data = this.get('');

If data is undefined, which part is to blame: foo or bar or baz? Again, we can dig in and figure out the answer, but it would be nice if we didn’t have to.

Best Practices

I consider it a best practice to define any property I intend to use at the top of my Ember.Object. If it will be a simple data type, I use something like:

export default Ember.Object.extend({
  aNumber: 0,
  aString: "",
  anArray: [],
  // computed properties...

Consequently, I almost never want to get or set a property on an Ember.Object that I did not explicitly define. Ideally, Ember would tell me immediately if I tried to get or set an unknown property and I didn’t intend to do so.

Strict Models

Luckily, it isn’t hard to accomplish this. Ember.Object provides two functions, unknownProperty() and setUnknownProperty(), which can be used to create “strict” models. The presumed intention of these functions is to allow dynamic execution based on the string value of the property name to be retrieved or set.

However, we can repurpose them to make our Ember.Object models more strict. We can implement unknownProperty() and setUnknownProperty() to throw errors providing details of the property meant to be used, which allows us to fail fast and get as close as Ember allows to a locked down, static class.

// as a mixin - this could also be defined on a base class
export default Ember.Mixin.create({
  unknownProperty(key) {
    throw new Error(`attempting to get unknown property ${key}`);
  setUnknownProperty(key,value) {
    throw new Error(`attempting to set unknown property '${key}' to '${value}'`);

Now, our first example throws an error when you try to set the wrong property:

post2.set('body', "Ain't goin' nowhere"); // throws error -
// "attempting to set unknown property 'body' to 'Ain't goin' nowhere'";

The Exception that Complicates the Rule

Actually, it isn’t quite so simple. On some occasions, the Ember framework (and potentially plugins used by your application) may invoke properties you don’t care about or want to declare. Accordingly, you’ll have to allow some property names even if they are not explicitly defined. For these exceptions, you’ll want to use the default behavior (return undefined for get(), and call defineProperty() for set()). This is frustrating, but I don’t think it reduces the value of strict models by an unreasonable amount.

const exceptions = [
  'isTruthy', // Ember rendering
  'size', 'length', // Ember.isPresent
// as a mixin - this could also be defined on a base class
export default Ember.Mixin.create({
  unknownProperty(key) {
    if (!exceptions.contains(key)) {
     throw new Error(`attempting to get unknown property ${key}`);
  setUnknownProperty(key,value) {
    if (!exceptions.contains(key)) {
      throw new Error(`attempting to set unknown property ${key} to ${value}`);
    } else {
      // I'd rather call _super() here, but Ember only auto-defines a property
      // when there is no implementation of setUnknownProperty(), as opposed to
      // making defineProperty the default implementation
      Ember.defineProperty(this, key, null, value);
      return value;

Types, But Not Too Verbose

On my current project, making all of our data transfer objects into strict models has already helped me catch and fix errors more quickly than I would have otherwise. In general, I’d rather have my code throw an error than fail implicitly or silently. And as I wrote about with generating Ember models from C#, even if JavaScript is not statically typed, I’ll nudge it in that direction when I can do so–as long as it doesn’t make my code overly verbose.

The post Making Ember Objects More Strict: Only Access Defined Properties appeared first on Atomic Spin.

AWS IoT Help Button

We recently moved into our new building at 1034 Wealthy in Grand Rapids. The new building is much larger than our old one, and I find myself running around much more and stationing myself in different areas, depending on what I am actively doing.

To help ensure I can provide timely hands-on help—particularly for our printer (which is a common source of problems)—I procured one of the new AWS IoT buttons and programmed it to page me when pushed.

AWS IoT Button Overview

The AWS IoT Button is a simple device consisting primarily of a push button, an LED indicator, and a WiFi card. It can be configured to connect to the AWS IoT (Internet of Things) service in order to deliver data about button pushes. The data consists primarily of the type of button push (short, double, or long), but it also includes the button’s serial number and the battery voltage. This data can then be acted upon to do any number of interesting things using AWS or calling out to other services.

AWS IoT Button


The AWS IoT Button requires Internet connectivity to communicate with the AWS IoT service. When configuring the button, you choose a WiFi SSID to connect to and provide the appropriate passphrase. The button also receives an ARN identifier, so that it can be uniquely referenced within the AWS ecosystem.


When configuring the AWS IoT Button, a new PKI certificate and private key are generated and uploaded to the button. This allows the button to communicate securely with AWS, and it allows AWS to validate the identity of that button. This becomes important when writing specific policies to enable button data to trigger events.

How I Use the AWS IoT Button

When someone presses the AWS IoT button, it kicks off a process which will simultaneously e-mail me, send me an SMS message, and show me a notification on Slack. The message contains a timestamp and an identifier for the button that was pressed (in case there are more such buttons deployed in the future).

I have set the expectation that if I am available, and not in a meeting or otherwise occupied, I will respond to a button push within five minutes. This is often much faster than someone would be able to locate me and request assistance otherwise. While there have been a few instances where people1 have pushed the button simply to test my response time, I’ve had over a dozen instances of legitimate button pushes. As a result of these, I was able to respond to the notification and assist with a printer problem in a timely fashion.

AWS IoT Help Button

I’m not sure how well this setup would scale, but for the moment, it is working well.

The AWS Service Flow


AWS IoT is a platform to allow devices to interact with AWS cloud services.

For AWS IoT Buttons, there is a device or “thing,” rule, certificate, and policy associated with each physical button. A “device” associates a button (by serial number) with a particular HTTP REST endpoint and MQTT topic. The “certificate,” uploaded to the button during configuration, is linked to a “device” and allows the button to securely submit data, while also authenticating it to AWS. The “rule” specifies how messages from the MQTT topic are used, defining what actions to take when a query matches a message. A “policy” authorizes a specific device to take AWS IoT actions, such as publishing to an MQTT topic.

In my setup, I added the endpoint information for my “device” to the AWS IoT button, which is linked to the specific “certificate” I uploaded, along with its private key:

  • REST API Endpoint:
  • MQTT Topic: iotbutton/G030JF055234P6KJ

I gave the ‘device’ permission to publish to the MQTT topic:

  "Version": "2012-10-17",
  "Statement": [
      "Action": "iot:Publish",
      "Effect": "Allow",
      "Resource": "arn:aws:iot:us-west-2:979276642162:topic/iotbutton/G030JF055234P6KJ"

I specified that any messages received on the specific MQTT topic are forwarded to an AWS Lambda function:

  • Query String: SELECT * FROM 'iotbutton/G030JF055234P6KJ'
  • Action: Lamda Action; Function Name AWS_IoT_Button_aogr_1_resource_area

In this case, the messages are JSON-formatted data representing events containing the button’s serial number, battery voltage, and type of button push:

  "serialNumber": "G030JF055234P6KJ",
  "batteryVoltage": "1568mV",
  "clickType": "SINGLE"

AWS Lambda

As I have written about before2, AWS Lambda allows functions written in a few different languages (Python, Java, and Node.js) to be executed in response to events.

For my AWS IoT Button, I created a function to publish to an AWS SNS topic.

My Lambda function is quite simple;

// Node.JS 4.3 Runtime
const AWS = require('aws-sdk');
const SNS = new AWS.SNS({ apiVersion: '2010-03-31' });
function findTopicArn(topicName, cb) {
    SNS.createTopic({ Name: topicName }, (err, data) => {
        if (err) console.log(err, err.stack);
        else cb(data.TopicArn);
function publishToTopic(params, cb) {
    SNS.publish(params, (err, data) => {
        if (err) console.log(err, err.stack);
        else cb(data.MessageId);
exports.handler = (event, context, callback) => {
    console.log('Received event:', event.clickType);
    var datetime = new Date();
    var topicArn = findTopicArn('aws-iot-button-sns-topic', (topicArn) => {
        console.log(`Publishing to topic ${topicArn}`);
        var params = {
            Message: `aogr_1_resource_area help request at ${datetime}`,
            Subject: `Help Request: aogr_1_resource_area`,
            TopicArn: topicArn
        var messageId = publishToTopic(params, (messageId) => {
            console.log(`Published to topic with messageId: ${messageId}`);    
    } );

The function finds an SNS topic ARN by name, and then publishes a message to the topic. The event data is not actually passed along to SNS as this Lambda function is unique to the AWS IoT Button that I am using (specified in the “plan” for the “device” in AWS IoT), so I just send a custom message crafted for the purposes of the button. It would not be difficult to modify the function to send data about the button push (such as the push type), or send additional data from AWS IoT (such as the button serial number).


AWS SNS allows sending push messages to subscribers of specific topics.

For my purposes, I created an AWS SNS topic called “aws-iot-button-sns-topic” to which I added two subscriptions: one e-mail and one SMS. As I wanted to receive notifications from pushes to the AWS IoT button, I used my e-mail address and mobile number. When messages are published to the topic from the Lambda function, I receive them via e-mail and on my phone.


While certainly not a very sophisticated use of IoT, creating the IoT Help Button provided a good opportunity for me to learn about AWS’s IoT offering. I also took the chance to build a nifty device which helps make me a little bit more effective at my job. I’m excited to try out connecting other devices to AWS IoT, so I can build something larger which drives a more complex set of services.

1. Shawn Anderson
2. Managing AWS Route 53 Hosted Zones with AWS Lambda and Managing AWS CloudFront Security Group with AWS Lambda

The post AWS IoT Help Button appeared first on Atomic Spin.

Short-Handed Management Model – Five Practices that Make it Work

Good management at Atomic is putting people in the right context for success and getting out of their way. In other words, we hire trustworthy people, then trust them. 

At lot goes into that simple statement.

Atomic Object's Grand Rapids Managing Partner Team

Our Management Model

At Atomic, we have strong leadership, but we are short handed when it comes to traditional management. Our short-handed management model requires us to hire the right people, foster the right culture, put a solid process into place, and provide positive support structures.

This management model is a feature, not a bug. It pushes leaders to trust individuals and teams, and it keeps our operational costs low.

I manage our Grand Rapids office with my partner Shawn Crowley. The two of us are responsible for sales, clients, and people in Grand Rapids. Between the two of us, we have 32 (and growing) direct reports. We do a good job with a few formal management practices. We strive to have quarterly one-on-ones with everyone; we conduct yearly compensation reviews; we recently implemented a mid-year reflection focused around past success and growth.

These practices are valuable, but they aren’t enough to sustain a large team of knowledge workers. The combination of our 16:1 direct report ratio and other responsibilities doesn’t allow us enough time to work closely with all Atoms.

Our Five Management Practices

Luckily for us, the role of management at Atomic is shared and built into our culture. The following five practices enable our short-handed management model to work. If we get lazy on any of these practices, we’ll have some serious managerial debt on our hands:

1. Hire the right people

People are the most important element. Like all companies, we need our Atoms to be smart, ethical, and team players. Because we’re consultants, we also need Atoms to be curious about a wide variety of topics, to be creative problem solvers, and most importantly, to be self-starters who don’t require excessive handholding. When you have the right people, it’s easy to be an exceptional manager.

2. Foster the culture

At Atomic, we have six core values. These values help guide our decisions, and they are behaviors that we expect from everyone. It’s the responsibility of leadership to not only live these values, but more importantly to enable and empower others to live the values. This empowerment creates a team of leaders. Teams of leaders manage one another.

3. Assemble the right teams

When a project is sold, the project team assignment is determined by the office management team. Since we place so much autonomy and responsibility on teams, we need to ensure that each team has the right personalities, expertise, leadership, and experience. Team assignments are some of the most important and influential decisions that the office management team can make. Teams provide a structure for teaching, learning, and ad hoc management.

4. Develop a process to follow

We identify project roles, work within a standard set of project phases, have a common point of view around development practices, leverage a handful of project management tools, and use a standard cadence for key meetings. These best practices create a steady and familiar environment for our team members. The process helps keep team members fed with valuable work to do.

5. Invest in a support structure

The building block of Atomic is the individual Atom. Atoms are supported by teams, teams are supported by geographical offices, and offices are supported by the company. Atomic actively invests in supporting project teams in a few key ways.

Micah Alles, a long-time Atom with a bunch of project experience, meets with all project teams to provide process support and coaching. This support helps share best practices between teams, provide support for tricky situations, and create opportunities for Atoms who are willing to step into a project leadership position for the first time (delivery, design, or development).

Atomic has also implemented the Delivery Lead role. Along with their project responsibilities, Grand Rapids Delivery Leads support each other by meeting weekly to discuss project dynamics.

Management for Growth

Our short-handed management model isn’t ideal for all job candidates. However, for self-starting individuals who are eager to take control of their careers and work, our model creates an ideal setting for growth and job satisfaction.

The post Short-Handed Management Model – Five Practices that Make it Work appeared first on Atomic Spin.

Three Benefits of Speaking at a Conference

I recently travelled to Kitchener, Canada, to speak at Targeting Quality 2016, a great little conference with a good range of speakers and topics. Going to conferences is a good way to learn and expand your network, and if you go to one as a speaker, there are a few more benefits –besides the obvious one of not having to buy a ticket!

Phil Kirkham at a conference


After doing your talk, there’s usually a Q&A session–but you’ll often find that after that, when you’re tidying away your material, there will be other people wanting to talk to you.

And after that, when you’re at other sessions or on a break, people will recognize you and start conversations. This is useful if you’re shy, but even if you’re not, you’ll find that the people talking to you have a connection to your talk. It’s great for getting feedback and for exploring your subject in greater depth.


Having to prepare a talk can help you reveal to yourself how well (or not) you know the topic. If you’re struggling to explain a topic or can’t explain why you chose a tool/language/framework, it may be an indication that you should be thinking more deeply about the subject you are talking about.


The closing keynote from Karen Johnson was very interesting. I now have a copy of Orbiting the Giant Hairball to read after her recommendation, and I have been thinking about one comment she made during her talk.

She said that speaking at a conference has made her a better consultant–she went from being a shy introvert hiding in the cubicle at the back of the room to being a keynote speaker. Having to prepare a talk and then give it in front of a room full of people has given her confidence and practice, so she is well prepared for going into a meeting and talking with a few people.

Dreaming Big

It can seem a huge daunting leap to go from being a conference attendee to a conference speaker, but the rewards are there if you do. Find a small local conference where you can start (or do a talk in front of your company), and then think about going national.

The post Three Benefits of Speaking at a Conference appeared first on Atomic Spin.

Ember.js Components with DOM Dependencies

Ember.js is a great framework for building single-page applications. Its mantra of “data down, actions up” sets a clear guideline on how to structure most of your application.

Your route gets some data and tees it up for your controller/component to render it. When something changes the UI (say entering text), you fire an action with the updated values and use it to update your data. This approach also helps with rendering speed under the hood. Your view is totally driven by your model. Perfect. Unless…

What happens when things aren’t so cut and dry? Let’s walk through a case where part of the view depends on how another part renders.

Recently, I had to build a matching question form that required drawing lines between matched elements. I wanted to float an SVG over the parent element and position the lines based on the items on each side of the match. But since Ember components don’t have access to each other, how would I know when it’s ready?

First, a couple of basic handlebars templates:

  <div class="leftCol">
    {{#each leftItems as |left|}}
      {{connectable-item item=left }}
  <div class="rightCol">
    {{#each rightItems as |right|}}
      {{connectable-item item=right }}
  {{magic-connection-lines pairs=pairs}}

    {{#each matchPairs as |mp|}}
      <line x1={{mp.x1}} y1={{mp.y1}} x2={{mp.x2}} y2={{mp.y2}} />

We let the parent component wrangle jQuery and wait for our children to be done rendering:

import Ember from 'ember';
export default Ember.Component.extend({
  isPollingForItems: false,
    this._super(...arguments);, this.get('pollForItemsRendered'));
  didUpdateAttrs() {
    // look again if our model has changed, this.get('pollForItemsRendered'));
  _isElementLoaded($el) {
    let isLoaded = true;
    if($el && $el.length > 0) {
      var imgs = $el.find('img');
      for(var i = 0; i < imgs.length; i++){
          isLoaded = false;
    } else {
      isLoaded = false;
    return isLoaded;
    var allLoaded = true;
    this.get('items').forEach(item => {
      var $item = Ember.$(`[data-id='${}']`);
      if(!this._isElementLoaded($item)) { allLoaded = false; }
      this.set('items', Ember.merge({}, this.get('items')));
    } else {, this.get('pollForAnswersRendered'));
  leftItems: Ember.computed('items', function() {
    this.get('items').filterBy('left').map(item => {
      var $item = Ember.$(`[data-id='${}']`);
      return {
        x1: $item.position().left,
        y1: $item.position().top,

So, we’ve managed to wire up our top-level component to:

  • Use jQuery to get the positions of previously rendered DOM elements
  • Wait for all images to load; poll if they are not
  • Restart the process if our underlying model changes

You can definitely feel that we’re going against the eloquent grain of Ember, but we still have the flexibility to make things work.

The post Ember.js Components with DOM Dependencies appeared first on Atomic Spin.

Mary O’Neill on Treating Employees Like Customers, Saying ‘No’ to the CEO, and Doing the Work that Needs to Be Done

Mary O'Neill, Business Manager at Atomic Object Meet Mary O’Neill, workplace designer, artisanal bread baker, and Business Manager at Atomic Object. I recently sat down with Mary to hear her story.

This is the sixth in a series of interviews with Atomic makers.

You’re Atomic’s Business Manager. What does that mean day-to-day?

I’m the master of the machine that runs Atomic—keeping the company operating effectively for our clients and our employees. That includes a lot of different things, for example:

  • I support business operations for the whole company by doing things like reviewing legal agreements, negotiating leases, managing banking relationships, etc.
  • I develop our strategy and search for compelling employee benefits.
  • I help create and maintain effective facilities for our office locations, which included being Atomic’s owner-representative on our recently finished new building project. I was directly involved in the design of the building, set project requirements, made tough decisions, signed contracts, and managed relationships with our neighbors, local government, architects, contractors, etc.
  • I assist with Atomic’s hiring process by checking references and interviewing job candidates.
  • I also work on a lot of special projects as they arise.

My job also used to include all of Atomic’s financial operations, but a little over a year ago, we hired a full-time accountant (Adam Medema). Hiring Adam was an acknowledgement that my job had become completely unsustainable for one person; it wasn’t possible for me to single-handedly do everything Atomic needed from an operations perspective. We transitioned most of the financial operations to Adam, which has allowed me to focus on a wider range of other business operations needs, especially the delivery of our new space.

Adam and I work as a great pair—he’s someone I can collaborate with, and we load-balance tasks between each other. I’ve never had a pair at Atomic, and it’s gratifying. Adam is a degree-holding accountant, and I am a self-taught business manager with a B.A. in workplace design, so I really appreciate his perspective and expertise.

How did a workplace interior designer end up as Business Manager at Atomic?

I started working at Atomic in July 2002, working maybe 10 hours a week. I’d been laid off from my job at Herman Miller late in 2001, and Carl Erickson (Atomic’s CEO and my husband) needed help with the business side of a then-fledgling company.

The job was intended to “take some of the load off Carl while I figure out my next career move.” And I did everything I could do to free him up to focus on clients and growing our team. That meant processing payroll, invoicing clients, making sure we complied with applicable laws, filing our tax returns on time, ensuring the facility worked to serve our needs, provisioning us with the right levels of business insurance, negotiating and administering the benefits we offered, buying office snacks, etc.

The job expanded as Carl and I started working together, solving problems and figuring out how to make the company run smoothly. A lot of the work we did early on was born out of Carl’s and my desire to not just create a tiny startup, but to position Atomic for growth as a viable, long-term consultancy and an attractive employer–for example, being forward-thinking and generous with employee benefits so we could hire and keep good people.

The nature and complexity of my job increased over time as the company grew. The more people we hired, the more activity there was with the hiring process, benefits, facilities, etc. More client projects meant more invoices, and the flow of money increased. My job scaled roughly in parallel with the company. My leadership role evolved as I earned the trust and respect of people around me. I worked hard, lived Atomic’s values and led by example.

Why haven’t you gone back to interior design?

When I graduated from college, I thought I’d always have a job related to my degree. But sometimes unexpected life circumstances create enormous opportunity. And a smart person who works hard can teach themselves to do all kinds of valuable things.

I wasn’t “born knowing I wanted to be a business manager,” but it was an important thing to do at the start of Atomic. And I was at a point where I didn’t know what my next professional move should be. So instead of waiting for a brilliant insight, I just dug into the work at hand to help my family. It was an active choice to jump into something unknown but necessary, rather than passively waiting to be inspired by something else that might have seemed like a better fit with my education and prior experience.

What do you like about being the Business Manager?

I like that my work is varied—I do a lot of different things within my job every day. I’m activated by change. I enjoy it. For Carl and me, Atomic is a team effort. Though we do different work, it’s something we do together, and 99% of the time, it’s fun.

I also like the fact that I get to help people, which sounds cliche, but I find it very satisfying to have a positive impact in other people’s lives.

What do you find frustrating/difficult about it?

Sometimes, I have a hard time understanding the technical context our makers work in. The nuts and bolts of software design and development is still a pretty abstract concept for me.

I have a very three-dimensional, spatial orientation, so it’s sometimes hard for me to fully understand the physicality of software. I’ve asked Carl, “Where is all the code right now?” I want to imagine the physical location for all the software we create.

You and the CEO of Atomic are married to each other. Does that change how people see you?

I think so, but I don’t know for sure. Over time, I have hit a few rough spots with some people who have (incorrectly) assumed that I’m just Carl’s surrogate and don’t hold my own opinions, stand on my own, or add my own value to our work. I had to say, “I’m not Carl’s yes-woman—never have been and never will be.” And I tell Carl all the time, I’m his biggest fan and his toughest critic. Nobody will be more honest with him about how things really are.

For about seven years, I was Atomic’s only woman employee. There were times when that was kind of strange and hard, but a vast majority of the time, it was fine. Part of that could have been because of my partnership with Carl, but more importantly, I’m comfortable in my own skin and I’ve enjoyed the privilege of working with a great group of men. And I love the fact that Atomic is 11 women strong and growing. That’s awesome.

What skills do you need to be a good business manager at Atomic?

I need to be aware of what’s going on around me. I need to respond to the needs of other people, but also to anticipate them. With employee benefits, you have to look forward and see what you can improve, to think, “What can we offer that we might not have, balancing costs for all parties?” When we were considering enhancing our parental leave, Carl and I asked ourselves, “What would be best for the baby? What are their needs?”

Also important is extreme task organization. I’ve had to learn how to delegate, something I had a hard time with early on. Daily, I ask myself, “Is there someone who could do this better? Someone who wants the opportunity to do this?” Delegation is important to get more things done, and it creates more opportunities for other people—to learn, to shine, to help me deliver great results.

Name something surprising that you think has made you better at your job.

My education and tenure at Herman Miller taught me about what attention to detail really means, not just dotting is and crossing ts, but the details of human experience. My mentor would always ask me what a design detail would be like to touch, not just how it looked or how it functioned. Focus on your user, and think about another human’s response to your work product.

As the Business Manager, Atoms and clients are my users. I focus on their experience at Atomic—resolving details thoroughly, thinking through them carefully and with empathy.

It was also very useful in our recent building project. We hired an architect, but Carl and I were very directly involved in the design of the building. Together, we are a powerful pair in thinking creatively about architecture and crafting spaces that solve real business needs. You’ll see evidence of that in every room of our new workplace.

What do you like to do outside of work?

I like to work with my hands. I’ve been a bread baker for a long time; I’m both self-taught and have taken some classes. Cooking has always been an important creative outlet for me. It’s a great way to express love and bring people together.

I enjoy reading, and the discipline my book group offers me. And I love to travel. Taking myself to a different place can be an amazing, mind-centering thing. Changing my venue inspires me and changes my worldview in meaningful ways.

The post Mary O’Neill on Treating Employees Like Customers, Saying ‘No’ to the CEO, and Doing the Work that Needs to Be Done appeared first on Atomic Spin.