Sarah Drasner – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Mon, 04 Oct 2021 21:38:20 +0000 en-US hourly 1 https://wordpress.org/?v=6.4.3 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 Sarah Drasner – CSS-Tricks https://css-tricks.com 32 32 45537868 New Nuxt Features past v2.10 https://css-tricks.com/new-nuxt-features-past-v2-10/ https://css-tricks.com/new-nuxt-features-past-v2-10/#respond Fri, 06 Aug 2021 15:43:44 +0000 https://css-tricks.com/?p=346290 Nuxt offers an incredible developer experience, with a lot of performance and application setup best practices baked in. In recent releases, they’ve been working on taking this developer experience to the next level, with some newer features that speed up …


New Nuxt Features past v2.10 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Nuxt offers an incredible developer experience, with a lot of performance and application setup best practices baked in. In recent releases, they’ve been working on taking this developer experience to the next level, with some newer features that speed up and simplify developer processes. Let’s explore some today.

I set up a repo and site for you to explore some of these features! You can check them out here:

A recipe page for crab cakes with red pepper. The recipe directions and ingredients are noted on the left and a featured image of the finished dish on the right.

Nuxt Content

You no longer have to pair Nuxt with an external headless CMS and do all of the setup, particularly if you’re not looking for something at a huge scale, but something smaller like a blog. Nuxt content offers a git-based headless CMS where you can write configuration in markdown, CSV, YAML, or XML, based on your preference. There are some out of the box configuration settings available to you, and writing custom configurations is as simple as creating a property.

What this means for development: you can write static Markdown files in a directory, and that can be your blog! We’re using the same dynamic pages API that you would typically use in Nuxt to generate this content.

It also offers full-text search out of the box, which is a lovely feature to add so quickly to a blog without having to integrate a third-party service.

This tutorial by Debbie O’Brien is an incredible guide, it walks you through every piece of setting it up, highly recommended.

Nuxt Components

One thing I noticed I was doing again and again and again was typing import code in all my components. I do have some snippets to make this a bit faster, but adding them each in every file was still interrupting the flow of my work just a bit.

Nuxt component module scans, imports, and registers components, so that we no longer need to do this. The components must be in the components directory, but we can use them in layouts, pages, and components themselves. 

The addition of this module is a small change to our nuxt.config.js:

export default {
  components: true
}

Seriously, that’s it!

If you’d like a deep dive, this incredibly comprehensive guide by Kruite Patel has you covered.

If you use the component repeatedly, Nuxt will do some nice optimizations such as automatically creating a shared chunk for the component. Be mindful when using this on huge projects, though, as it may impact build times. 

Nuxt Image

Nuxt Image is a newer module that offers seamless and quick resizes and transforms for optimized responsive images. You can use their built-in optimizer, or work with 10+ ready-to-use popular providers such as Cloudinary or Fastly.

The code output from using their API are standard <img> and <picture> tags, so there’s no obfuscation when integrating them into your workflow.

After adding the module, you’ll be able to add configuration to the images via an images property in the nuxt.config.js, and designate breakpoints, providers, and other configurations:

export default {
  image: {
    // The screen sizes predefined by `@nuxt/image`:
    screens: {
      xs: 320,
      sm: 640,
      md: 768,
      lg: 1024,
      xl: 1280,
      xxl: 1536,
      '2xl': 1536
    },
    // Generate images to `/_nuxt/image/file.png`
     staticFilename: '[publicPath]/images/[name]-[hash][ext]',
     domains: [
        'images.unsplash.com'
    ],
    alias: {
      unsplash: 'https://images.unsplash.com'
    }
  }
}

This is just a sampling of some of the options available to you, provided as an example. The full documentation is here.

And then the usage is similar to any Vue component:

<nuxt-img src="/nuxt-icon.png" />

or

<nuxt-picture src="/nuxt-icon.png" />

Further information and all options are documented here. Hat tip to Ben Hong for letting me know this was available. He has a few Nuxt resources out there that are worth exploring, too!

Sample Repo

I’ve created a sample repo for you to explore that uses all of this functionality. It’s a small recipe blog with nuxt-content for the recipe entries, Nuxt components so that I didn’t need to define imports, and nuxt-image for the image transformations.

You can visit it here to see it all in action, fork it, play around with it, and make it your own.

You can see in it how I used the $img API in Nuxt image for background images here, too, which is not yet fully documented.


Nuxt offers incredible developer experience. Nuxt is even coming out with a new version soon with more updates, always expertly implemented. It’s why using Nuxt is continually such a joy, and proves to be a great framework for teams and single developers alike.


New Nuxt Features past v2.10 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/new-nuxt-features-past-v2-10/feed/ 0 346290
Good Meetings https://css-tricks.com/good-meetings/ Fri, 02 Jul 2021 14:41:26 +0000 https://css-tricks.com/?p=342995 Like it or not, meetings are essential to a good working environment and communication. Therefore, it’s crucial that we work on making them as productive as possible. Today we’ll explore myriad ways to keep meetings coordinated, well documented, and talk …


Good Meetings originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Like it or not, meetings are essential to a good working environment and communication. Therefore, it’s crucial that we work on making them as productive as possible. Today we’ll explore myriad ways to keep meetings coordinated, well documented, and talk about how to recognize and steer away from anti-patterns.

I’m timid to write this because I have not always hosted good meetings. I have, however, hosted thousands of them, so I’ve learned both from some mistakes and successes. In all likelihood, if you do any kind of management or lead work for a while, you’ll also see your own spectrum of meetings: meetings with different types of agendas and purposes, meetings with varying levels of awkwardness, meetings that didn’t have a formal outcome. We’ll dive into all of these in this article, as well as some tips for each.

The truth is, a meeting by its nature can almost never be perfect because it is by definition a group of people. That group of people will consist of different people: with different tastes, different opinions, different priorities, and different values. There’s a high chance that not everyone will agree on what a great meeting is. So half of the journey is aligning on that.

The Good, The Bad

One thing’s for sure: we can agree on what a bad meeting is. So let’s start by using that as a ballast:

  • There’s no clear purpose or direction
  • It feels chaotic
  • The wrong people are there
  • People are generally disrespectful of one another
  • Everyone feels it’s a waste of time

From those assertions, we can then derive what a good meeting is:

  • The purpose of the meeting is clear
  • There’s an agenda (we’ll dive in to the complexity of this in a moment)
  • There are the right people in the room. Not too many where communication is overly complicated, not too few where the people you need to move forward aren’t there.
  • There’s some order. People aren’t dropping in and out, talking over each other, or being generally inconsiderate
  • There’s a clear decision, outcome, and next steps at the end

Purpose of the Meeting and Direction

The first point and the last are connected: to have a good meeting, there is a core. You’ve all come for a unique purpose, and the end of the meeting should encapsulate what you’ve learned about that purpose and what the next steps are. Thus, the beginning and end of the meeting might sound a little similar:

We’re all here today to discuss how we’re going to support the next version of framework X. I have some new data to show you that frames the direction, Hassan and Jenna are here to talk about some of the details of the implementation, and Angela, we’d love to coordinate with you on a rollout process because it affects your team.

And at the end:

OK, so we decided we’re going in Y direction. Angela, your team seems comfortable doing Z, is that correct? And the rollout timeline we’ve agreed on is 5 weeks. The next steps are to explore the impacts of A, B, and C and reconvene in a week on our findings and process.

This is just an example—it’s not important to model this precisely. But you should be aligning at the beginning and end of the meeting to make sure that nothing major is missing and everyone is on the same page. If you haven’t come to a decision by the end of the meeting, then your next steps may be either to figure out who will make the decision and inform everyone or roll over to a new meeting.

Ideally these sentences are encapsulating information everyone needs:

  • The shared purpose
  • What you’re doing about getting to that outcome
  • Who is owning what
  • How
  • When, what are the timelines

If there are people there who do not need to know this information, they probably shouldn’t have been at the meeting in the first place.

The Agenda

Beyond deciding that a meeting should have an agenda, there are so many ways and means an agenda can be used. Strangely enough, an agenda can also be a way to not have a good meeting, so let’s explore that, too.

An agenda should ideally always state the purpose of the meeting. I personally love to then include some bullets as talking points, as well as space to take notes right in the document during the meeting.

Sometimes people use an agenda to write thoughts down before the meeting, and I would strongly suggest you steer clear of this—there’s nothing wrong with a person keeping notes for themselves for the meeting but if you come to a meeting where an agenda is locked top to bottom with material, it can sometimes shut down the collaborative aspect of the meeting—which means it shouldn’t be a meeting at all, it should just be a shared doc, to be consumed async. Part of the purpose of the meeting is the discussion itself. Again, louder:

Part of the purpose of the meeting is the discussion itself.

Not all meetings are the same

There are also different kinds of meetings. Let’s go over what type of agenda you might use for each:

Brainstorming session: perhaps you don’t want a full agenda, just the purpose and a notes section, or even a Miro board or other whiteboarding tool to use for capturing people’s thoughts, with small areas stubbed out.

Weekly discussion or daily standup: I typically have folks add whatever they like to ours, prefacing their contribution with their name and a small category, for instance, RD for rapid decision, D for discussion, and P for process. Here’s an example:

- [Sarah, RD] should we block off 4 hours to triage our iceboxed issues?

Our team uses a kanban board during the standup and people take turns talking about what they’re doing for that time period. It’s nice how it helps solidify the tasks and priorities for the week, and allows for some course correction if there’s accidental misalignment before the work is done.

We also talk about what was done or shipped in the previous week so we can celebrate a little. Especially on tasks we know took the person a long time or took a lot of effort.

We found through trial and error that twice a week check-ins suited us: once on Monday to kick the week off, and again on Wednesday to keep us aligned and the momentum going.

Cross-Functional meetings: This is one where a more formal agenda with some preparation can be really helpful, so that all parties have enough information about the purpose and what’s being discussed. If you have a lot of information, though, I would suggest creating a one-sheeter and sharing that ahead of time instead of adding everything to an agenda. Sometimes if I know everyone is too busy to read everything async, I will give the first 5 minutes to the group to read through the one-sheeter on the call so we’re all on the same page. People usually appreciate this. YMMV.

All this said, agendas are very useful, but I’ve seen strange culture arise from making strict rules around them. The point of the agenda and meeting is to collaborate on something. That point is nullified if folks are putting process ahead of that impetus.

The best cultures I’ve worked at use both meetings and agendas as tools for working together effectively- tools that everyone equally feels responsible for making useful.

All Kinds of Awkward

OK, you led a meeting! You gave people purpose, you set direction and timelines. But why was it so awkward?!

Not all forms of awkward are bad, really. There are different kinds of awkward, and some are quite natural, some are more harmful. Let’s analyze this for a moment, starting from most innocuous to something more insidious.

You all didn’t know each other well

The team I got to work with at Netlify was some of the silliest, most collaborative, and trustworthy groups I’ve ever had the pleasure of working with. We actively cultivated this culture and it was great fun. Every meeting started with goofing off and chatter. Then, when we got to business.

The meeting would flow effortlessly because we were all comfortable together. One time a friend in the People department asked “what do you do to break the ice with your team”, and I jokingly responded “ice? Our team? No… we don’t need that… maybe we should be frozen?”

Not all conversations are going to be like this. We knew each other fairly well and actively worked to have vulnerability together. If your meetings with other groups you don’t know well have awkward moments, that’s actually pretty natural, and nothing to be too concerned with. You can try to make conversation and that can help, but trying to force it too much can also feel a bit stilted, so just ease up on the guilt for this one. There’s nothing wrong with you, I promise.

