thoughts Nico Killips thoughts Nico Killips

Vodori Final Day

Being a Vodorian has been an honor, and a pleasure. To say that Vodori has some of the most talented people I've ever worked with is a gross understatement.

Today is my last official day at Vodori. I'm feeling the rush of support from my co-workers as I embark on the next part of my journey. This makes it all the more bittersweet for me.

Being a Vodorian has been an honor, and a pleasure. To say that Vodori has some of the most talented people I've ever worked with is a gross understatement.

Thank you to my co-workers and friends! I will miss you all, but I'll be back to visit soon! Until next time.

Read More
thoughts Nico Killips thoughts Nico Killips

Vodori Retrospective

My role evolved from "markup producer" to nearly full-fledged "front-end developer."

My departure

I've had a great run here at Vodori. I've been here for a year and change. My role evolved from "markup producer" to nearly full-fledged "front-end developer". I even tried my hand at project management (thank you, Scott giving me a chance)!

However, the universe was giving me chances that I would regret passing up.

I've learned a lot

To say I've learned a lot while working here would be a gross understatement. Through my project work, consulting others, and being consulted, I've greatly grown my skills in:

  • Javascript
  • CSS and Preprocessors
  • HTML
  • Git
  • Atlassian Product Suite
  • Agile Methodology
  • Cross Browser Optimization
  • Graceful degradation
  • Mobile Device Optimization

Bittersweet

While I'm excited about what's next, it will be bittersweet to move out of Chicago. I've really enjoyed living here, and I've made some wonderful friends. It was great to be around such intelligent, talented, and driven people at Vodori. It was an invaluable experience that shaped my career, and life for the better. To anyone from Vodori that might be reading this, Thank you!

Read More
thoughts Nico Killips thoughts Nico Killips

Pre-processer Love

I've been working with preprocessors for a few years now, I feel good about sharing the features that I used the most and find the most useful.

There's no shortage of posts about preprocessors, and more specifically about LESS. Now that I've been working with preprocessors for a few years now, I feel good about sharing the features that I used the most and find the most useful.

Variables and Mixins

Arguably the two biggest reasons to use a preprocessor are variables and mixins. The power of these features are at this point well documented, and people have become very creative with their usage.

It's pretty common to use variables in the context of colors, values that are used frequently, and even for class names. It's just as common to use mixins as a way to pass variables into them like functions. However, the large scale project I worked on regularly in my last agency job pushed me to think creatively about how to use variables and mixins, and how to make them usable (something I had not considered before).

I've talked about how to use variables for established media queries. While this was very useful, it was only the start of how I would experiment with variables and mixins. Rather than thinking about reusing individual variables, I started thinking about how to reuse entire design patterns leveraging variables and mixins.

The Project Backstory

This large-scale project I keep talking about throughout my posts was truly gigantic. It is internationalized for over 20 countries, has a back-end system that pulls data from all over the place, displays data to the front-end dynamically based on very complicated information architecture, user interactions, and requirements. What Vodori has created in terms of a product for this client is truly amazing!

Now that we have glimpse of context around the depth, and size of this application, we can understand the need for identifying design patterns, and being able to reuse them.

Design Patterns?

As with everything in this space, "Design Pattern" means many different things to different people. In my case, I see a "design pattern" as a set of attributes, be it design, or data, that are reused in many contexts. Since I'm a front-end developer, I'll use an example of a visual pattern.

header {
  padding: 1em 2em;
}
section {
  margin-top: 3em;
  margin-bottom: 3em;
  padding: 1em 2em;
}
footer {
  margin-top: 3em;
  padding: 1em 2em;
}

In this case, we want the padding of the header, section, and footer to be the same, so our content is displayed consistently. The padding: 1em 2em line is an example of a design pattern because we are using it in multiple places.

Since we can recognize this as a design pattern, we can turn it into a mixin.

.content-padding() {
  padding: 1em 2em;
}

