2016: A Year In Review

When a new year begins, we always take some time to set our own (usually unrealistic) goals for ourselves both personally and together as a company. This helps us stay focused and dedicated throughout the year. As the year comes to a close we found ourselves reflecting on what this year meant for us. We are incredibly thankful for our clients and for our friends for supporting us throughout this year. We’d like to take a bit to recap our year, and give some insight into what the next year will bring for us.

What went right?

After taking the plunge to moving the company from a single person to a lean, three person team, this year was our most successful to date (and we’re really proud of that). The way we measure that success is by seeing how many things from the past year we can put into our “things we care about most” buckets which are:

  1. Client Wins
  2. Personal Wins
  3. Speaking Engagements
  4. Event / Organization Sponsorships

Client Wins

Our clients success is our success, and we’re deftly intent on seeing them succeed. Here are some awesome wins they had in 2016:

Owner of CrowdfundInsider launches platform to search and promote SEC filings

We worked with the owner of the leading news and information website covering disruptive finance to improve the process that users go through to access SEC filings. This service, Disclosure Quest, allows users to see an “at a glance” view of crowdfunding filings but more importantly, allows them to dig deeper and view the actual documents and assets that were filed with an easy to use search interface.

The AIM Institute launches a service to test new markets for product development

AIM is a long-time client of ours who we have had an ongoing feature and maintenance contract with. They’re an absolute pleasure to work with. This year we were able to bring to fruition an amazing idea they had, B2B MarketView, which gives businesses the ability to answer a few questions to receive an insightful, custom built report regarding the market position of potential new products.

iDisclose and Disclosure Quest launch Form C support

May 15th, 2016 was a big day in the crowdfunding industry. It was the first day that one could file the newly available “Form C” document, allowing individual people to invest in one’s company in exchange for equity. We can proudly say that the first Form C document that was filed, at 6:35am that day, was a document created by iDisclose, a client whose web based application we developed in 2015.

Soon after submission, someone could find the filing information on Disclosure Quest, another of our client’s projects. Having support for Form C from day one was massively important for our clients, a need that we can say confidently that was met.

vLoan launches newly realigned homepage and expanded online mortgage service

We worked with vLoan on a number of pieces to their online mortgage system, but this year we were given the ability to take a fresh look at their homepage which was originally built for their MVP launch. We had a year of data and customer experiences which were used to target the messaging and layout for conversion. In doing so, we were also able to make improvements to design, performance, and page accessibility; three things we care a lot about as a company.

Peak Telematics launches Darby, a usage based insurance application

Working directly with Brad Colbow, a local UX and design guru, we designed and built the templates for the company’s web application which takes an ultra modern approach to an industry not known for putting an importance on usability and design. In 2016 they released an alpha version of their application which they intend to license to insurance companies.

A magazine with more than 500,000 monthly page views gets complete website redesign

Working with our friends at Studio Mercury we had the distinct pleasure of implementing, from the ground up, the new website design they created for one of their clients. There was a lot of custom functionality developed to help meet the new, modern demands of their site’s users. The website is slated for launch in early 2017.


Personal Wins

We believe that it’s very important to grow as a person outside of the business. We try to give back and involve ourselves in causes that we care deeply about in our communities.

Byron was accepted into the 2017 class of Akron Torchbearers, a Leadership Akron independent affiliate

One of our developers, Byron, was accepted into the 2017 class of Torchbearers. This program is equally focused on leadership development and community service and has well over double the amount of applicants as it does accepted members. The organization exists to strengthen the connection between Akron-area nonprofits and emerging leaders.

Company sponsors, helps organize, and attends Cleveland GiveCamp

Cleveland GiveCamp, one of the nations largest GiveCamps with over 200 volunteers annually, has been a passion of Jon Knapp since its inception 8 years ago. As Coffee and Code grows, so does its involvement in the organization. More on this can be read in a previous write-up here.

Company helps organize and attends Hack N Akron, a civic hackathon

Hack N Akron, a civic hacking group, was founded by a group of local volunteers including our developer, Byron. He helped not only plan the technical direction for the day, but connected the city staff to the development team, and worked hard to make the event a success. Eric also attended the event and helped with design guidance and research questions.

Akron Front End Development Group