There were too many people

During the pandemic, my husband and I would sometimes try to replace in-person dinner parties with zoom versions of the same. What we learned was they didn’t quite work at scale. When you have an in-person party with 12 or more people, everyone doesn’t really stay in one huddle together, they break off to smaller conversations. When we started hosting the zoom parties with smaller groups, the calls became more fluid, relaxed and comfortable.

There’s a certain scale at which conversation begins to feel performative because there are so many eyes on a person when they’re speaking. Meetings are very much the same. Try not to invite too many people to a meeting. If you are worried folks might not feel included unless you invite them, you can either mark them as optional or let them know you’ll be sure to tell them the outcome.

If you’re inviting too many people because there’s a company culture that everyone should be involved in every decision, that might be a sign of a wider issue that needs some solving. Companies at a certain scale start to have issues functioning if there is no clear understanding of ownership. If you’re inviting everyone out of fear of hurt feelings often, it’s likely not a problem with your meetings, and more a sign that you need some clarity. See the DRI section at the end of this chapter for more information on how to mitigate this.

There’s something people aren’t saying

This kind of awkward is probably the most harmful. If the meeting is awkward because people don’t feel comfortable telling the truth, or there’s an elephant in the room, or there’s a smell that needs to be dealt with. Elephant smells? Ok, moving on.

We should watch out for this and try to do something about it. Personally, I’m a “walk towards the fire to put it out” kind of person, and will actually just acknowledge that it’s awkward because it doesn’t feel like we’re being transparent with one another. I’ll state what I know from my perspective and then ask if other folks are feeling the same. 

If you do this, you’ll usually have to wait a beat or two. People will likely be a bit shocked that you came right out and said it. It will take them a couple of seconds to adjust and consider what will happen if they tell the truth, too. It’s crucial that you not speak to fill the silence in these moments. It will feel very uncomfortable, but I promise, you have to let the silence hang for a bit before someone speaks up. Typically from there, people will all start speaking, and you can actually dig into the problems.

Conflicts

There’s an entire chapter devoted to conflicts because the topic is big and nuanced enough to warrant its own time and space, but let’s apply some of the principles here, because there is an intersection of good meetings and dealing with conflicts directly.

The most important piece here is that conflicts are not something to be avoided. It’s not bad that people feel passionate about their work, it’s great. Not all conflicts are negative- the point of the meeting may be to bring to light where folks aren’t aligned. There probably is some base premise or problem they are all trying to solve, but they see the solution differently. It can help to find the alignment there so the ideas can be fleshed out without being attached to a particular person’s identity.

 The identity thing can be a pitfall, because if you have two people discussing their idea instead of an idea, it can feel to them like someone is rejecting them rather than a concept

We want to try to guide towards an approach where it doesn’t feel like anyone is attacking one another, and also manage actively against people being disrespectful to one another. It’s the job of a manager to disambiguate healthy conflict from attack so that respectful discourse is encouraged. If folks are putting out ad hominem attacks, it’s on you to reel that in and move the conversation towards the work instead. Otherwise, it really is hard for the conversation to stay productive.

Typically I’d say it’s good to hear people out, and then reign things back in by discussing what you think you’re hearing and tying it back to a shared purpose. Then we find where we have common ground. Here’s an example:

“What I’m hearing is that Rashida feels that team X is migrating a system that affects her team while they are trying to release a big feature. Is that correct? And that Jerome feels that it’s crucial that team X be able to migrate the system soon for stability purposes. Is that correct?

“OK, well, it sounds like we have a shared goal of making sure the company can ship features with some stability. Perhaps we can talk through what timelines are immovable and which are not so that we can stay coordinated?

“I’m sure we all want to be able to ship said feature without any hiccups and also get the new system up and going”

Here, we stated what we thought we were hearing, which allows for the person to either feel heard or correct us if we’re mistaken and there’s a miscommunication. (Sometimes there is!)

Then we stated the shared goal from both parties, as well as risks and constraints that may play a part in some of the conflicts that need to be ironed out.

You’ll note in the last sentence, we try to tie a knot for a vision of stability that addresses both of their understandable needs.

A couple of things to note: I’m giving an example here and you absolutely don’t have to do it like me. The most important thing is that folks feel heard and that you all agree on what the conflict is. And that you remain open to that discussion, while finding the base premise of why you’re even talking about it.

It’s also way easier said than done. If you have a conversation that goes off the rails, I’d suggest spending a bit of time after you’re off the call to write down what you think happened.

I tend to give myself a section to just talk through the facts of what happened, and then another to talk through my feelings of what went poorly and what could have been better. It helps to check in with the facts separately because our human brains can sometimes try to protect us and see a particular version of an event. Hard to do, but checking in with just the facts helps ground that a bit.

There can be times where a strong conflict happens during a meeting and you’re at an impasse, and you need to give folks time to regroup. I’d suggest calling another meeting in a week as a follow up, and try to hear people out individually in the meantime. Sometimes people need a little distance from a matter, or they’re having a hard day, and that’s totally ok.

The DRI

The DRI stands for “Directly Responsible Individual” and is one of the most important pieces that we haven’t covered yet. A good meeting must have a DRI, and it is not necessarily the person who called the meeting. It might not be you. But you must designate who owns the project and ultimately makes decisions when there’s one to be made.

Why do you need a DRI? Well, as much as you do want to hear input from everyone, eventually you have to make a decision, and there are plenty of things in software development that don’t necessarily have one true answer.

Note that the phrasing is not PWMD (Person Who Makes Decisions) though that acronym looks pretty hardcore. Instead, we use Directly Responsible Individual because that’s also core to deciding who this person is. They are the person who is going to own the outcome.

That’s part of why not everyone can get equal say- if it’s your project and you are on the line for the outcome of whatever decisions are made, you can see how you would also need to own decision making. And likewise, if people who have no skin in the game decide things, they might not understand all the moving parts or invest as much in the gravity of the matter.

The appointment of the DRI not only unlocks the groups to make final decisions and move forward, but also places the responsibility on the party that will carry the weight.

There are several systems of ownership you can explore, such as DACI, which separates out Driver, Approver, Contributors, and Informed so that everyone knows their roles, and several others such as RACI and RAPID. Use whichever system makes the most sense for your organization.

I find it best to identify this person early on in a project and make sure it is restated at the start of a meeting (it can be included on the agenda as well), as it helps greatly if you find yourself at a crossroads. This person can unblock you and help the group move forward.

Moving Forward

It may at times feel like meetings are a drag on a software engineering process, but it doesn’t always have to feel this way. There’s something special about collaborating with a group of people who are respectful and working towards a common purpose. Good meetings can provide clarity and save people hours and days of work when they’re headed in the wrong direction. Having clear ownership, documentation, and only the right people in the room can keep many teams in lockstep, even when problems are complex.

Buy the Book

This is just a sample of the kind of content from my latest book coming out soon…


Good Meetings originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
342995
Your Team is Not “Them” https://css-tricks.com/your-team-is-not-them/ https://css-tricks.com/your-team-is-not-them/#comments Wed, 28 Apr 2021 19:35:32 +0000 https://css-tricks.com/?p=338885 This post was written for engineering managers, but anyone is welcome to read it.

Let’s talk for a moment about how we talk about our teams. This might not seem like something that needs a whole article dedicated to it, …


Your Team is Not “Them” originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
This post was written for engineering managers, but anyone is welcome to read it.

Let’s talk for a moment about how we talk about our teams. This might not seem like something that needs a whole article dedicated to it, but it’s actually quite crucial. The way that we refer to our teams sends signals: to stakeholders, to your peers, to the team itself, and even to ourselves. In addressing how we speak about our teams, we’ll also talk about accountability.

I have noticed shared similarities in those folks I consider good managers whose teams deliver well, and those who don’t. It starts with how they communicate about their teams.

Your team is “we”

There can be a perception that as a manager of an organization you are in control at all times. Part of that control can invariably be perceived as how you appear to be in charge, are competent, or how you personally perform. Due to that, some bad behaviors can arise- not due to malice, but due to fear. For this reason, it can be tempting to take credit for success and avoid credit when there is failure.

The irony is that the more that you try to hold on to these external perceptions, the more it will slip away. Why? Because the problems you are solving as a manager really aren’t about you.

Your team is “we”. You are a driving force of that team, no matter how high up the hierarchy chain. What happens on that team is your responsibility. When you speak about your org, you should include yourself in the statement.

When your team succeeds in something though, then you can praise them and leave yourself out of it. Here’s an example:

They really pulled this project over the line, despite the incredibly tight project timeline. Everyone showed up and was driven throughout the engagement. They did a fantastic job.

However, if the team failed at something, the pronoun is then I:

I didn’t recognize how tight this turnaround was and failed to prioritize the team’s time well. I need to reconvene with everyone so we can come up with a better plan.

And never, ever them:

They didn’t adhere to this tight timeline. They just weren’t able to get this project over the line.

Do you see how the last example shirks responsibility for what occurred? Too often I will hear managers relieve themselves of their duties when shit hits the fan, and that is exactly when a manager needs to step up, and dive in to the problems that are their responsibility.

Photo by Marvin Meyer on Unsplash

The wider organization

There is another piece of this too, and it impacts how your team operates. It’s that your job is not to be the ambassador of who you manage and think of every other group as separate. You’re part of a larger system. A company is composed of groups, but those groups can only be successful if they’re working together, not if they are protecting their own org at all costs.

I admit I didn’t fully understand the depth of this until I read Patrick Lencioni’s great book The Advantage, thanks to Dalia Havens, a peer at Netlify. In the book, Lencioni talks about how organizational health, not “being smart”, as the biggest key to success. Plenty of smart people with good ideas build companies and see them fail. Success lies in being able to work together.

Fundamentally, other groups at the company are not separate from your group, rather that you’re all part of one whole. The Leadership Team is also a team, and should be treated as your team. How you speak about this team is equally important.

As such, when we talk about successes and failures of any groups, these should also be shared. There should be a sense that you’re all working towards a common goal together, and every group contributes to it. Within a leadership team there should be trust and vulnerability to own their part so that the whole organization can operate at its best.

And, yes, the leadership team as well

You may see where I’m going with this: when you talk about the leadership team, this is “we” too. You can’t speak to your team about decisions that were made at a table with your peers and boss and say “they decided something you don’t agree with” even if you don’t agree. You were there, ideally you took part in that decision, when you talk about that team, presenting them as “we” is important as well.

Why? Because as a manager, our job is to try as much as we can to drive balance and clarity. It’s confusing and disorienting to hear a manager talk about a leadership team they are on as though they aren’t a part of it and not take accountability for what’s happening there. Your reports themselves can’t effect change at that level, so if you don’t own your involvement in the leadership group, you can demoralize your staff and make them feel distrustful of other parts of the company. This can have an effect where folks demonize other teams and their initiatives, which as we discussed is ultimately unhealthy.

Saying “we” holds you accountable to your team for leadership decisions that you are a part of, which is how it should be. If people on your team have issues with the direction, it’s also your responsibility to own that conversation and next steps, as a liaison to the leadership team.

There are of course, some small instances when this might not be appropriate. Something that really goes against your core values that you fought strongly against can make this untenable. I would say those instances should ideally be very infrequent, or unfortunately you may need to pursue another place to work.

Speaking about the Leadership Team in Practice