Now, we can reuse this design pattern without having to declare and remember the padding values. It's much easier to remember "content-padding". As a bonus, this type of modularity adheres to DRY!

/* Note: Even though we're not passing anything into the mixin, 
I still like to add the parens so it's easy to identify it as a 
mixin, pattern, or object */
header, section, footer {
  .content-padding();
}

The beauty of this approach is that if we discover a new design pattern that pertains to the "content-padding mixin, all we have to do is add it to one place!

The problem: for semantics, we may need to rename the mixin if the design pattern strays from whitespace. Or perhaps there's a better way. This would be a good time to talk about "Design Objects".

The problem: Patterns with different functions

When I was going through this exercise of using design patterns, I found that quite often, I would make a set of design patterns that were not related in function. Rules around whitespace, typography, and positioning quite often would get mashed together into a mixin that would get used in many places, forcing us to override them in edge cases. (Cringe)

The way we handle this is to go back to basics with Object Oriented CSS principles.

Object Oriented CSS Principles

The idea with OOCSS is to decouple rules into modular objects, which for CSS usage, are injected into the HTML. Since we're using LESS, we can use this same principle without injecting HTML classes.

Again, there are many ways to do this, but I have a general method for abstracting patterns. I try to not cross-pollinate these patterns so they can stay abstracted by function.

Typography: color, text-decoration, font-family, font-size, line-height
Positioning: floats, TRBL (top, right, bottom, left) positions, absolute, relative, z-index
Whitespace: padding, margin

Naming Convention: Slightly Modified BEM

Using a naming convention is critical in ensuring your code is scannable, intuitive, and maintainable. This is especially important when creating patterns and objects. The developer looking at this code needs to be able to see relationships between patterns and objects at glance, without too much explanation. (Although, writing comments is extremely important too!)

I loosely adhere to the "Block, Element, Modifier" naming convention (BEM) for naming classes. This methodology was designed for large applications (althought it works very well for smaller projects too), and I can attest that this method works very well in that context. Here's an example of a slightly modified version of BEM:

/*"content-section" is the block with dash separating words, and "typography" is the modifier */
.content-section--typography();

/*"content-section" is the block with dash separating words, and "positioning" is the modifier */
.content-section--positioning();

/*"content-section" is the block with dash separating words, and "whitespace" is the modifier */
.content-section--whitespace();

Patterns and Objects in Practice

Let's take the original example. Now we can see how the design patterns are making up the design object.

/* The design object */
.content-padding() {
  /* The design patterns */
  padding: 1em 2em;
}

header, section, footer {
  .content-padding(); /* The design object */
}

Now, let's say we want to add more patterns to the design object. Let's add some typography patterns that we can reuse. Now that we're creating patterns with different functions, let's rename the patterns so they are more semantic.

/* Variables */
@brand-font--primary:       'Open Sans', Helvetica, Arial, sans-serif;
@brand-color--body-copy:    #4a4a4a;

/* Design Patterns */
/* Let's keep the .content-padding() but use it as a design pattern, not a design object. Also, let's rename it to something more semantic and appropriate.
*/
.content-section--whitespace() {
  padding: 1em 2em;
}

.content-section--typography() {
  font-family: @brand-font--primary;
  color: @brand-color--body-copy;
  font-size: 1em;
  line-height: 1.75em;
}

/* Design Object */
.content-section--patterns() {
  .content-section--padding();
  .content-section--typography();
}

header, section, footer {
  .content-section--patterns();
}

Patterns as objects

You might thinking: this is too granular! You might be right. On some cases, it might be too risky to add all the patterns into one object. In this case, we should use our patterns as objects.Essentially, all the patterns are objects and can be used as such.

Here's an example of using patterns as objects.

/* 
Instead of creating a design object, you could just apply the design patterns as individual objects.

You may need to do this in some cases, especially in the case of pattern variation.
*/
header, section, footer {
  .content-patterns();
}