Byron has been the sole organizer of a technical meetup group in the Akron area that he started as a Micrommunity of Launch League in May of 2016. The group has hosted monthly meetups and several hack nights to create a community of local developers and designers interested in leveling up and expanding their skill set.


Speaking Engagements

We believe that public speaking, especially at conferences and meetups relating to your field, is one of the best ways to grow as a person, and as a professional. The confidence, required research, and people skills developed while doing this are invaluable.

Design Feedback for Everyone, Eric Browning

Eric’s talk, Design Feedback for Everyone, was a big hit this year. On discussing how non-designers and designers can interact more efficiently, Eric gave this talk at three different events. First at StirTrek, then at the Columbus Web Group, and lastly at Flight.

Personas: an Interactive User Experience Workshop, Eric Browning

Eric crafted an interactive workshop to help work out different personas given a particular group, organization, etc. He gave this workshop at the UX Akron meetup group and an event organized by Akron Women in Tech.

Docker on the Docks, Jon Knapp

Speaking to the Cleveland Ruby Brigade (CleRB) Group, Jon talked through the process of creating and setting up Docker containers, how they differ from VMs, and lessons learned bringing local development and deployments to the technology.

Building “Serverless” Software with AWS Lambda, Jon Knapp

After utilizing AWS Lambda for a few interesting projects at the company, Jon put together a talk on the subject which he gave at Erie Day of Code, Pittsburgh Tech Fest, and will be delivering it in January of 2017 at CodeMash.

Wadsworth Career Day, Jon Knapp

For the third year in a row, Jon talked to Wadsworth high school students at their annual Career Day. He spoke a bit on starting a business, his personal development path post high school, info about the job market, and focused on open Q&A with the students.

How HTTP/2 Fits Into Your Workflow, Byron Delpinal

For a while now, Byron has been interested in web performance. He gave this talk outlining the benefits of HTTP/2 and how to implement it at Flight and will be giving it again in early January 2017 at Codemash.


Event / Organization Sponsorships

We believe in supporting things that we want to see more of. It’s a big deal to us, especially in our local community. Here are the events and organizations that we supported in 2016:


Looking Forward to 2017

2016 was great, but what happens next? We’re looking to do more of what we love and are interested in finding:

  1. Awesome clients to bring on board in the new year.
  2. Great people to work with in developer, marketing/sales, and business development roles.
  3. Opportunities to speak at industry events.

If you’re interested in bringing any of these to our attention, don’t hesitate, we’d love to hear from you! You can contact us at info@coffeeandcode.com.

Designing for Inclusion

A local company recently asked us to review their new application which focuses on parenting and childcare. They’re doing lots of things right and we wish them the best, but as I was going through their signup flow, something caught my eye.

The very first thing they ask as you fill in your (required) profile is “Gender” with the options “Male” or “Female”. This felt off to me, so I began researching so I could more eloquently explain myself.

There are a number of personal and life situations someone might be encountering that could make answering this a challenge, from gender identity questions to perhaps a single father not knowing if he needs to check female to be the “main/mother” on the account. Similarly, does a child with 2 parents of the same gender need different choices here?

The answer might be no to all of these, but consider that this is the first thing people have to answer about themselves. It could lead to complicated feelings and emotional responses; think about how that starts their journey with your application. Is that the right tone?

One of the best ways to avoid this is to consider if you really need to ask this information or could it be left out, or made optional later? Beyond gender, applying this test to anything you ask a user to provide is a valuable process. Why burden someone, or waste their time, or make them feel unwelcome?

Assuming you do need the information, you should offer a quick explanation in that section that explains how it’s used. Attached is an example of how Facebook explains what a user’s preferred pronoun is used for.

Pronoun usage explanation

It may seem like an edge case to you or possibly just ‘political correctness’, but this is such a simple way to address issues it’s not worth alienating even a small subset of your (potential) users.

Another idea is to offer more choices; not that anyone wants to feel like an ‘other’, but anything beyond a binary choice opens up paths to make people feel comfortable. Trying to go beyond to create a comprehensive list might even work for a particular situation, but it’s often riddled with challenges and limitations, as discussed in detail here.