Here’s how this works in practice, using an example of conveying a decision at the leadership level to the people who report to you:

The leadership team decided that we need to ship at least 3 features this quarter so I guess that’s what we have to figure out to do.

Versus:

One of the key OKRs this quarter is that we as a company need to double the signups to our platform. We’ve done some calculations that show we can almost certainly get there by shipping 3 features, so let’s all talk about what we can do within our group to make that possible. If you’re curious, we can chat through what initiatives other groups are doing to support this as well.

The first is not just passive, but demotivating. I have made the mistake of using this approach when I want to be liked by my employees and for them to think of me as a peer. But we’re not peers, I have a responsibility to them.

You’ll note in the second approach, we also explained the reasoning behind the decision. I’ve noticed personally that when I have to hold myself accountable to the decision, I care a bit more that people understand the reasoning behind it. This is a very good thing for the morale on your team! Which is arguably one of your most important jobs.

The last line in the second approach also opens up discussion- since you’re taking ownership of the decision, you’re also owning that you know about other pieces of the puzzle, and show a willingness to dive in with your team.

What if you make a mistake?

We all do! Management can be difficult and it’s impossible to be perfect all the time. Try not to beat yourself up, but perhaps show a bit more thoughtfulness next time. I’ve made lots of mistakes as well. It’s not a stick to beat up yourself or others, but a lesson learned to be as mindful as possible and promote a better working environment.


We communicate to our teams, peers, and stakeholders whether or not we’re taking responsibility as a true leader in these moments. We communicate whether we’ll approach a problem with humility, and a desire to collaborate and improve. This may seem to be a detail, but it’s a powerful piece of leading an organization.

Buy the Book

This is just a sample of the kind of content from my latest book coming out soon…


Your Team is Not “Them” originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/your-team-is-not-them/feed/ 6 338885
The Importance of Career Laddering https://css-tricks.com/the-importance-of-career-laddering/ https://css-tricks.com/the-importance-of-career-laddering/#comments Thu, 15 Apr 2021 14:29:18 +0000 https://css-tricks.com/?p=337830 The title of this article is misleading. It’s not actually very important for an Engineering Manager to use career laddering, per se, or my process. It is, however, very important that an Engineering Manager is clear with their employees


The Importance of Career Laddering originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The title of this article is misleading. It’s not actually very important for an Engineering Manager to use career laddering, per se, or my process. It is, however, very important that an Engineering Manager is clear with their employees about what their expectations and direction, not to mention where they are in terms of a raise and promotion.

I’ve personally found that career laddering can help with this, but is only one small supportive piece of a whole. You can have formalized career laddering in place and still mislead your staff, so it’s critical that career laddering docs are just one tool embedded in a deeper process.

What is a career ladder?

Before we dive any further, let’s clarify first what we mean by a career ladder. Career laddering is typically a system used to show what expectations are at different levels of a role, a purpose of which is defining how one might be promoted. This can have different forms, but tends to be an internal document that states the expectations of a staff member at any given stage of their career.

Here is a microsite where I open sourced all of my career ladders >

As you can see in the site, it outlines each of the different levels of the job, as well as the roles and responsibilities expected at that level. In this particular example, there is a basic concept that ties the whole thing together:

  • To get to Senior, you’re the best “you” you can be — you perform your role exceedingly well and you’ve reached a high potential for your own output.
  • To get to Staff, your focus is really to expand beyond yourself. You start teaching people the great things you learned and help serve their needs.
  • To get to Principal, you’re creating systems that scale beyond yourself. You’re no longer helping folks be like you — you’re helping them where they are. A lot of your activities are enabling the success of everyone around you.

What I like about this system is that the job of the most advanced folks becomes helping support and grow other people or system in such a way that benefits everyone. Principal-level folks don’t lord knowledge over others; they work to put the knowledge into practice in a way that’s truly helpful.

Again, it’s not important that you use my exact system, but I want to show that having clarity about the roles and expectations of each team member can really go a long way. Why? Let’s dive in.

Photo by Damian Zaleski on Unsplash

Clarity

“You can’t call yourself a leader by coming into a situation that is by nature uncertain, ambiguous — and create confusion. You have to create clarity where none exists.”

— Satya Nadella

I have never seen employees more demoralized than when they’re unsure where their career is headed and whether their title/compensation is fair. It’s frustrating, exhausting, and can lead to burnout. It’s also incredibly distracting — who can get their job done when they have no clue if what they’re doing is valued?

Some may ask about intrinsic motivation. You can have an employee that cares intrinsically about their work and still feels misaligned with the overall impact that the company sees in it. That’s often when the disconnect feels the most hurtful. If you have an employee who is working extremely hard and doing absolutely everything they can, the feeling of being undervalued can be heartbreaking.

Clarity with people about their level and being explicit about what they should be working on is critical. Transparency around timing for such a promotion cycle if you know it can help as well.

There’s a bit about trust in here, too. If you are working with someone on their growth path and trust that you will honor it, you enter into a sort of partnership.

Personally, I love it when the qualities you’re working on are things that would serve them anywhere, not just the company. These should be things that expand their skill set. These types of tasks typically take some long term work, but it can be very rewarding to work together on because there’s a larger purpose.

One thing is critical: if you guide employees on this journey, you need to give them the promotion at the end. The promotion is a change in title and compensation, of course, you break the bond of that partnership if you don’t follow through. Always give the promotion if that person has earned it on their end.

Putting career laddering to work

I mentioned that a career laddering document alone will not help drive a team, and I also mentioned the importance of clarity. So, let’s tie this all together and talk through how to use this in practice.

Photo by FLY:D on Unsplash

Step one: The big picture

I am one of those annoying managers who asks people where they’d like to be in five years. I call it “annoying” because it’s a lot to think about. But I still ask it, not because I’m not looking for a perfect answer, but because it gives them an opportunity to consider their future and, usually, they tell me something I should know.

Here are some examples:

  • I don’t really know what I want to be doing but I know that I don’t want to still be focused on build systems in five years.
  • I’m not really sure because I think I might want to be a manager, even though I haven’t tried it yet.
  • I want to be able to go camping whenever I feel like it, take my family with me, and work on the road.
  • I want to be sure that fellow developers in Africa have every opportunity they want.

Notice that these are not a formal outline for the next five years. But you can already get a sense of people’s values, their boundaries, and what we may want to incorporate as part of their working environment.

Step two: Career laddering review

If you don’t know where you are going, you might wind up someplace else. 

— Yogi Berra

In this step, we go through the career laddering doc. What I typically do is have an employee read out every list item in their current role to me, then self-assess the progress they’ve made on each item. I sound off a bit on it. We generally align; people tend to be fair and honest. I personally think it’s important that they read their list to me instead of the other way around, there’s a sense of ownership that way.

We also go over the next stage in their career and the list items for it. At the end of the process, we break down any common themes. For example:

You’re solidly a Senior, and doing quite well in your role. To get to Staff, you need to be helping others a bit more. Let’s make sure you have the time to be available for more PR reviews and pairing in the next few weeks. Let’s also talk about getting that internal tool you were building over the line, that would likely help the team move faster

Step three: 30/60/90

The next step I do is called a 30/60/90. The concept is that you break down the work you want to be doing in 30, 60, and 90 days. 

I tend to do this with a bit of a twist: We start with 90 days and ask: what would you like to accomplish here within the next three months? Since career laddering is fresh in their minds, there’s already some guidance on what their focus should include. It’s safe at this point to let them drive, and tell you what they should be doing instead of the other way around. 

Sometimes this can be quantifiable: 

  • Engineering: I would like to close five issues each week, ideally with at least two PRs.
  • Docs: I would like to address content gaps on two features.
  • Anyone: I would like to pair with at least two people.

It can be expressed as a metric:

  • I would like to help increase adoption of our npm package by 10%.

Or it can be less measurable:

  • I would like to try to understand our component library a little more as a newcomer.
  • I would like to try to interrupt other people less in meetings.

All of these are valid.

Photo by Christin Hume on Unsplash

Now that we’ve taken the time to define the 90 day plan, we figure out what’s doable in a 30-day period. Again, it’s up to them what they think they can accomplish in this time. I only chime in if I think they’re being too ambitious, or they are missing something that the company needs.

It can also be helpful to state that things change, and nothing in this plan is set in stone — other things may come up that need attention. We’ll adjust, it’s no big deal. I honestly don’t find the 60-day piece to be very useful because a lot changes in a month. I usually skip it, but you can absolutely use it if you find it helpful!

We also get to talk through what they shouldn’t be doing. If you find that something they are spending time on is not useful for the employee or the company, you may be able to remove the task and clarify this to other stakeholders. The employees themselves may not be able to have that conversation.

This can be incredibly useful for someone who may be an over-performer, but are burning out. It helps us align on the tasks that are overextending them so that they can properly prioritize and focus. It’s tempting to think that over-performers need less guidance but I’ve found that they tend to need more clarity, not less, so that we can define scope and help them set a good direction.

I’ve also seen under-performers turn around after the career laddering process. What one might see as a lazy quality in that person might actually be a symptom of being misaligned with the purpose of the tasks. A career ladder helps them recognize what, when, why and how the things they’re working on fit into the bigger picture.

Iteration and reflection

From here, it’s probably pretty clear what you do — keep revisiting the list! I try to set a reminder in our one-on-one doc to revisit the 30/90 plan in about a month. When we check in, we see how far they’ve come on each task, putting little checkmarks next to what’s done. I’ll sometimes put a celebration emoji on something they did particularly well — I believe it’s important to celebrate those as successes, even if it makes me sound like Mr. Rogers. Show folks that you appreciate their work and how far they’ve come.

From there, you can carve out another block for the 90, so they have direction for the next 30 days. If they didn’t finish something, carry it over to the next month.

Every few months, we’ll go back and do the career laddering exercise again, but this time denoting the progress that’s been made in every area. When they’ve filled their end of the deal of the things you asked them to work on, it’s time to promote them! 🎉 Don’t forget to celebrate that as well!

Wrapping up

This is not the only way to provide direction and clarity in a person’s work — the sky’s the limit. Anything that provides clarity for your staff can be helpful.

What I’ve liked about the career laddering process is that there are no surprises: people know where they are, and what it will take to get to the next level. There are no surprises in 360 reviews as far as what stage they’re at and what they should be working on between now and the next check in. The progress is a tangible thing that becomes a partnership between the both of you, and the work is just a unit within something measurable on that path.

It can be clarifying for everyone around: they know the system — there should be no surprises why a person is getting promoted at a given time. Hopefully that alleviates any tension in the process. 

Our collective aim as managers should be taking the careers of our employees as seriously as we do the team’s technical processes. Promotions ideally come exactly when and how everyone thinks it will. The goal is to set your team up for success: everyone has a good path forward and they can focus on doing work that is both impactful and rewarding.

Buy the Book

This is just a sample of the kind of content from my latest book coming out soon…


The Importance of Career Laddering originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-importance-of-career-laddering/feed/ 7 337830
Splitting Time Between Product and Engineering Efforts https://css-tricks.com/splitting-time-between-product-and-engineering-efforts/ https://css-tricks.com/splitting-time-between-product-and-engineering-efforts/#comments Mon, 05 Apr 2021 19:57:38 +0000 https://css-tricks.com/?p=337340 At each company I’ve worked, we have had a split between time spent on Product initiatives and Engineering work. The percentages always changed, sometimes 70% Product, 30% Engineering, sometimes as much as a 50/50 split. The impetus is to make …