/* The Sidebar has slightly different typography rules, but the same padding rules

We can apply the padding design pattern, but apply different rules for the typography
*/

/* Let's hash out those typography rules as a new pattern. */
@brand-color--sidebar-body-copy: #cccccc;

.sidebar-typography() {
  font-size: 0.85em;
  line-height: 1.25em;
  color: @brand-color--sidebar-body-copy;
}

aside {
  .content-padding();
  .sidebar-typography();
}

We could have wrote rules for sidebar typography, but it's smarter to convert the set of typography rules into a pattern so we can reuse it later if we need to.

Be careful! I strongly recommend not reusing patterns if your intent is to only use some of the rules. This breaks the idea of a pattern, and causes messy situations where you have to override.

.content-padding() {
  padding: 1em 2em;
}

.content-typography() {
  font-family: @brand-font--primary;
  color: @brand-color--body-copy;
  font-size: 1em;
  line-height: 1.75em;
}
/* ---------------------------
Don't do this!
--------------------------- */
aside {
  .content-padding();
  .content-typography();
  /* The content-typography has most of the rules I want, except for the color. */
  color: red;
}

While it may be trivial in this example to override one of the design pattern rules, this way of thinking can lead to messy overriding problems that can be difficult to keep track of, and or troubleshoot. This is especially true when working in a large application.

A Learning Experience

Aside from using mixins and variables to make patterns and objects, the exercise of pattern recognition has a lot of value. Working with designers in the beginning stages of projects to uncover these patterns greatly improved my development workflow, and understanding of OOCSS.

Read More
thoughts Nico Killips thoughts Nico Killips

My First Large Scale App Experience

Since my development career began, I had the itch to contribute to a large-scale app. I had no idea what was in store!

Since my development career began, I had the itch to contribute to a large-scale app. You know? The kind that involved a big team, lots of meetings, deep coordination. Reading about it intrigued me, but it wasn't nearly enough to prepare me for what was in store.

I got my chance to work on my first large-scale, international, fully responsive web app while working at Vodori. Not only did I learn a lot about my own craft, experimenting with different media query objects, using custom breakpoints, and even ways to structure our file imports, I also learned a lot about how a large app is managed. Below are some of the key components.

  • Budget
  • Staffing
  • Timeline
  • Process
  • Client Dynamic
  • Business Goals
  • Budget

Being a medium-sized company, and having a good long-standing relationship with the client, the leadership team was able to procure a contract that had a large enough of a budget to comfortably include a team of developers, designers, project managers, and business analysts.

Budget plays an important role in the consideration of how to approach responsive design in that it determines how to phase the development. With a small budget, you may have to optimize in phases. One approach could be to optimize for the two most important viewports (based on analytics and business goals) first, then in another round of funding, perform the remainder of the optimization.

Staffing

The exercise of knowing how many people you need, for how many hours of the work week, while maximizing capacity is no easy task. Vodori was (thankfully) able to hand-pick people for various roles. Although, throughout the project, we were seeing people being very cross-functional and stepping outside of their traditional roles in order to keep the project moving (a truly awesome thing to see).

A lesson learned about staffing in my experience at Vodori was to involve the right people at the right time. As an example: involving front-end developers at the beginning stages when the Experience Design (XD) team was crafting mood boards, mockups, interactive prototypes, information architecture, and making user experience decisions would have saved a lot of time, and budget.

This was a classic case of "staff chunking", where you have different discipline teams working in a silo, then hand off their work to another discipline team, without any further interaction. It makes complete sense to do this when planning such a large project, however after executing it, we learned that if we had allocated time a bit differently (disciplined teams spending their time across the project instead of in one large chunk), the project would have gone more smoothly.

Timeline

The work was slated to be completed within a matter of only a few months. This timeline was quite aggressive for a website of this scale and complexity.