When we think of accessibility, it’s often framed in terms of screen readers, valid code, and progressive enhancement techniques. I think there’s another layer we should be considering though, which is a less technical, more conceptual side. What we ask of users, and how we ask it can be just as important.

If you’re at all interested I recently read a great book that goes deeper into topics like this, Design for Real Life. I encourage you to check it out, as well as these other relevant links:

http://www.designprinciplesftw.com/collections/the-ten-principles-of-inclusive-web-design

http://blog.aarp.org/2015/08/26/how-the-americans-with-disabilities-act-benefits-all-of-us/

http://www.uxbooth.com/articles/women-on-top-inappropriate-dropdowns/

http://www.uxbooth.com/articles/inclusive-design-greater-identity-representation/

image courtesy http://www.wocintechchat.com

Responsive Graphing and Charting Using HTML5 Canvas

Recently we were tasked with creating a dynamic chart and graph for a client who is in the B2B Coaching space. They wanted this chart in a dynamically created PDF as well as in their responsive web application. In this post, we’ll talk about how we solved this problem in their responsive web application using zero Javascript dependancies for an added performance win.

Finished Product

You can view all of the code related to this post on Codepen with this link.

See the Pen Responsive Charting and Graphing with the HTML5 Canvas Element by Byron Delpinal (@coffeeandcode) on CodePen.

Client Application: https://b2bmarketview.theaiminstitute.com/

Fair Warning: This post is going to be dry and code-heavy, but there’s some pretty cool stuff in there if you can stick with me.

Technical Requirements

  1. We will use an image for any static content with-in the charted area.
  2. The dynamic content will be generated by vanilla Javascript to mitigate the need for bringing in any external libraries.
  3. All measurements when drawing will be percent-based to keep the drawing responsive.
  4. The dynamic content will be stored as data- attributes on the canvas element.

Markup

We want to be as minimal as possible here. The bare-bones of what we need are an image, a container to hold that image that will resize to be the exact size of the image, and a placeholder for the canvas drawing.

<div class="b2b-graph-container">
  <img alt="B2b index graph" class="b2b-graph" src="/pathtoyourimage/image.png"/>
  <canvas data-aggregate="58" data-knowledge="14" data-interest="7" data-objectivity="6" data-foresight="11" data-concentration="20" id="graph-canvas"></canvas>
</div>

Javascript

There is a lot of Javascript required to make this work. I tried my best to keep things modular and abstract things when it made sense. Hopefully this will make this a bit easier to digest.

The initial JSON objects used to store the known values of the bar graph and each line graph point:

var barGraphElement = {
    maxAmount: 100,
    scoreAttribute: 'data-aggregate',
    width: 7.5,
    xCoord: 10.8,
    yScale: 10
  },
  lineGraphElementList = [{
    maxAmount: 20,
    scoreAttribute: 'data-knowledge',
    width: 1.25,
    xCoord: 37,
    yCoord: 0,
    yScale: 2
  }, {
  // All other points on the line graph
  ...
  }];

When our page is loaded, our application.js file runs conditional code to see if we need to draw our graph on this page or not. That looks like this:

var canvasElement = document.querySelector('#graph-canvas'),
    graphElement = document.querySelector('.b2b-graph-container');

if (canvasElement && graphElement) {
  drawGraph(window, graphElement, canvasElement);
}

This separates our concerns a bit having the application logic finding the required elements and passing them into our actual drawGraph function. Our drawGraph doesn’t necessarily care about what the elements are, or what context is used, it only knows about drawing the graph.

When we know that we should be drawing our graph on this page, we need to wait for our image to load before doing anything else. There’s a .complete method for images that can be used like this:

var imgElement = container.querySelector("img");

if (imgElement.complete) {
  // The image is already loaded!
  initializeDrawing()
} else {
  // The image is not loaded, let's attach an event handler to it
  imgElement.addEventListener('load', initializeDrawing, false);
}

Our initializeDrawing function handles the main logic flow, here it is, I’ll break it down below:

var initializeDrawing = function     initializeDrawing() {
  var context = canvas.getContext('2d');

  resizeAndPositionCanvas(canvas);
  updateContainerOffsets();

  // Set the stroke color
  context.fillStyle = '#ed1c24';
  context.strokeStyle = 'rgba(255,0,0,0.5)';

  // Draw the overall score
  drawOverallScore(context);

  // Draw the bar graph
  drawBarGraph(context);

  // Draw the line graph
  for (var i = 0, l = lineGraphElementList.length; i < l; i++) {
    var currentItem = lineGraphElementList[i],
      previousItem = lineGraphElementList[i-1];

    // Draw the current point on the graph
    drawLineGraphPoint(context, currentItem);
    // Draw a line from the current point to the previous point
    drawLineGraphLine(context, currentItem, previousItem);
  }

  global.addEventListener('resize', resize, false);
}

The first thing that we do is grab the 2D canvas context that we will pass around and use to draw everything we need to on the canvas element.

Next we’ll need to position the canvas directly on top of the image, so the resizeAndPositionCanvas() function takes the canvas element and manually sizes it to be 100% of the parent container of the image.

After that, we call the updateContainerOffsets() function that updates the canvasContainerOffsets object that we’ll be using later on.

After we’ve changed our drawing colors to red, it’s time to start putting some things on our graph! To do this responsively, there’s one key concept that we need to understand: Everything must be measured in a percent based on the parent container.

Diving right into the drawOverallScore() function, we see this:

var drawOverallScore = function drawOverallScore(context) {
  context.font = getPixelWidthFromPercent(4) + "px Arial";
       context.fillText(canvas.getAttribute(barGraphElement.scoreAttribute),
  getPixelWidthFromPercent(44),
  getPixelHeightFromPercent(15.5));
  };

It’s pretty straight forward, we’re just using the fillText function to put the text on the page. The weirdness comes from converting our percentages into pixels, which we’ve abstracted away into the getPixelWidthFromPercent() and getPixelHeightFromPercent() functions. Here they are:

var getPixelHeightFromPercent = function getPixelHeightFromPercent(percent) {
  return canvasContainerOffsets.height * (percent/100)
};

var getPixelWidthFromPercent = function getPixelWidthFromPercent(percent) {
  return canvasContainerOffsets.width * (percent/100)
};

Remember talking about seeing the canvasContainerOffsets object again later? Here it is. Anytime the screen is resized, we recalculate the width and height of the parent container so we can use them at anytime to convert percentages to pixels quickly. That code looks like this:

// Add the event listener
global.addEventListener('resize', resize, false);

// Handle the callback
var resize = function resize(event) {
  updateContainerOffsets();
};

// Update the offsets
var updateContainerOffsets = function updateContainerOffsets() {
  var parentElement = container;

  canvasContainerOffsets = {
    height: parentElement.offsetHeight,
    width: parentElement.offsetWidth
  };
}

Now, we can draw the bar graph:

var drawBarGraph = function drawBarGraph(context) {
  var currentItemScore = canvas.getAttribute(barGraphElement.scoreAttribute);

  context.beginPath();

  var distanceFromTop = calculateDistance(barGraphElement.maxAmount-currentItemScore, barGraphElement.yScale);
  var barHeight = calculateDistance(currentItemScore, barGraphElement.yScale);

  context.rect(getPixelWidthFromPercent(barGraphElement.xCoord),  getPixelHeightFromPercent(universalDistanceFromTop + distanceFromTop),
    getPixelWidthFromPercent(barGraphElement.width),
    getPixelHeightFromPercent(barHeight));

  context.fill();
};

var calculateDistance = function calculateDistance(score, scale) {
  var distanceBetweenEachMarker = 6.2;

  return (score / scale) * distanceBetweenEachMarker;
};

Admittedly, that context.rect() call is a bit weird, so I’ll dissect it a bit. If you check out the canvas rect documentation you’ll see that the parameters are .rect(x, y, width, height) – so we’re defining the x and y starting points, and then the width and height from there. Recall that our barGraphElement has maxAmount, width, xCoord, and yScale properties on it. These, along with the scoreAttribute from our data- attributes will be what we need to complete our goal here. The width is a set percentage, as is the xCoord.

Because of the nature of the .rect() method we will start from the top of the shape and define it from there, this means that we must figure out where the top of a dynamically sized shape. This may seem odd at first, but because we have a background image with horizontal markers on it, the problem isn’t too difficult. It work out to something like this:

((maxAmount - currentScore) / (maxAmount / numberOfMarkers) * distanceBetweenEachMarker) + universalDistanceFromTop

(maxAmount - currentScore) – This gives us the amount of distance from the top of where the bar graph will be, to the top of the bar graphs maximum amount. If our score was 60, we know that it’s 40 from the top. We have to then divide that by the scale. The scale is calculated by seeing how many markers we have (10) and dividing that by the maximum score (100) – in this case, our scale is 10. After we have that, we multiply it all by the distance between each marker to get the final distance as a percentage between the top of the bar graph and the top of the maximum bar graph. Finally, we add the distance from the top of the bar graph to the top of the page. At this point, we know where the top left corner of our bar graph will be, as a percent based on our full image. This is all handled in the above drawBarGraph() and calculateDistance() functions.

As it turns out, we can apply that same logic to draw all of the other things that we need to on our graph. The only two things remaining are the line graph points of intersection, and the lines themselves.

We see above in the initializeDrawing() function that we are looping through each point and using the current item to draw the point, and the current + previous point to draw the line. Here are those functions:

var drawLineGraphPoint = function drawLineGraphPoint(context, currentItem) {
    var currentItemScore = canvas.getAttribute(currentItem.scoreAttribute);
    // We  inverted the coordinates by subtracting it from the maximum since (0,0) is in the top left of the coordinate plane:
    var distanceFromTop = calculateDistance(currentItem.maxAmount-currentItemScore, currentItem.yScale);
    //Since the y distance is only the distance from the top of the plane to the value, we account for the  top buffer of space as well:
    currentItem.yCoord = universalDistanceFromTop + distanceFromTop;

    context.beginPath();

    context.arc(getPixelWidthFromPercent(currentItem.xCoord),
    getPixelHeightFromPercent(currentItem.yCoord),
    getPixelWidthFromPercent(currentItem.width),
      (Math.PI/180)*0,
      (Math.PI/180)*360,
      false);

    context.fill();
};

var drawLineGraphLine = function drawLineGraphLine(context, currentItem, previousItem) {
  if (!previousItem) {
    return;
  }

  context.beginPath();
  context.lineWidth = 4;

  context.moveTo(getPixelWidthFromPercent(previousItem.xCoord), getPixelHeightFromPercent(previousItem.yCoord));
  context.lineTo(getPixelWidthFromPercent(currentItem.xCoord), getPixelHeightFromPercent(currentItem.yCoord));

  context.stroke();
};

So now, we’ve drawn our score onto our graph, our bar graph, and our line graph. Presto, they now work on all screen sizes, using no external Javascript dependencies. Performance win, responsive win, all around win.

If you’d like to learn more about how responsive and performance based approaches can build better web software, we’d love to talk. Please visit us at www.coffeeandcode.com.

2016 Cleveland GiveCamp Recap

Waking up the Monday after GiveCamp is always the most relaxing morning of the year. It’s juxtaposed with the two preceding days where sleep is hard to come by and each morning you are reminded of all of the work that needs to get done that day.

What is GiveCamp?

Cleveland GiveCamp is an incredibly well-organized event that takes place in Cleveland, OH every year that benefits non-profit organizations in the area. The basic flow of events is this:

  1. A local non-profit needs a problem solved through technology but does not have the personal or financial means to solve it themselves.
  2. They apply to GiveCamp to have volunteers solve said problem for them.
  3. After a very long weekend, they leave GiveCamp with a (hopefully) working and maintainable solution to their problem.

Every year the event has ~200 volunteers who handle everything from design, development, implementation, and copy writing, to food, setup, and cleanup.

The event is a time where you can meet like-minded people, make meaningful connections with others, and do some good in the world.

What did Coffee and Code do?

We proudly play many roles in helping GiveCamp become the successful event that it is today. Did I mention that it’s the nations largest and most well-sponsored GiveCamp event?

1. Sponsor

GiveCamp Water Bottles

Photo by Stuart O. Smith, Jr. @sos_jr

We were more than happy to become one of the many sponsors of this event, helping to ensure that it had the funds it needed to make sure every team had the supplies they need to succeed.

2. Organizer & Fire Extinguisher