Splitting Time Between Product and Engineering Efforts originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
At each company I’ve worked, we have had a split between time spent on Product initiatives and Engineering work. The percentages always changed, sometimes 70% Product, 30% Engineering, sometimes as much as a 50/50 split. The impetus is to make sure that Engineering spends a portion of their time building new features, but also ensures we can do “our own” work such as address technical debt, upgrade systems, and document our code.

The trouble is, it’s one thing to say this at the outset, and another to make it a reality. There are some reasons that I’ve seen this model fail, not because people don’t understand in theory that it’s valuable, but because in practice, there are some common pitfalls that you have to think through. We’ll cover some of these scenarios from the perspective of an Engineering leader so that we can address a good path forward.

The issues

Some of the pointers below are reactions and planning based on what can go wrong, so let’s talk first about the challenges you can encounter if this isn’t set up right.

  • Product may have conflicts, either with the work itself or the time involved. This can strain the relationship between Product and Engineering. If they are caught by surprise, you can potentially find the boundaries of your work getting more restrictive.
  • Your engineers might not understand what’s expected of them. Parallelization of efforts can be hard to do, so building a good process can provide clarity.
  • Maintenance path should be clear: Are you planning on making a giant system upgrade? This may affect other teams over time and if you’re not clear about eventual ownership, it could come back to haunt you. 👻

As nice as it is to have some freedom in your engineering time, communication, planning, and clear expectations can help make sure that you avoid any of the issues outlined above.

A group of people working
Photo by Akson on Unsplash

Communication

Once you figure out what problem you would like to tackle, it’s critical to write up a small one-sheeter that you can share with stakeholders on the nature of the work, the amount of time it’s going to take, and why it’s important.

If it’s a large project, you can also scope those pieces down into GitHub/GitLab/Jira issues, and add a label for the type of work that it is. This is great because you can use whatever project management system you already use to elevate the amount of work and expectations weekly. It’s good to keep the dialogue open with your Product partners on scope and the nature of the work so they aren’t surprised by other work getting done. This will largely vary by the culture of the team and organization.

This can help provide clarity for your Engineers, too. If they understand the nature of the work and what’s expected of them, it’s easier for them to tackle the small issues that make up a whole.

You may find that it makes less sense from a focus perspective to have every engineer split time across product and engineering projects. They may instead prefer to split the work up between themselves: three people on product work for a few weeks, one person on engineering work. There are also times where everyone does need to be involved so that they have equal institutional knowledge (migrations can be like this, depending on what it is). Your mileage may vary based on the size of the team, the amount of product work, and the type of project. 

Communication helps here, too — if you’re not sure what the right path is, it can help to have a small brainstorm as a group on how you want to get this done. Just be sure you also align everyone with why the project is important as you do so.

Types of projects

There are many types of projects that you can create in your Engineering team time, and each has slightly different approaches from what I’ve seen, so let’s go over each one of them.

Tech debt

Let’s address technical debt first because that’s one of the most common pieces of work that can unlock your team. For every feature you write, if Engineering effort is slowed, you’re not only losing time in terms of product development, you’re also losing money in terms of engineering time in salary.

A bit of technical debt is natural, particularly at smaller companies where it makes more fiscal sense to move quickly, but there are some points where tech debt becomes crippling for development and releases, and makes a codebase unstable. Sometimes it needs to be done immediately to make sure all your engineers can work efficiently, and sometimes it’s gradual.

In a lot of cases, the technical debt pieces are things you learn you need by a bottoms-up approach: the devs that are closest to working with the system will know best what day-to-day technical debt exists than Engineering Managers (EMs) typically will. The challenge as an EM is to notice larger patterns, like when many folks complain of the same thing, rather than one dev who may have a strong opinion. Asking around before you start this type of project can help — poll people on how much time they think they’re wasting in a given week vs the prospect of an alternative.

Sometimes technical debt is a matter of a large amount of refactor. I’ve seen this go best when people are up front on what kind of pull requests (PR) are necessary. Do you need to update the CSS in a million spots? Or convert old class components to hooks? You probably don’t want one huge PR for all of it, but it doesn’t make sense to break this work per-component either. Work together as a team on how much each PR will hold and what is expected of the review so you don’t create a “review hole” while the work is being done.

Two people looking at some code
Photo by heylagostechie on Unsplash

Innovative projects

A lot of companies will do hack week/innovation week projects where devs can work on some feature related to the company’s product untethered. It’s a great time for exploration, and I’ve seen some powerful features added to well-known applications this way. It’s also incredibly energizing for the team to see an idea of their own come to fruition.

The trouble with doing these kinds of projects in the split engineering time is that you can, at times, make the Product team feel a little slighted. Why? Well, think of things from their perspective. Their job is to put forth these features, plan carefully with stakeholders, put together roadmaps (often based on company metrics and research), and get on the Engineering schedule, usually working with a project manager. If you spend half your time working on unplanned features, you can potentially fork an existing plan for a project, go against some of the known research they have, or simply slow down the process to get a core make-it-or-break it feature they need.

The way I’ve seen this play out well is when the EM communicates up front with Product. Consider this a partnership: if Product says that a particular feature doesn’t make sense, they likely have a good reason for thinking so. If you can both hear each other out, there is likely a path forward where you both agree. 

It’s good to address their fears, too. Are they concerned that there won’t be enough time for product work? Ask your team directly how many weeks at half time they think it might take (with the expectations that things might shift once they dig in). Make it clear to everyone that you don’t expect it to be done at a break-neck pace.

Ultimately, communication is key. Ideally, these are small projects that won’t derail anything that can be done in parallel to the regular work. My suggestion is to try it with something very small first to see what bumps in the road there might be, and also build trust with Product that you’ll still get your work done and not “go rogue.”

The final piece of this is to figure out who is responsible for metrics, outcomes, and when things don’t go well. Part of the reason Product gets to decide direction is because they’re on the hook when it fails. Make sure you’re clear that as an Engineering leader, you’re taking responsibility for outcomes, both the good and the bad to maintain a good relationship.

Slow, ongoing work

This is probably the most clear-cut of any of the types of projects and will likely get the least amount of pushback from anyone. Examples of this type of work is internal documentation, tooling (if you don’t have a dedicated tools team), or small bits of maintenance.

The communication needed here is a little different from other projects, as it’s not necessarily going to be one constrained project that you ship, but rather an iterative process. Take documentation as an example: I would suggest building time for internal documentation into any feature process. 

For instance, let’s say you created a new feature that allows teams to collaborate. Not everyone across the company may know that you created a microservice for this feature that any team can use, and what parameters are expected, or how to add functionality down the road. Internal docs can be the difference between the service being used, as well as your team being asked to pair with someone every time someone needs to use it. Or worse: them trying to hack around and figure it out on their own, creating a mess of something that could have been worked on quicker and more efficiently.

Unlike the innovation projects, slow, ongoing work is typically not something folks really crave doing, so setting a process and expectations up straightaway works best. Internal documentation is a sometimes hidden but very important part of a well-functioning team. It helps with onboarding, getting everyone on the same page about system architecture, and can even help devs really solidify what they built and think through how they’re solving it.

Two women talking about something on a computer screen
Photo by Christina @ wocintechchat.com on Unsplash

Migrations

Migrations are handled a little differently than some other types of projects because it likely affects everyone. There is no one right way to do this, and will also largely depend on what type of migration it is — framework to framework, breaking down a monolith, and migrating to a different build process or server all may have different approaches. Due to the fact that each one of these is likely an article of its own, let’s go through some high level options that apply to the organization of them.

  • My first suggestion is to do as much research as possible up front on whatever type of migration you’re doing. There’s no way to know everything, but you don’t want to get part-way through a process to find out something critical. This is also helpful information to share with stakeholders.
  • Are there internal debates about what direction your company should head in? Timebox a unit of time to work through the problem and make sure you have a clear decision-maker at the end. A lot of tech problems don’t have one “true” solution, so having one owner make the decision and everyone else disagree and commit can help. But you also want to give a moment for folks to have their voices heard about what gives them pause, even if they are in disagreement — they might be thinking of something you’re not.
  • Document a migration plan, both at a high level and then work through the impact on each team. This is also a great time to explain to Product why this work is important: is your codebase becoming old and can no longer play well with other libraries and tools? Did a new build process come out that could save your engineers time in a release process? Help them understand why the work is critical.
  • Be clear about maintenance and ownership. If one team migrates a build process that then causes issues for another, who’s fixing things to unblock that team? You should decide this before it happens.
  • Some migration paths allow you do things slowly over time, or team by team, or do a lot of the work up front. However, there is usually a time when it’s going to be critical and all hands on deck are needed. Unlike some of the other work that can be parallelized, you may have to work something out with Product where all other feature work is stalled for a little bit while you get the new system in place. If you work closely with them, you may find that there are times in the season where you naturally have more of a customer lull, and it could give you the breathing room you need to get this done. I’d suggest that if they’re willing to let you take Engineering time to 100% for a little while, you return the favor; and once the platform is stable, dedicate 100% of the team’s time to Product work.

Celebrate!

This final step might seem optional, but it’s a big deal in my opinion. Your team just pulled off something incredible: they parallelized efforts, they were good partners to Product, they got something done for the Engineering org at large. It’s crucial to celebrate the work like you would a launch.

The team needs to know you value this work because it’s often thankless, but very impactful. It can also build trust to know that if something hairy comes up in the future, that it does actually help their career path as well. Celebrating with your team what you accomplished costs very little, and has great cultural impacts.

Buy the Book

This is just a sample of the kind of content from my latest book coming out soon…


Splitting Time Between Product and Engineering Efforts originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/splitting-time-between-product-and-engineering-efforts/feed/ 3 337340
Mistakes I’ve Made as an Engineering Manager https://css-tricks.com/mistakes-ive-made-as-an-engineering-manager/ https://css-tricks.com/mistakes-ive-made-as-an-engineering-manager/#comments Thu, 18 Feb 2021 22:39:50 +0000 https://css-tricks.com/?p=334528 I’ve been a manager for many years at companies of different scale. Through these experiences, I’ve done my share of learning, and made some mistakes along that way that were important lessons for me. I want to share those with …


Mistakes I’ve Made as an Engineering Manager originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I’ve been a manager for many years at companies of different scale. Through these experiences, I’ve done my share of learning, and made some mistakes along that way that were important lessons for me. I want to share those with you.

But before diving in, I want to mention a strong caveat that my advice may be unique to my situation because I’m white and a woman in tech. My experiences may be relevant to that point of view, but your mileage may vary.

Another huge caveat: I’m sharing mistakes I’ve made so far in the interest of helping others, but I’m sure I’m not done making mistakes, either. I don’t have it all figured it out, I’m still on this journey.

Credit: WoCinTechChat

Mistake 1: Thinking people give feedback the way they want to receive it

Feedback is one of the most important tools you have as a manager, but it can also be incredibly disruptive with poor execution. One of the hardest things I’ve had to learn is that humans aren’t pure functions: an input that works one day and gets one result, then again another day and get an entirely different result.

The same is true of how people give and receive feedback: someone may give you feedback in a particular way, but they prefer to receive much differently when it comes to themselves.

How do you get around this? Asking helps. I’ve started doing an exercise with my team where I ask the group as a whole how they would like to get feedback. Not only does it open up ideas, but it also helps that each individual has to think for themselves how they prefer to receive feedback. Normalizing this type of vulnerability and self-reflection can help us all feel like partners, instead of some top-down edict.