Similar to budget, the timeline plays an important role in how to phase the development. The timeline also can drive the decision to use a framework, or to build one from scratch. It's also worth discussing with the client whether the timeline is arbitrary, or must be set in stone. Hard-fast deadlines that are close in calendar time may warrant using a responsive framework, and other pre-build components.

Process

Webflow

The XD Team, while being well-versed in the vocabulary and considerations of responsive design, did not have a lot of practical experience with it in the context of a large-scale application. (None of us really did!) We all had a lot to learn, and quickly! We thought that one way to get over that learning curve a little easier was to use Webflow to create responsive and interactive prototypes.

Our first thought, to save on budget and stay on target for our deadline was to bring in Webflow's frontend code into the production environment. Being the middle-man between the XD team and the developers, I made the mistake of bringing in Webflow's HTML and CSS into the project and going through the exercise of parsing what we needed and purging what we didn't.

While we were able to get templates off the ground quickly, we ran into trouble when we had to make tweaks to the HTML and CSS. The project specific CSS imported from Webflow was quite verbose and bloated, which made it difficult to find the classes/selectors we needed to modify, without affecting something else. Regression city!

The verbose and non-semantic markup was part Webflow's default CSS being bloated, and part a result of our XD team not having enough knowledge (or time!) with coding best practices. This was was not their fault. In retrospect, we should have used Webflow's CSS/HTML as a guide for development: cherry picking CSS rules we needed while writing our own HTML and class names.

Working in Silos

Working with an aggressive timeline, and with seemingly endless JIRA tickets, our developers were working in silos. In retrospect, the team would have benefitted from more interaction to solve some of these very complex front-end, and back-end puzzles. (While the back-end was very complex, it was planned in a way that made it easier to get off the ground. The front-end work ended up being the larger time-sink.)

There were many instances where I needed a sanity check to see if that code that I had been working on for nine-straight hours was viable. Unfortunately, this did not happen, and as a result, I had to go back and refactor many lines of code when I came back to it the next day with a fresher mind.