GiveCamp Team Y Group Photo

Photo by GiveCamp photographers

Jon Knapp, founder of Coffee and Code, is a recurring organizer for GiveCamp as well as a member of Team Y. Call them all-stars, fire extinguishers, or red-shirts, Team Y was the group that you called when something went wrong. They are seasoned members of the community that are veterans in flipping a train wreck into a smooth delivery.

3. Volunteer

GiveCamp Team M Group Photo

Photo by GiveCamp photographers

Byron Delpinal, developer at Coffee and Code, is a second-year volunteer and member of Team M. His team helped the Northeast Ohio Voters Advocates better show their goals to a wider audience through a newly branded and designed website. This allows them to showcase who they are to a wider group of people. They now have a mobile-friendly site and can even take donations online!

What’s the weekend like?

A weekend at GiveCamp takes roughly 400 hours to complete in the minds of those that attend. In reality, it’s a 72-hour weekend.

Day One: Plan and Begin

Site Map and Priority List
Volunteers arrive and check-in Friday around 5PM where they are assigned a team. Each team is a single letter. At this point, the volunteer doesn’t know which non-profit they’re working with, or who their other team members are. There is a 30min opening ceremony , and then its off to dinner. Oh my gosh, dinner. The food at GiveCamp is so top-notch, seriously. I can’t say enough about it. At dinner, you are assigned an eating / working area where you finally meet your team and non-profit all at once. This is a meet and greet where you get to find out what work you’ll be completing and who you’ll be completing it with.

After dinner, the project manager starts assigning tasks and it’s off to the races! Teams work hard to start gathering the resources they need and syncing up development environments. Day one usually starts winding down after the last stand-up at 11PM, but teams can be seen working on the boat until very early in the morning. At the end of this day, you should have mapped out what this project looks like and how you’re planning to tackle this.

Day Two: Collaborate and Work

Task List on Post It Notes

Photo by Anna Kiss Mauser-Martinez

On Saturday, breakfast is served at 7:30AM. Teams eat and begin working around 8. At this point, the team usually has a fairly good understanding of the direction of the project as well as what each members role in that will look like. Task lists are created and teams go to work on their collaborative solution.

Depending on how large your project is, Saturday can become anywhere from a 12 to a 20 hour work day. This is where the real magic of GiveCamp happens, and most of the work is done. The organizers of this event do an amazing job of making sure that whatever it is that keeps you going is there to support you. Whether you work best on low-carb energy bars, fruit, coffee, donuts, cupcakes, or chips, there are snacks and drinks available 24/7. The planned meals, again, are on a league of their own.

Day Three: Finish up and Present

Waking up Sunday is a very different experience for everyone. Some projects have been finished and are writing documentation for their non-profits while others have three members from Team Y in their work space. No matter where you are on that spectrum, don’t panic. Sometimes things happen that aren’t ideal and that’s ok, remember that everyone is there to help. This year there was a 100% project success rate, which only happens when you truly have a community that is focused on helping others. Egos are put aside, frustrations are calmed, and everyone does whatever is necessary to get the projects completed.

Closing ceremonies are at 4PM where each project is presented to the group. This is when you can finally relax your mind and enjoy the fact that no matter which project you were on, you helped someone that needed it. Regardless of your stress level throughout the weekend, you leave with a big smile and a feeling of satisfaction.

The Role of Books in a Modern Tech Company

It’s cliché, but the one thing that never changes in the tech industry is that things are always changing. As of writing this I’ve been out of college about 10 years; the devices, environments, and technology I learned are so wildly out of date now that if I hadn’t continued learning, I’d have virtually nothing to offer a client.

We try to make learning and growing a priority at Coffee and Code. We love attending (and speaking) at conferences, and we’re always discussing the latest blog articles and industry news. But for a deeper understanding and more thorough levels of discourse, books are often the answer.

Anecdotally it seems like books have a love/hate place in the tech world. We like to praise authors and retweet new book announcements, but when push comes to shove many of us turn to quick answers on Stack Overflow or social media and blogs almost exclusively. Books seem to be a nice luxury for a company lounge, but not truly essential to our work anymore.