Another thing that’s helped? Asking folks directly in a one-on-one meeting if they have feedback for me as a manager, and following up with an anonymous survey. Again, it makes things feel less one-sided and provides everyone the opportunity to say things that they might not want to say directly to my face, which I know can be tough.

And lastly, if something comes up, addressing it immediately can be helpful. There’s nothing worse than your manager having an issue with something you did and only finding out about it three months later, especially if it’s tied to a performance review that you could have impacted had they been transparent earlier.

The truth is that even my advice here is imperfect. Feedback is tough. Being honest and improving together as a team is awkward. It’s incredibly worth it, though. That’s where the real growth is. That said, no two people are alike, no two groups are alike, and you may have to use your best judgement given the situation at hand.

Mistake 2: Trying to do everything yourself as a manager is the best way to help

Years ago, I managed a woman who was bright, talented, capable, and an all around pleasure. She was sort of new to the industry and could come across as timid, so I did my best to be a poop umbrella for her, fighting battles behind the scenes to set her up for success. She was on a steady track to land a senior role. Even after I decided to leave the company, I let the next manager know this person is track for a senior position in the next few months.

Then I moved to another city. Years later, I met up with the woman and was shocked to learn she never got the position.

Here’s what I learned: her promotion wasn’t the same high priority for the capable hands I left her in as it was for me. The team was challenged with a million other things that took center stage to the extent that her promotion fell off the radar. But even more than that, what became very clear to me was that all of that “protection” I thought I had set up for her didn’t really serve her well for the long haul. For example, I didn’t teach her how to advocate for herself or how to navigate the system. I vowed never to make that mistake again.

This is tough! If you’re strong and care about your team as people, it can feel very unnatural to teach someone to advocate instead of moving things out of their way themselves. And the point is not to throw that person into the fire. The point is to care. Are you teaching the things they need to learn? Are they really growing under you? Feeling like you’re protecting someone at all costs also lead to your own ego trip, too, which threatens progress.

Try to think through what skills someone needs to succeed without you. Teach those things incrementally. Sure, this is easy advice to say, but it’s really hard to do in the thick of things. Spend some time with it, and think through ways you can inject that learning into everyday work and interactions.

Credit: Charles Deluvio on Unsplash

Mistake 3: Communicating something one time is enough

No one likes to feel like they’re repeating themselves. It’s annoying to say something more than once, and it’s annoying to hear something over and again. But if you have a big enough group and there’s enough going on, things are going to slip through the cracks, so repetition becomes an important tool to make things stick. The trick is to say the same things, but in different ways.

There was a time last year when I asked my team to do something and none of them did it. What happened there? Given that it’s a team of highly efficient, strong collaborators, do you think they just all table-flipped and didn’t take action? Not a chance. I was the one who wasn’t clear. In fact, you can probably guess that if a whole group of people don’t understand or take action, the chance is that you, the manager, are the common denominator for why something is blocked. Not only did I not repeat myself enough to be clear, I didn’t align anyone with the why of the purpose of the task. It’s pretty easy to forget or not prioritize doing something if you have no clue why you’re doing it. Repeat yourself and align the group with the importance of the task and you’ll likely have a better result.

Think of all the ways we have to communicate these days: chats, emails, video meetings, texts, document comments, and so much more. And because some people communicate better in one medium than another, using all of the platforms have in various mediums becomes a strategy for repetition without nagging.

I’ve found that what work best is allowing everyone to own the information themselves. For example, if your team practices career laddering, the individual can read aloud each of the ladders in one-on-one and then talk you through their responses to each item. That way, you’re not lecturing — they are owning where they are and what the next steps are as you guide them along.

Mistake 4: You have to have everything together all the time

Some folks think that management looks like a steel fortress of preparedness and authority. I’m not so sure about that.

If something goes wrong, are you more likely to tell the manager acts as though they have everything together all the time, or the manager owns their mistakes? The truth is that your team needs to know you’re human. You can’t fix problems if you don’t know about them, and no one will tell you about them unless you make space for that.

One time, the night before a big release, someone on the team pushed a change that created thousands upon thousands of calls to a service that, in turn, thought it was the target of a DDoS attack, which then shut down our access. Here’s a moment when a lot of folks could have panicked and blamed one another. Instead, we giggled wildly, jumped into chat and on calls, fixed it, and kept going.

I couldn’t have been more proud of the team that day. Their response was wonderful. And it makes all the difference in how we work together, recover, and iterate.

You’re the manager, so if someone is going to show vulnerability first, it’s easiest on team dynamics if it’s you. You can try this by admitting you’re having a bad day, that you don’t understand something, or that made a mistake. You don’t have to do this constantly, a little is helpful.

This is way tougher if you are an underrepresented minority in tech. People will definitely think of an admitted mistake coming from one person as humility and another as failure. I myself struggle with this, too. I think it’s ok to admit that and feel the situation out given your circumstance.


Being a manager is tough. Your mistakes impact people, and that feeling of pressure can be a little isolating. I’ve made all of the mistakes above and more. I feel it’s critical to share so that when we encounter pitfalls, we don’t feel so alone and have a potential path forward.

Buy the Book

This is just a sample of the kind of content from my latest book coming out soon…


Mistakes I’ve Made as an Engineering Manager originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/mistakes-ive-made-as-an-engineering-manager/feed/ 13 334528
Creating Arrays in Hasura https://css-tricks.com/creating-arrays-in-hasura/ Mon, 04 Jan 2021 22:12:33 +0000 https://css-tricks.com/?p=330906 Hasura is one of my favorite ways to create a managed GraphQL API for my applications. I find it easy and straightforward as well as suitable for a wide range of use cases. However, since working with Hasura, I’ve seen …


Creating Arrays in Hasura originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Hasura is one of my favorite ways to create a managed GraphQL API for my applications. I find it easy and straightforward as well as suitable for a wide range of use cases. However, since working with Hasura, I’ve seen the same question come up again and again: how should we make an array? Given the fact that array and map are not provided in the type dropdown for rows, what’s the best way to accomplish this?

Truthfully, the concept of an array can be captured by Hasura a few different ways, and what follows is a breakdown of methods to approach this. My personal preference is the last option we’re going to cover, JSONB, but we’ll walk through other options in case you’d like to take another path, as every option has slightly different benefits.

Method 1: Literal arrays, manually

Hasura doesn’t offer “array” as a type, but we can create an array of strings by selecting “Text” and adding square brackets at the end, like this:

What we get is text[], and we’ll be prompted to create arrays in one of two ways:

["one", "two"] 
// or 
{"one", "two"}
insertion of row with type {"foo", "bar"} or ["foo", "bar"]

Method 2: Create a relationship

We can also create a relationship with another table that’s a series of text elements. To do so, create a row that has the type of text.

We’ll also create a new table via the “Add Table” button in the sidebar, and we’ll create a very simple row, with a unique key for the type we need — text, integer, or whatever is necessary for the data.

Now, click the “Relationships” tab. In the table, select the “Array Relationship” option, give it a name, and reference the original table that was created.

The id of the first table should have a relationship with the id of the second table we just created.

Once it’s saved, you should see the array relationship reflected in the table in the same relationships tab, with an arrow denoting the direction of the relationship.

users.gameId → favoriteGames.id

Now we can look up the array in the “GraphiQL” tab:

Method 3: JSONB

What follows is one of my favorite ways to create an array in Hasura. I like it because it can be really performant. We can use the “JSONB” type and create an array by selecting JSONB from the dropdown. Then we will be prompted in a similar fashion as the text[] option:

When it’s filled out, it will look like this:

From there, not only can we add the arrays to your query as above, but we can also search by tag through multiple indexes, and their GraphiQL tab makes it easy to explore. Check out when I filter the tags by what contains “animation”:

query MyQuery {
  codesamples(where: {tags: {_contains: "animation"}}) {
    userId
    name
    id
  }
}

However, a lookup like this is not necessarily performant out of the box, especially when there are large amounts of data. Luckily, we can define what fields we would like to index. From the “Data” tab at the top, select the “SQL” group in the side panel, and in that area we can define what fields we would like to index in order to maintain a performant lookup. In this example, we’ll create an index on the “tags” field:

create index codesample_gin on codesamples using gin(tags)

This will run the query, and index this lookup, making it more performant in the future.

Wrapping up

Hasura has a wonderful developer experience to set up quick and easy-to-use GraphQL APIs. For those who are interested in setting up arrays with Hasura, I hope this article is helpful.

Thanks to Adron Hall from Hasura who proofed this post.


Creating Arrays in Hasura originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
330906
Creating UI Components in SVG https://css-tricks.com/creating-ui-components-in-svg/ https://css-tricks.com/creating-ui-components-in-svg/#comments Mon, 23 Nov 2020 23:35:41 +0000 https://css-tricks.com/?p=325860 I’m thoroughly convinced that SVG unlocks a whole entire world of building interfaces on the web. It might seem daunting to learn SVG at first, but you have a spec that was designed to create shapes and yet, still has …


Creating UI Components in SVG originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I’m thoroughly convinced that SVG unlocks a whole entire world of building interfaces on the web. It might seem daunting to learn SVG at first, but you have a spec that was designed to create shapes and yet, still has elements, like text, links, and aria labels available to you. You can accomplish some of the same effects in CSS, but it’s a little more particular to get positioning just right, especially across viewports and for responsive development.

What’s special about SVG is that all the positioning is based on a coordinate system, a little like the game Battleship. That means deciding where everything goes and how it’s drawn, as well as how it’s relative to each other, can be really straightforward to reason about. CSS positioning is for layout, which is great because you have things that correspond to one another in terms of the flow of the document. This otherwise positive trait is harder to work with if you’re making a component that’s very particular, with overlapping and precisely placed elements.

Truly, once you learn SVG, you can draw anything, and have it scale on any device. Even this very site uses SVG for custom UI elements, such as my avatar, above (meta!).

That little half circle below the author image is just SVG markup.

We won’t cover everything about SVGs in this post (you can learn some of those fundamentals here, here, here and here), but in order to illustrate the possibilities that SVG opens up for UI component development, let’s talk through one particular use case and break down how we would think about building something custom.

The timeline task list component

Recently, I was working on a project with my team at Netlify. We wanted to show the viewer which video in a series of videos in a course they were currently watching. In other words, we wanted to make some sort of thing that’s like a todo list, but shows overall progress as items are completed. (We made a free space-themed learning platform and it’s hella cool. Yes, I said hella.)

Here’s how that looks:

So how would we go about this? I’ll show an example in both Vue and React so that you can see how it might work in both frameworks.

The Vue version

We decided to make the platform in Next.js for dogfooding purposes (i.e. trying out our own Next on Netlify build plugin), but I’m more fluent in Vue so I wrote the initial prototype in Vue and ported it over to React.

Here is the full CodePen demo:

Let’s walk through this code a bit. First off, this is a single file component (SFC), so the template HTML, reactive script, and scoped styles are all encapsulated in this one file.

We’ll store some dummy tasks in data, including whether each task is completed or not. We’ll also make a method we can call on a click directive so that we can toggle whether the state is done or not.

<script>
export default {
  data() {
    return {
      tasks: [
        {
          name: 'thing',
          done: false
        },
        // ...
      ]
    };
  },
  methods: {
    selectThis(index) {
      this.tasks[index].done = !this.tasks[index].done
    }
  }
};
</script>