As an example: About four hours into the development of a feature, I wanted to discuss an approach with another developer before I submitted it for a pull request. Unfortunately, our team had no availability (even to block out fifteen minutes!), so I spent another four hours finishing the feature and submitting the pull request. I was hoping our tech lead could guide me through any revisions within the pull request dialogue, but she was also unavailable (this was not her fault as she's overseeing this gigantic app, while being in meeting for most of the day). She ended up coming over to my desk and informed me about another feature that was being implemented, which would make my code problematic. (I'm amazed that she had enough time to even do this! I consider myself lucky because most tech leads do not have the same level of awareness with such a large app. She's awesome! :))

Turns out, if I would have known this when I had originally asked a developer for a consult, I would have saved four hours of development time.

Now, I'm not blaming anyone for this inefficiency. In fact, the team I worked with was truly fantastic and awesome to work with. It's nobody's fault that the work was done so siloed, and from a project planning perspective, it was the best option we had. However, I do feel as though we, as a team, could have implemented a workflow that allowed for more internal consulting time. What I took away from this was that it's important to plan for developer to developer consulting time. In this case, it would have saved me four hours!

Client Dynamic

Our relationship with the client was generally very positive. We had been working with this client for a long time (about 8 years). However, this client was at times not very easy to work with, for many reasons (multiple stakeholders, lack of consolidated opinions/direction).

We ended up conceding on a number of design and development approaches, mostly because we weren't able to educate them on certain aspects of the project (time constraints as a result of staying on budget and timeline). The other reason we ended up in this boat was because we were working with a third party that was developing the ecommerce component of their product in parallel with the main app that we were building. This agency had strong opinions about certain technical implementations and were able to push their weight around to influence certain aspects of the project.

While we were working on two completely different apps, both parties had to ensure that our technology and design decisions were aligned since these two apps were under the same brand (rebrand). This proved to be very challenging when it came down to the approach for responsive implementation. It was difficult to coordinate on how we were changing elements on different viewports, but our Project Managers did a great job of communicating these strategies, and helping to come up with compromises on both ends.

Unfortunately, these types of politics will come with the territory, especially on larger projects. What I took away from this was that it is important to understand the client dynamic early on, and to plan for interactions that involve taking a firm stance, and to remind the client that the decisions made are for their benefit.

Business Goals

I've talked about the importance of knowing your client's business goals as a developer. This was especially important for this project and client. The approach to responsive design, and development was created based on the business goals: "we want an immersive experience that tells the story of our brand, while providing a simple path to purchasing our products." This is of course a summation, but it was a good high-level concept to keep in mind during development.

One example of how we approached development based on the client's goals:

Back story: The topic of conversation and contention was around a particular element on the site: A container that exists at the top of most pages that contains a hero image, a heading, and in same cases: a subheading with calls to action. The third party vendor was in favor of dropping text below images on smaller viewports to allow for more text. We felt differently. This was my stance, and defense of implementing an approach to keeping text on top of images, and to maintain this design pattern even as we experience the site on smaller viewports.

We believe that part of creating a system is having parameters around more than just data, but also having parameters around maintaining design integrity. Allowing a variable amount of text in the hero container compromises the integrity of the design. To better understand why we feel this way, let us explain the design process.

As we went through the process, we were finding that the vision we were striving for depended heavily on the combination of compelling imagery matched with rich copy. In order to create that immersive experience, we needed to ensure that the all the content was working together in way that would tell the brand story. In many cases, letting the image scale down across viewports, and dropping the text below the image did not lend itself well to that vision, so we decided to take the more difficult development path in order to deliver this vision. While this was a more difficult path from a development perspective, it actually opened up more doors for design.

The other topic of conversation was around a method of cropping we utilized for maintaining a central focal point for images that are implemented with the img tag. We were using css to center the focal points of key images in certain templates across our required viewports. Again, the third party vendor took issue with this approach, stating that it was too difficult to maintain and it would be easier to change the layout of the templates so that the image is displayed fullwidth, and shrinks down naturally with the browser/device. Again, this was an issue because some of the images had an aspect ratio that would render the image very short on smaller viewports. This was one of the reasons we decided to go with cropping instead of scaling. We explain:

Using our image cropping method allows for more flexibility in how we display our content. As an example, one of our design patterns is that we use min-heights on containers of content in order to provide enough whitespace for the copy to breathe, and to have control over the visual weight of the background imagery. The background images (among many other components) play a very key role on how the user digests the content. If we have control over how large the images are across our viewports, we can more effectively tell the story.

In the end, the client went with both maintaining the text over image design pattern, and our cropping approach. (hoozah!) While it took a little bit more development work, it ended up aligning with their business goals, which the client greatly appreciated. This example shows how if you map your decisions with your client's goals, you have much more ground to stand on.

Being a Team Player

When the deadline approaches, and the days get longer, it's important to be a team player. As an example: one of our project managers offered to take on some of my own project management work (for a different client) in order to free me up for development work (you rock, Dan!). This allowed me to be heads down on some of the development work that would have been difficult to finish quickly had I tried to balance both the PM and Development work.

The Large Takeaway

Working within a team for an application of this size is totally different than smaller projects. What I learned:

  • There are more stakeholders
  • More team members
  • Organization and workflow planning is very important (it's borderline disastrous to ad hoc!)
  • Communication between developers is critical
  • Plan for for internal consultations between all disciplines
  • Involve developers in the processes of establishing design, ux, ia, and wireframing early on in the project. If you, as a developer, feel you should be part of meeting, find a way to inject yourself!
  • Be mentally ready to deal with politics. Things will not always go the way you want!
  • Read up on all the documentation related to the client goals and relationship with your agency
  • Don't be afraid to ask a lot of questions!
  • Be Patient! Project managers, tech leads, and business analysts have a lot on their shoulders. Be cognizant of this.
Read More