In order to explore books more fully and take our learning as a company to the next level, we started a book club. The rules are simple, choose a book as a team then break it out into reasonable chunks. Set dates to have discussion on the most recent section. The simple act of splitting a book up into sections and discussing each as a group has been refreshing. Peer pressure is an amazing force to leverage to keep yourself accountable (diet and fitness social apps lean heavily on this).

We’ve learned a few things along the way I wanted to share:

Picking titles is hard, but worth spending time on.

Choosing books that suit multiple team members, but also push your team outside their comfort zone is a tricky balancing act. Inevitably a book will probably be below someone’s skill level and likely above someone else’s (and possibly not even in their interests).

If you have a diverse group, trying to alternate between different subject matter is a solid approach. Part of the appeal though is being forced to read something you might not otherwise.

We started out with Git for Humans by David Demaree. Git is something we all use, but have very different backgrounds and proficiency with. Choosing broad topics for the first few books is a good way to get used to the format and the schedule.

Strive to accommodate format preferences.

Some people (I’m one of them) just aren’t fond of longform reading on a computer screen (or tablet/phone). This means paying the extra to get physical copies, or making sure your team has access to e-readers.

Be reasonably aggressive with your schedule.

Everyone is busy; especially in our industry. There’s always something to do, and the pressure to go ‘above and beyond’ is constant: speaking and presenting, blogging, attending Meetups, contributing to open source projects; it all adds up quickly.

It’s easy to set super long deadlines for each chapter or section, but pushing yourself a bit keeps the pressure on and helps you get through each book quicker.

Embrace honesty and have a little fun.

Nothing is set in stone here, if your team misses a session or everyone is a bit behind their reading nothing is going to fall apart. If you haven’t read the section, be honest about it. A little friendly shaming might help a team member who is behind, but remember this is all to help each other grow and learn.

Similarly, if your book discussions veer off on some tangents, that’s fine too. Learning isn’t always a linear process, and inspiration and growth can come from unexpected places.

What does AWS Lambda support?

Anyone who’s developing in JavaScript knows the extremely useful features that have been creeping into Node and different web browsers. They also know the frustration of determining which features are supported and the pain of forced polyfills and code transformations tacked onto our build processes.

At Coffee and Code, I’ve been doing quite a few projects involving AWS Lambda which provides a Node.js runtime, but I kept having to look up whether I could use a specific ES6 feature or not.

How do I find out what features are supported and which I’d require something like Babel for?

Kangax provides a great resource for determining what features are supported in different JavaScript environments. However, they only show the major versions of Node.

node.green is a fairly new resource that focuses on more releases of Node and also utilizes the Kangax test suite, but they don’t list results for older versions of Node.

That’s why I built whatdoeslambdasupport.com, a website to quickly see what tests pass or fail for each Node runtime that AWS Lambda supports.

The tests results are generated by running the Kangax tests inside each of the Node.js Lambda runtimes so there’s no “it works on my machine” issues with the test results.

You can use this resource to determine what JS features you can use in your Lambda projects, or to make a call whether including something like Babel makes sense.


If you’re interested in hearing more about how I’ve used Lambda for client projects, I’ll be speaking at Pittsburgh TechFest and Erie Day of Code over the next couple weeks. Stop by and say hello!

Talking About Design Feedback at Stir Trek 2016

Last week I had the opportunity to speak again at Stir Trek, a yearly conference held in Columbus at a large multiplex theatre. It’s a one-day event with 6 different ‘tracks’ of speakers. You finish up after the sessions with a showing of the latest Marvel movie (or Star Trek, etc). It’s a great event; organized and run very well, and the cost is very reasonable.

My talk this year was on how to give design feedback. Specifically, how to give useful feedback when you’re not a designer. It was a tough topic to prepare, because I had to research and work through the problem myself; it’s something that’s been troubling me for a number of years.

I took the risk of keeping the presentation short, allowing 20 minutes for a mini-workshop getting actual critiques from attendees. The goal was to ask attendees how they’d respond in example design critiques using the advice from my talk. I also had a 1:00pm time slot and crowd interaction allowed me to fight off post lunch food comas as best as I could.

I can happily report that it went very well. Things ran smoothly, there was plenty of audience participation (and it was ~80% developers!), and I had some nice discussions afterward.