Now, what we want to do is create an SVG that has a flexible viewBox depending on the amount of elements. We also want to tell screen readers that this a presentational element and that we will provide a title with a unique id of timeline. (Get more information on creating accessible SVGs.)

<template>
  <div id="app">
    <div>
      <svg :viewBox="`0 0 30 ${tasks.length * 50}`"
           xmlns="http://www.w3.org/2000/svg" 
           width="30" 
           stroke="currentColor" 
           fill="white"
           aria-labelledby="timeline"
           role="presentation">
           <title id="timeline">timeline element</title>
        <!-- ... -->
      </svg>
    </div>
  </div>
</template>

The stroke is set to currentColor to allow for some flexibility — if we want to reuse the component in multiple places, it will inherit whatever color is used on the encapsulating div.

Next, inside the SVG, we want to create a vertical line that’s the length of the task list. Lines are fairly straightforward. We have x1 and x2 values (where the line is plotted on the x-axis), and similarly, y1 and y2.

<line x1="10" x2="10" :y1="num2" :y2="tasks.length * num1 - num2" />

The x-axis stays consistently at 10 because we’re drawing a line downward rather than left-to-right. We’ll store two numbers in data: the amount we want our spacing to be, which will be num1, and the amount we want our margin to be, which will be num2.

data() {
  return {
    num1: 32,
    num2: 15,
    // ...
  }
}

The y-axis starts with num2, which is subtracted from the end, as well as the margin. The tasks.length is multiplied by the spacing, which is num1.

Now, we’ll need the circles that lie on the line. Each circle is an indicator for whether a task has been completed or not. We’ll need one circle for each task, so we’ll use v-for with a unique key, which is the index (and is safe to use here as they will never reorder). We’ll connect the click directive with our method and pass in the index as a param as well.

CIrcles in SVG are made up of three attributes. The middle of the circle is plotted at cx and cy, and then we draw a radius with r. Like the line, cx starts at 10. The radius is 4 because that’s what’s readable at this scale. cy will be spaced like the line: index times the spacing (num1), plus the margin (num2).

Finally, we’ll put use a ternary to set the fill. If the task is done, it will be filled with currentColor. If not, it will be filled with white (or whatever the background is). This could be filled with a prop that gets passed in the background, for instance, where you have light and dark circles.

<circle 
  @click="selectThis(i)" 
  v-for="(task, i) in tasks"
  :key="task.name"
  cx="10"
  r="4"
  :cy="i * num1 + num2"
  :fill="task.done ? 'currentColor' : 'white'"
  class="select"/>

Finally, we are using CSS grid to align a div with the names of tasks. This is laid out much in the same way, where we’re looping through the tasks, and are also tied to that same click event to toggle the done state.

<template>
  <div>
    <div 
      @click="selectThis(i)"
      v-for="(task, i) in tasks"
      :key="task.name"
      class="select">
      {{ task.name }}
    </div>
  </div>
</template>

The React version

Here is where we ended up with the React version. We’re working towards open sourcing this so that you can see the full code and its history. Here are a few modifications:

  • We’re using CSS modules rather than the SCFs in Vue
  • We’re importing the Next.js link, so that rather than toggling a “done” state, we’re taking a user to a dynamic page in Next.js
  • The tasks we’re using are actually stages of the course —or “Mission” as we call them — which are passed in here rather than held by the component.

Most of the other functionality is the same :)

import styles from './MissionTracker.module.css';
import React, { useState } from 'react';
import Link from 'next/link';

function MissionTracker({ currentMission, currentStage, stages }) {
 const [tasks, setTasks] = useState([...stages]);
 const num1 = 32;
 const num2 = 15;

 const updateDoneTasks = (index) => () => {
   let tasksCopy = [...tasks];
   tasksCopy[index].done = !tasksCopy[index].done;
   setTasks(tasksCopy);
 };

 const taskTextStyles = (task) => {
   const baseStyles = `${styles['tracker-select']} ${styles['task-label']}`;

   if (currentStage === task.slug.current) {
     return baseStyles + ` ${styles['is-current-task']}`;
   } else {
     return baseStyles;
   }
 };

 return (
   <div className={styles.container}>
     <section>
       {tasks.map((task, index) => (
         <div
           key={`mt-${task.slug}-${index}`}
           className={taskTextStyles(task)}
         >
           <Link href={`/learn/${currentMission}/${task.slug.current}`}>
             {task.title}
           </Link>
         </div>
       ))}
     </section>

     <section>
       <svg
         viewBox={`0 0 30 ${tasks.length * 50}`}
         className={styles['tracker-svg']}
         xmlns="http://www.w3.org/2000/svg"
         width="30"
         stroke="currentColor"
         fill="white"
         aria-labelledby="timeline"
         role="presentation"
       >
         <title id="timeline">timeline element</title>

         <line x1="10" x2="10" y1={num2} y2={tasks.length * num1 - num2} />
         {tasks.map((task, index) => (
           <circle
             key={`mt-circle-${task.name}-${index}`}
             onClick={updateDoneTasks(index)}
             cx="10"
             r="4"
             cy={index * +num1 + +num2}
             fill={
               task.slug.current === currentStage ? 'currentColor' : 'black'
             }
             className={styles['tracker-select']}
           />
         ))}
       </svg>
     </section>
   </div>
 );
}

export default MissionTracker;

Final version

You can see the final working version here:

This component is flexible enough to accommodate lists small and large, multiple browsers, and responsive sizing. It also allows the user to have better understanding of where they are in their progress in the course.

But this is just one component. You can make any number of UI elements: knobs, controls, progress indicators, loaders… the sky’s the limit. You can style them with CSS, or inline styles, you can have them update based on props, on context, on reactive data, the sky’s the limit! I hope this opens some doors on how you yourself can develop more engaging UI elements for the web.


Creating UI Components in SVG originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/creating-ui-components-in-svg/feed/ 13 325860
Quick LocalStorage Usage in Vue https://css-tricks.com/quick-localstorage-usage-in-vue/ https://css-tricks.com/quick-localstorage-usage-in-vue/#comments Thu, 05 Nov 2020 19:20:21 +0000 https://css-tricks.com/?p=325093 localStorage can be an incredibly useful tool in creating experiences for applications, extensions, documentation, and a variety of use cases. I’ve personally used it in each! In cases where you’re storing something small for the user that doesn’t need to …


Quick LocalStorage Usage in Vue originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
localStorage can be an incredibly useful tool in creating experiences for applications, extensions, documentation, and a variety of use cases. I’ve personally used it in each! In cases where you’re storing something small for the user that doesn’t need to be kept permanently, localStorage is our friend. Let’s pair localStorage with Vue, which I personally find to be a great, and easy-to-read developer experience.

Simplified example

I recently taught a Frontend Masters course where we built an application from start to finish with Nuxt. I was looking for a way that we might be able to break down the way we were building it into smaller sections and check them off as we go, as we had a lot to cover. localStorage was a gsolition, as everyone was really tracking their own progress personally, and I didn’t necessarily need to store all of that information in something like AWS or Azure.

Here’s the final thing we’re building, which is a simple todo list:

Storing the data

We start by establishing the data we need for all the elements we might want to check, as well as an empty array for anything that will be checked by the user.

export default {
  data() {
    return {
      checked: [],
      todos: [
        "Set up nuxt.config.js",
        "Create Pages",
        // ...
        ]
     }
   }
}

We’ll also output it to the page in the template tag:

  <div id="app">
    <fieldset>
      <legend>
        What we're building
      </legend>
      <div v-for="todo in todos" :key="todo">
        <input
          type="checkbox"
          name="todo"
          :id="todo"
          :value="todo"
          v-model="checked"
        />
       <label :for="todo">{{ todo }}</label>
     </div>
   </fieldset>
 </div>

Mounting and watching

Currently, we’re responding to the changes in the UI, but we’re not yet storing them anywhere. In order to store them, we need to tell localStorage, “hey, we’re interested in working with you.” Then we also need to hook into Vue’s reactivity to update those changes. Once the component is mounted, we’ll use the mounted hook to select checked items in the todo list then parse them into JSON so we can store the data in localStorage:

mounted() {
  this.checked = JSON.parse(localStorage.getItem("checked")) || []
}

Now, we’ll watch that checked property for changes, and if anything adjusts, we’ll update localStorage as well!

watch: {
  checked(newValue, oldValue) {
    localStorage.setItem("checked", JSON.stringify(newValue));
  }
}

That’s it!

That’s actually all we need for this example. This just shows one small possible use case, but you can imagine how we could use localStorage for so many performant and personal experiences on the web!


Quick LocalStorage Usage in Vue originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/quick-localstorage-usage-in-vue/feed/ 11 325093
The Empty Box https://css-tricks.com/the-empty-box/ https://css-tricks.com/the-empty-box/#comments Wed, 23 Sep 2020 22:34:52 +0000 https://css-tricks.com/?p=321187 When I was in high school, we learned about “The Black Box” which is concept in theater. If memory serves me right, the approach was a simple and elegant one: that you can take any space, any black …


The Empty Box originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
When I was in high school, we learned about “The Black Box” which is concept in theater. If memory serves me right, the approach was a simple and elegant one: that you can take any space, any black box, and make it come to life with a story. I liked the idea that it’s possible to convey anything, tell any story, and create any reality — all in the confines of what equates to a black box, a simple room that requires a curtain and very little else.

It’s an exciting concept. You see something extremely polished like a studio-produced movie. One might think, “No way I could do that.” All the scripts, the actors, the production, animation, set, props, everything. Where do you even begin?

But looking at things through The Black Box model, we distill the movie down to its essence, the story. We can see it as some folks telling a story in a stark, empty room. Take Thor: Ragnarok, a movie I really enjoy. It has incredible special effects, bits of humor, tension, relationships and stories that are well told. Sibling rivalry? Most of us know of or have seen something like that. Someone confronting you and you’d like to escape? We have all likely dealt with a challenge like that.

Those are the stories. The special effects and polished production? Those merely dress up the stories but aren’t necessary to convey the story. But still, how do you get from a black box to a large scale production?

Or, put in a different context: how do we get from an idea to a full-fledged website or app? You see all of these incredible sites around you and could easily fall into a trap of thinking anything you put out needs to meet the same scale and production. But let’s pull the curtain back on that and play with the idea that…

Apps are the box

Programmers are literal creatures, so instead of a “black box,” which has different connotations in tech, I’ll switch it up and call it an “empty box” — even though that also has roots in other metaphors, such as a the “tabula rasa” (clean slate) in art, which is a very similar concept.

If you look at an apps like Notion, Airbnb, or Etsy as newcomers to the industry, the yes, it might seem impossible how you might get from learning basic CRUD operations to working on an application at the same scale, state and complexity as those apps. But what happens if we flip the script? Instead of thinking about building the entire universe from scratch, maybe we start with an empty box, one that only holds the core use case or problem that’s being solved. We can decide what we’re going to create with this small bit of space we have in the world.

It’s a nice way to dial back the scope. Of course, people might use our sites in myriad ways, but when you peel back every usage, every feature, and compare what else is out there, what is the purpose? Sometimes we work at big companies with lots of competing priorities — so many that if you ask different folks, you’ll likely get a wide range of answers. And certainly any app with any level of complexity has to cater to many user needs.

However, I wonder if it might serve us to be able to answer that question with clarity. Particularly when we’re just starting out.

You have an empty box. What can you build in that space? You can engage people all around the world instantly in any way. You can create any interaction. What is that interaction and what is it trying to convey? What is going to make it relatable? What’s going to get the message across?

Forget about all the production and complexity you could build. What’s the purpose you want to convey at the core? What are you most excited about? What’s the solution to the problem right in front of you?


The Empty Box originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-empty-box/feed/ 3 321187
Setting up and Customizing the Ant Design System in a Nuxt App https://css-tricks.com/setting-up-and-customizing-the-ant-design-system-in-a-nuxt-app/ https://css-tricks.com/setting-up-and-customizing-the-ant-design-system-in-a-nuxt-app/#comments Wed, 09 Sep 2020 19:46:24 +0000 https://css-tricks.com/?p=320361 I don’t typically work with UI libraries because they can be cumbersome and hard to override, which can contribute to a bloated. However, Ant Design has recently gained some some of my affection because it’s easy to use, has extensible …


Setting up and Customizing the Ant Design System in a Nuxt App originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I don’t typically work with UI libraries because they can be cumbersome and hard to override, which can contribute to a bloated. However, Ant Design has recently gained some some of my affection because it’s easy to use, has extensible defaults, and features a delicate design.

Nuxt and Ant Design work well together, in part because of Nuxt’s code-splitting and tree-shaking abilities, not to mention Nuxt’s new static target deployment option. I can serve an app using Ant Design with great performance scores.

Combining the two was a little tricky and there isn’t a lot in the way of documentation for how to do it, so what follows are the steps you need to set it up. Let’s get started!

Install Ant.design

The first step is installing the ant-design-vue package, along with Less.js and less-loader, which we will need to create our Less variables:

yarn add ant-design-vue less less-loader
# or
npm i ant-design-vue less less-loader

Now lets tell Nuxt to use it globally via a plugin. We’ll create a file called antd-ui.js:

import Vue from 'vue'
import Antd from 'ant-design-vue/lib'

Vue.use(Antd)

You may notice that unlike the process outlined in the Ant Design getting started guide, we are not importing the global CSS file they mention. That’s because we’re going to manually import the base variable Less file instead so that we can override it. 

We have a few things to do in our nuxt.config.js file. First, let’s register the plugin we just made:

plugins: ["@/plugins/antd-ui"],

Next, we’re going to let webpack know we’d like to build Less:

build: {
   loaders: {
     less: {
       lessOptions: {
         javascriptEnabled: true,
       },
    },
  },
}

Finally, we need to create a global stylesheet for our variables that imports Ant Design’s defaults as well as our overrides:

css: [
  "~/assets/variables.less"
],

We can see that this file exists in a /assets folder, so let’s make it. We’ll create a file in there called variables.less, and import Ant Design’s Less variables:

@import '~ant-design-vue/dist/antd.less';

Below this line, there are myriad variables you can override. This is just a sampling. The rest of the variables are here, and you’ll need to include them by their @ and can change it to whatever you wish:

@primary-color: #1890ff; // primary color for all components
@link-color: #1890ff; // link color
@success-color: #52c41a; // success state color
@warning-color: #faad14; // warning state color
@error-color: #f5222d; // error state color
@font-size-base: 14px; // major text font size
@heading-color: rgba(0, 0, 0, 0.85); // heading text color
@text-color: rgba(0, 0, 0, 0.65); // major text color
@text-color-secondary: rgba(0, 0, 0, 0.45); // secondary text color
@disabled-color: rgba(0, 0, 0, 0.25); // disable state color
@border-radius-base: 4px; // major border radius
@border-color-base: #d9d9d9; // major border color
@box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15); // major shadow for layers

We’re good to go! There’s no need to import what we need into every component because Nuxt will now take care of that. If you’d like to override very specific styles not included in the variables, you can find the associative classes and override them in your layouts/default.vue file as well.

Ant.design and Nuxt allow you a great framework for building apps very quickly and with ease. Enjoy!


Setting up and Customizing the Ant Design System in a Nuxt App originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/setting-up-and-customizing-the-ant-design-system-in-a-nuxt-app/feed/ 2 320361
The Making of: Netlify’s Million Devs SVG Animation Site https://css-tricks.com/the-making-of-netlifys-million-devs-svg-animation-site/ https://css-tricks.com/the-making-of-netlifys-million-devs-svg-animation-site/#comments Mon, 03 Aug 2020 15:04:53 +0000 https://css-tricks.com/?p=318353 The following article captures the process of building the Million Developers microsite for Netlify. This project was built by a few folks and we’ve captured some parts of the process of building it here- focusing mainly on the animation …


The Making of: Netlify’s Million Devs SVG Animation Site originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The following article captures the process of building the Million Developers microsite for Netlify. This project was built by a few folks and we’ve captured some parts of the process of building it here- focusing mainly on the animation aspects, in case any are helpful to others building similar experiences.

Building a Vue App out of an SVG

The beauty of SVG is you can think of it, and the coordinate system, as a big game of battleship. You’re really thinking in terms of x, y, width, and height.

<div id="app">
   <app-login-result-sticky v-if="user.number" />
   <app-github-corner />

   <app-header />

   <!-- this is one big SVG -->
   <svg id="timeline" xmlns="http://www.w3.org/2000/svg" :viewBox="timelineAttributes.viewBox">
     <!-- this is the desktop path -->
     <path
       class="cls-1 timeline-path"
       transform="translate(16.1 -440.3)"
       d="M951.5,7107..."
     />
     <!-- this is the path for mobile -->
     <app-mobilepath v-if="viewportSize === 'small'" />

     <!-- all of the stations, broken down by year -->
     <app2016 />
     <app2017 />
     <app2018 />
     <app2019 />
     <app2020 />

     <!-- the 'you are here' marker, only shown on desktop and if you're logged in -->
     <app-youarehere v-if="user.number && viewportSize === 'large'" />
   </svg>
 </div>

Within the larger app component, we have the large header, but as you can see, the rest is one giant SVG. From there, we broke down the rest of the giant SVG into several components:

  • Candyland-type paths for both desktop and mobile, shown conditionally by a state in the Vuex store
  • There are 27 stations, not including their text counterparts, and many decorative components like bushes, trees, and streetlamps, which is a lot to keep track of in one component, so they’re broken down by year
  • The ‘you are here’ marker, only shown on desktop and if you’re logged in

SVG is wonderfully flexible because not only can we draw absolute and relative shapes and paths within that coordinate system, we can also draw SVGs within SVGs. We just need to defined the x, y, width and height of those SVGs and we can mount them inside the larger SVG, which is exactly what we’re going to do with all these components so that we can adjust their placement whenever needed. The <g> within the components stands for group, you can think of them a little like divs in HTML.

So here’s what this looks like within the year components:

<template>
 <g>
   <!-- decorative components -->
   <app-tree x="650" y="5500" />
   <app-tree x="700" y="5550" />
   <app-bush x="750" y="5600" />

   <!-- station component -->
   <app-virtual x="1200" y="6000" xSmall="50" ySmall="15100" />
   <!-- text component, with slots -->
   <app-text
     x="1400"
     y="6500"
     xSmall="50"
     ySmall="15600"
     num="20"
     url-slug="jamstack-conf-virtual"
   >
     <template v-slot:date>May 27, 2020</template>
     <template v-slot:event>Jamstack Conf Virtual</template>
   </app-text>

   ...
 </template>

<script>
...

export default {
 components: {
   // loading the decorative components in syncronously
   AppText,
   AppTree,
   AppBush,
   AppStreetlamp2,
   // loading the heavy station components in asyncronously
   AppBuildPlugins: () => import("@/components/AppBuildPlugins.vue"),
   AppMillion: () => import("@/components/AppMillion.vue"),
   AppVirtual: () => import("@/components/AppVirtual.vue"),
 },
};
...
</script>

Within these components, you can see a number of patterns:

  • We have bushes and trees for decoration that we can sprinkle around viax and y values via props
  • We can have individual station components, which also have two different positioning values, one for large and small devices
  • We have a text component, which has three available slots, one for the date, and two for two different text lines
  • We’re also loading in the decorative components synchronously, and loading those heavier SVG stations async

SVG Animation

Header animation for Million Devs

The SVG animation is done with GreenSock (GSAP), with their new ScrollTrigger plugin. I wrote up a guide on how to work with GSAP for their latest 3.0 release earlier this year. If you’re unfamiliar with this library, that might be a good place to start.

Working with the plugin is thankfully straightforward, here is the base of the functionality we’ll need:

import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger.js";
import { mapState } from "vuex";

gsap.registerPlugin(ScrollTrigger);

export default {
 computed: {
   ...mapState([
     "toggleConfig",
     "startConfig",
     "isAnimationDisabled",
     "viewportSize",
   ]),
 },
 ...
 methods: {
   millionAnim() {
     let vm = this;
     let tl;
     const isScrollElConfig = {
       scrollTrigger: {
         trigger: `.million${vm.num}`,
         toggleActions: this.toggleConfig,
         start: this.startConfig,
       },
       defaults: {
         duration: 1.5,
         ease: "sine",
       },
     };
   }
 },
 mounted() {
   this.millionAnim();
 },
};

First, we’re importing gsap and the package we need, as well as state from the Vuex store. I put the toggleActions and start config settings in the store and passed them into each component because while I was working, I needed to experiment with which point in the UI I wanted to trigger the animations, this kept me from having to configure each component separately.

Those configurations in the store look like this:

export default new Vuex.Store({
  state: {
    toggleConfig: `play pause none pause`,
    startConfig: `center 90%`,
  }
}

This configuration breaks down to

  • toggleConfig: play the animation when it passes down the page (another option is to say restart and it will retrigger if you see it again), it pauses when it is out of the viewport (this can slightly help with perf), and that it doesn’t retrigger in reverse when going back up the page.
  • startConfig is stating that when the center of the element is 90% down from the height of the viewport, to trigger the animation to begin.

These are the settings we decided on for this project, there are many others! You can understand all of the options with this video.

For this particular animation, we needed to treat it a little differently if it was a banner animation which didn’t need to be triggered on scroll or if it was later in the timeline. We passed in a prop and used that to pass in that config depending on the number in props:

if (vm.num === 1) {
  tl = gsap.timeline({
    defaults: {
      duration: 1.5,
      ease: "sine",
    },
  });
} else {
  tl = gsap.timeline(isScrollElConfig);
}

Then, for the animation itself, I’m using what’s called a label on the timeline, you can think of it like identifying a point in time on the playhead that you may want to hang animations or functionality off of. We have to make sure we use the number prop for the label too, so we keep the timelines for the header and footer component separated.

tl.add(`million${vm.num}`)
...
.from(
  "#front-leg-r",
  {
    duration: 0.5,
    rotation: 10,
    transformOrigin: "50% 0%",
    repeat: 6,
    yoyo: true,
    ease: "sine.inOut",
  },
  `million${vm.num}`
)
.from(
  "#front-leg-l",
  {
    duration: 0.5,
    rotation: 10,
    transformOrigin: "50% 0%",
    repeat: 6,
    yoyo: true,
    ease: "sine.inOut",
  },
  `million${vm.num}+=0.25`
);

There’s a lot going on in the million devs animation so I’ll just isolate one piece of movement to break down: above we have the girls swinging legs. We have both legs swinging separately, both are repeating several times, and that yoyo: true lets GSAP know that I’d like the animation to reverse every other alteration. We’re rotating the legs, but what makes it realistic is the transformOrigin starts at the center top of the leg, so that when it’s rotating, it’s rotating around the knee axis, like knees do :)