After the conference, I spotted this great review and among the retweets and mentions were these awesome sketch notes:

There’s much more to learn and share around feedback, so I look forward to hopefully giving a similar presentation again and discussing with more people.

My slides are available here. If you’re interested in a live presentation of this talk, please reach out to eric@coffeeandcode.com!

Converting Documents with OpenOffice / LibreOffice

Did you know that you can convert documents with a headless version of OpenOffice or LibreOffice? If you pass a few commands to the soffice binary, you can convert one document type to another.

My examples will include paths for LibreOffice on a Mac, so make sure to adjust accordingly.

The following will convert all Word documents on my desktop to PDFs in the convert folder on my Desktop:

HOME=/tmp TMPDIR=/tmp /Applications/LibreOffice.app/Contents/MacOS/soffice --headless --convert-to pdf:writer_pdf_Export --outdir /Users/jon/Desktop/output/ /Users/jon/Desktop/*.doc

Make sure to include HOME=/tmp TMPDIR=/tmp before the command or it will run into permission issues and be unable to complete the file conversion.

Some believe writing files to the /tmp directory is a better approach, but I didn’t end up trying it myself.

Thanks to: https://ask.libreoffice.org/en/question/2641/convert-to-command-line-parameter/

Talking Personas and Empathy Mapping with UX Akron

I had the great opportunity last week to give a short presentation at UX Akron, and lead a small workshop on personas and empathy mapping.

A persona is simply a fictional character (or set of them) your team creates to serve as a snapshot of your audience. The idea is to take things like demographics, goals, wants and needs and give them a relatable human presence. It’s much easier for us to be empathetic when we’re discussing ‘someone’ rather than just ‘our users’ or some other more abstract reference.

Empathy mapping is an exercise used to get in the mindset of your users, helping you to think and act like they would. You take one of your target users, and divide up a sheet into quadrants: thinking, feeling, seeing, and doing. You brainstorm different ideas with sticky notes for each section to help build a snapshot of this user at this point in time.

Our goal was to learn a bit about personas, and then look at personas that have been created for the UX Akron group. We used empathy mapping to understand the thoughts and motivations each of those personas was experiencing as they were thinking “I’m considering going to a UX meetup”. We looked at our results and it led to some quick ideas on how the group is missing marketing opportunities, or might structure its messaging to better appeal to certain groups.

Overall it was a great night with a diverse group. I look forward to attending as a regular member, and hopefully speaking again in the future.

If you’re looking to learn more about a current design topic, let us know at info@coffeeandcode.com We’re booking speaking and workshop engagements now for Fall and Winter 2016.

Photos credit UX Akron & WOCinTech

Returning Simple Data with Tastypie

It’s not everyday that I find myself in the land of Python, but I recently started working on a project with a friend’s company to help them reach an upcoming deadline.

The project uses Tastypie to generate an API based on Django models, which works great! However, when I wanted to return generic data I ran into a bit more resistance than expected.

The API pointed me to Using Tastypie With Non-ORM Data Sources, though I was hoping for something less heavy handed. I didn’t want to make resourceful routes around a custom data source, I just wanted to return a simple json object.

I ended up with the following solution:

# Custom object that we'll use to build our response.
class CustomResourceObject(object):
    def __init__(self, name=None, label=None):
        self.label = label
        self.name = name


# The Tastypie resource that will return our data.
# Make sure to inherit from Resource instead of ModelResource.
class CustomResource(Resource):
    # You will need to add fields for each property
    # that will be returned in the response.
    label = CharField(attribute='label', readonly=True)
    name = CharField(attribute='name', readonly=True)

    class Meta:
        # Start by disabling all routes for this resource
        allowed_methods = None
        # Allow the `get` index call where we will return data
        list_allowed_methods = ['get']
        # Use the custom object we created above
        object_class = CustomResourceObject
        # API endpoint for this resource
        resource_name = 'custom_endpoint'

    # Create our array of custom data
    def get_object_list(self, request):
        return map(lambda val: CustomResourceObject(label=val[0], name=val[1]), DjangoModel.CHOICES)

    # Return our custom data for the API call
    def obj_get_list(self, bundle, **kwargs):
        return self.get_object_list(bundle.request)

Photo via Visual hunt