Adding an Animation Toggle

animation toggle

We wanted to give users the ability to explore the site without animation, should they have a vestibular disorder, so we created a toggle for the animation play state. The toggle is nothing special- it updates state in the Vuex store through a mutation, as you might expect:

export default new Vuex.Store({
  state: {
    ...
    isAnimationDisabled: false,
  },
  mutations: {
    updateAnimationState(state) {
      state.isAnimationDisabled = !state.isAnimationDisabled
    },
  ...
})

The real updates happen in the topmost App component where we collect all of the animations and triggers, and then adjust them based on the state in the store. We watch the isAnimationDisabled property for changes, and when one occurs, we grab all instances of scrolltrigger animations in the app. We don’t .kill() the animations, which one option, because if we did, we wouldn’t be able to restart them.

Instead, we either set their progress to the final frame if animations are disabled, or if we’re restarting them, we set their progress to 0 so they can restart when they are set to fire on the page. If we had used .restart() here, all of the animations would have played and we wouldn’t see them trigger as we kept going down the page. Best of both worlds!

watch: {
   isAnimationDisabled(newVal, oldVal) {
     ScrollTrigger.getAll().forEach((trigger) => {
       let animation = trigger.animation;
       if (newVal === true) {
         animation && animation.progress(1);
       } else {
         animation && animation.progress(0);
       }
     });
   },
 },

SVG Accessibility

I am by no means an accessibility expert, so please let me know if I’ve misstepped here- but I did a fair amount of research and testing on this site, and was pretty excited that when I tested on my Macbook via voiceover, the site’s pertinent information was traversable, so I’m sharing what we did to get there.

For the initial SVG that cased everything, we didn’t apply a role so that the screenreader would traverse within it. For the trees and bushes, we applied role="img" so the screenreader would skip it and any of the more detailed stations we applied a unique id and title, which was the first element within the SVG. We also applied role="presentation".

<svg
   ...
   role="presentation"
   aria-labelledby="analyticsuklaunch"
 >
   <title id="analyticsuklaunch">Launch of analytics</title>

I learned a lot of this from this article by Heather Migliorisi, and this great article by Leonie Watson.

The text within the SVG does announce itself as you tab through the page, and the link is found, all of the text is read. This is what that text component looks like, with those slots mentioned above.

<template>
 <a
   :href="`https://www.netlify.com/blog/2020/08/03/netlify-milestones-on-the-road-to-1-million-devs/#${urlSlug}`"
 >
   <svg
     xmlns="http://www.w3.org/2000/svg"
     width="450"
     height="250"
     :x="svgCoords.x"
     :y="svgCoords.y"
     viewBox="0 0 280 115.4"
   >
     <g :class="`textnode text${num}`">
       <text class="d" transform="translate(7.6 14)">
         <slot name="date">Jul 13, 2016</slot>
       </text>
       <text class="e" transform="translate(16.5 48.7)">
         <slot name="event">Something here</slot>
       </text>
       <text class="e" transform="translate(16.5 70)">
         <slot name="event2" />
       </text>
       <text class="h" transform="translate(164.5 104.3)">View Milestone</text>
     </g>
   </svg>
 </a>
</template>

Here’s a video of what this sounds like if I tab through the SVG on my Mac:

If you have further suggestions for improvement please let us know!

The repo is also open source if you want to check out the code or file a PR.

Thanks a million (pun intended) to my coworkers Zach Leatherman and Hugues Tennier who worked on this with me, their input and work was invaluable to the project, it only exists from teamwork to get it over the line! And so much respect to Alejandro Alvarez who did the design, and did a spectacular job. High fives all around. 🙌


The Making of: Netlify’s Million Devs SVG Animation Site originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-making-of-netlifys-million-devs-svg-animation-site/feed/ 4 318353
Vue 3.0 has entered Release Candidate stage! https://css-tricks.com/vue-3-0-has-entered-release-candidate-stage/ https://css-tricks.com/vue-3-0-has-entered-release-candidate-stage/#comments Thu, 23 Jul 2020 14:57:58 +0000 https://css-tricks.com/?p=317490 Vue is in the process of a complete overhaul that rebuilds the popular JavaScript framework from the ground up. This has been going on the last couple of years and, at long last, the API and implementation of Vue 3 …


Vue 3.0 has entered Release Candidate stage! originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Vue is in the process of a complete overhaul that rebuilds the popular JavaScript framework from the ground up. This has been going on the last couple of years and, at long last, the API and implementation of Vue 3 core are now stabilize. This is exciting for a number of reasons:

  • Vue 3 promises to be much more performant than Vue 2.
  • Despite being a complete rewrite, the surface API hasn’t changed drastically, so there’s no need to forget what you already know about Vue.
  • The Vue documentation was completely migrated revised. (If you see me celebrating that, it’s because I helped work on it.)
  • There are several new features — like the Composition API (inspired by React Hooks) — that are additive and helpful for composition between multiple components.

Here’s how you can get your hands on the Vue 3 release candidate:

There is more information about DevTools, experimental features and more in the release notes.

Docs updates, now in beta

Why am I so excited about the Vue doc updates? Because the updates include but are not limited to:

We are still actively working on things, of course, so if you see to-dos or unresolved work, please let us know! Feel free to open an issue or PR over at GitHub but, please, note that large requests will likely be closed out while we’re still refining our current work.

All in all we think you’ll enjoy it! It’s all the features you know and love, with some extra lovely bits, plus excellent performance.


Vue 3.0 has entered Release Candidate stage! originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/vue-3-0-has-entered-release-candidate-stage/feed/ 1 317490
In Defense of a Fussy Website https://css-tricks.com/in-defense-of-a-fussy-website/ https://css-tricks.com/in-defense-of-a-fussy-website/#comments Fri, 26 Jun 2020 19:12:01 +0000 https://css-tricks.com/?p=314496 The other day I was doom-scrolling twitter, and I saw a delightful article titled “The Case for Fussy Breakfasts.” I love food and especially breakfast, and since the pandemic hit I’ve been using my breaks in between meetings …


In Defense of a Fussy Website originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The other day I was doom-scrolling twitter, and I saw a delightful article titled “The Case for Fussy Breakfasts.” I love food and especially breakfast, and since the pandemic hit I’ve been using my breaks in between meetings (or sometimes on meetings, shh) to make a full bacon, poached egg, vegetable plate, so I really got into the article. This small joy of creating a bit of space for myself for the most important meal of the day has been meaningful to me — while everything else feels out of control, indulging in some ceremony has done a tiny part to offset the intensity of our collective situation.

It caused me to think of this “fussiness” as applied to other inconsequential joys. A walk. A bath. What about programming?

While we’re all laser-focused on shipping the newest feature with the hottest software and the best Lighthouse scores, I’ve been missing a bit of the joy on the web. Apps are currently conveying little care for UX, guidance, richness, and — well, for humans trying to communicate through a computer, we’re certainly bending a lot to… the computer.

I’m getting a little tired of the web being seen as a mere document reader, and though I do love me a healthy lighthouse score, some of these point matrixes seem to live and die more by our developer ego in this gamification than actually considering what we can do without incurring much weight. SVGs can be very small while still being impactful. Some effects are tiny bits of CSS. JS animations can be lazy-loaded. You can even dazzle with words, color, and layout if you’re willing to be a bit adventurous, no weight at all!

A few of my favorite developer sites lately have been Josh Comeau, Johnson Ogwuru and Cassie Evans. The small delights and touches, the little a-ha moments, make me STAY. I wander around the site, exploring, learning, feeling actually more connected to each of these humans rather than as if I’m glancing at a PDF of their resume. They flex their muscles, show me the pride they have in building things, and it intrigues me! These small bits are more than the fluff that many portray any “excess” as: they do the job that the web is intending. We are communicating using this tool- the computer- as an extension of ourselves.

Nuance can be challenging. It’s easy as programmers to get stuck in absolutes, and one of these of late has been that if you’re having any bit of fun, any bit of style, that must mean it’s “not useful.” Honestly, I’d make the case that the opposite is true. Emotions attach to the limbic system, making memories easier to recall. If your site is a flat bit of text, how will anyone remember it?

Don’t you want to build the site that teams in companies the world over remember and cite as an inspiration? I’ve been at four different companies where people have mentioned Stripe as a site they would aspire to be like. Stripe took chances. Stripe told stories. Stripe engaged the imagination of developers, spoke directly to us.

I’m sad acknowledging the irony that after thinking about how spot on Stripe was, most of those companies ignored much of what they learned while exploring it. Any creativity, risk, and intention was slowly, piece by piece, chipped away by the drumbeat of “usefulness,” missing the forest for the trees.

When a site is done with care and excitement you can tell. You feel it as you visit, the hum of intention. The craft, the cohesiveness, the attention to detail is obvious. And in turn, you meet them halfway. These are the sites with the low bounce rates, the best engagement metrics, the ones where they get questions like “can I contribute?” No gimmicks needed.

What if you don’t have the time? Of course, we all have to get things over the line. Perhaps a challenge: what small thing can you incorporate that someone might notice? Can you start with a single detail? I didn’t start with a poached egg in my breakfast, one day I made a goofy scrambled one. It went on from there. Can you challenge yourself to learn one small new technique? Can you outsource one graphic? Can you introduce a tiny easter egg? Say something just a little differently from the typical corporate lingo?

If something is meaningful to you, the audience you’ll gather will likely be the folks that find it meaningful, too.


In Defense of a Fussy Website originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/in-defense-of-a-fussy-website/feed/ 12 314496
Get Programmatic Control of your Builds with Netlify Build Plugins https://css-tricks.com/get-programmatic-control-of-your-builds-with-netlify-build-plugins/ https://css-tricks.com/get-programmatic-control-of-your-builds-with-netlify-build-plugins/#comments Wed, 27 May 2020 14:14:34 +0000 https://css-tricks.com/?p=311377 Today at Jamstack_Conf, Netlify announced Build Plugins. What it does is allow you to have particular hooks for events within your build, like when the build starts or ends. What’s nice about them is that they’re just a …


Get Programmatic Control of your Builds with Netlify Build Plugins originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Today at Jamstack_Conf, Netlify announced Build Plugins. What it does is allow you to have particular hooks for events within your build, like when the build starts or ends. What’s nice about them is that they’re just a plain ‘ol JavaScript object, so you can insert some logic or kick off a library just the way you typically would within your application.

A “Build” is when you give your site to Netlify either via GitHub/GitLab/etc., or by literally just dropping the directory into the interface, Netlify will process all the assets, download and install packages, and generate a static version of the site to deploy to CDNs all around the world.

What the Build Plugin does is give you access to key points in time during that process, for instance, onPreBuild, onPostBuild, onSuccess, and so forth. You can execute some logic at those specific points in time, like this:

module.exports = {
  onPreBuild: () => {
    console.log('Hello world from onPreBuild event!')
  },
}

You don’t only have to build them yourself, either! You can use build plugins that have been made by the community. There are very interesting ones, such as a11y, Cypress for testing, Inline Critical CSS, and my personal favorite, Subfont, which optimizes fonts for you in a really incredible way (you can watch a video about that).

Enable them through the dashboard through a few button clicks:

If you’d like to learn more, check out the announcement post here! Happy building!


Get Programmatic Control of your Builds with Netlify Build Plugins originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/get-programmatic-control-of-your-builds-with-netlify-build-plugins/feed/ 1 311377