How to Think Full-Stack

I’d like to share some thoughts on what it means to be a full-stack developer and how to think full-stack while building a web application.

But first, a disclaimer: I wouldn’t call myself a full-stack developer the way many understand the job. Being a true full-stack engineer is rare these days, as technology and language advancements add layers to the stacks we work in. I do, however, work on features that cut across layers of the stack. I also feel stronger working in some layers over others, and often seek out guidance from others. But the way I think about it, full-stack is usually more of a goal than a title. And even without reaching that goal just yet, thinking like a full-stack developer is achievable for engineers at all experience levels. This skill will help you build applications with clean architectures that are easy to maintain and grow.

Full-stack Development: What is it?

If full-stack development isn’t being a total master of the stack, what is it? According to the Stack Overflow Developer Survey results, full-stack web developer is the second most common developer occupation. Accordingly, there are a lot of definitions out there and every job posting will expect something a little different. But basically, it’s what it sounds like. There’s this “stack” of layers in a web application and a full-stack developer has familiarity in all (or most) of them.

“The Stack”

What stack am I talking about?

An example of a web developer's stack

One example of a web developer’s stack. There are other layers (especially deeper layers), but these are a solid starting set for web developers like me.

At the top are the more practical layers that are closer to the customer. Having product and business expertise is how you understand the needs of your customers. This layer involves understanding the business value of what you’re building, which helps you make the correct strategic decisions that will delight your customers and meet their needs. This, in conjunction with the User Experience (UX) layer, focus on making it easy to use your product the right way and hard to use it the wrong way.

Further down are the more technical layers, where you’ll start seeing code. First, the User Interface layer (the “frontend”) is where you display application data to the user in readable layouts. This also includes frontend data models/data flows and the user interactions within the application. The API layer largely bridges the communication gap between frontend and backend. It is important that it connect the various services of your application effectively. The Data Modeling layer is all about creating a conceptual model of how the data in your app is structured, which can be persisted in relational or non-relational data stores. The Backend Logic layer contains the code needed to perform the business logic of the app. It tends to handle the heavy lifting in terms of processing and calculations. And finally, the Infrastructure layer encompasses the many concerns of development and operations, including network resources, storage, data redundancy, and availability, to name a few.

Full-Stack Skills and Concepts

There are a lot of layers, and each one has many technologies that are widely used. On the Internet, you’ll find lists on lists of what a full-stack web developer is supposed to know, and many of them will be pretty overwhelming. They’ll expect you to know the basics (like HTML, CSS, JavaScript, jQuery) and at least one frontend framework (like React or Angular) on top of at least one backend language (like Python, Java, C++). But that’s not all. They’ll also expect you to be familiar with SQL and NoSQL datastores, as well as web storage options (like caching and local storage), communication protocols between applications (like HTTP and REST), and general architecture tools (like Heroku and AWS).

Some tools, frameworks, languages used in different layers of stack

A (very limited) assortment of frameworks, technologies, and tools listed by the layer of the stack in which they’re used.

But I personally think that’s a lot for any one developer to know, and it’s a lot more than I knew when I got started as a full-stack developer at Qualtrics. Instead, it’s enough to start by having some familiarity in one or two levels of the stack and an interest in learning about the others. The goal is to make decisions in one area of the stack that will be efficient and clean to work with in other layers. But really, it takes a long time and extensive practice to be a specialist in all of the layers. A big part of being a full-stack developer is being excited about trying new things, but also asking for help from the specialists on your team (experts in certain technologies or layers of the stack) when you need it.

The Value of Full-Stack Development

Since full-stack development requires a lot of knowledge and experience, why do we try to do it anyway? First, full-stack development, when done well, allows a segmented application to feel more unified. Say you’re working on a frontend task, for example. It can be enough to just consume or write to an API that someone else on your team has written or that you have designed together. But if you understand the datastore you’re using and how the backend reads from and writes to that datastore, you’re going to be able to design better data models and also better API’s that fit logically into your frontend components.

As a full-stack developer, you bring a complex and diverse perspective to the table. You understand your customers, the consumers of your work, and the context in which they use your application. This helps you build a better, more sellable product. You can also understand the roles your teammates play in specific parts of the stack and can make their jobs easier by considering the limitations and benefits of the tools they use. This creates a team dynamic based on empathy and common interest.

Full-Stack Development in Action

To show the value of thinking full-stack, I’ll walk through a feature I worked on a few months back and discuss some decisions I made about how to build it using a full-stack mindset. I’m hoping this will provide some concrete examples so that you can apply this thought framework to your own work.

I work on the team that builds Qualtrics Stats iQ, an intuitive statistical analysis application that empowers analysts of all experience levels to look at statistical relationships in their data. To do this, we parse user datasets (usually collected via Qualtrics surveys) into sets of variables that can then be related and analyzed in various ways.

Sometimes users want to create derived variables, i.e. variables that either combine data from multiple sources or involve further processing of data associated with a single variable. Consider, for example, a researcher who collected customer data about age in numbers, but wanted to bucket those ages into categories like “18-34”, “35-54”, and “55+” so they can examine the interests of those age groups. They could do this in Stats iQ by creating a derived variable based on their existing age data with our variable creation interface.

A Full-Stack Feature

This variable creation interface is what I’m going to talk about today. It’s evident that this will be a feature that will benefit from a full-stack mindset. Why? Well, we need to provide an interface for our users to define their variables. That means we’re thinking about our users and what they need out of our variable creation interface (product expertise layer, UX layer), as well as planning the data models and UI components that power this experience (user interface layer).

Considerations of this project in near-user layers of the stack

Considerations of this project in near-user layers of the stack.

After the variables are created, our users are going to want to be able to run analyses on them. The effort we spent defining the variable would be wasted if we couldn’t do anything with what we made! This means we’re also considering backend layers, like how we model the definitions for these created variables (data model layer), update those definitions (API layer), and persist changes between sessions (data storage layer).

Considerations of this project in more user-removed layers of the stack

Considerations of this project in more user-removed layers of the stack.

Getting concrete

Now we know that we have a full-stack problem, we can tackle a few design questions in a full-stack way, starting with the data model.

Data Model

For consistency, it would be convenient to use a data model for these created variables that is easy to use at all layers of the stack, including our JavaScript frontend, Python backend, and MySQL data store. We also need to consider at which layer performance is most important. For my team, the user experience is super important and we want to provide a product that’s responsive and quick. Accordingly, I decided to focus on a structure that would be easy to interpret, render, and update in the user interface. However, because we would need to be able to process the definition on the backend in analyses using the created variables, I also needed to consider what information is needed to create a column of data from a variable definition and make sure it’ll be easy to compute that information on the backend.

With these considerations in mind, I decided to use a JavaScript object for my variable definitions. The key-value structure allowed me to provide a more human-friendly interface to the fields of the definitions by giving them names. This made the frontend code more intuitive to read and write. These objects are also convenient because they can easily be stringified as JSON and passed between layers of the Stats iQ application via HTTP request bodies.

At the data modeling/storage layer, I had to consider the trade-offs of using a longtext type (the column type for JSON blobs in our MySQL store) because they tend to be less searchable. But since our database operations always grab the entire value at a time, the lack of searchability turned out to be an irrelevant concern. And finally, in addition to being convenient at the UI, API, and data storage layers, the stringified objects can also be parsed as a Python dict in the backend for easy computation. Problem solved!

Computations

Speaking of computations, a big part of working full-stack is determining where computations should live. I knew the backend would be in charge of taking a variable definition and creating a column of data from it, but what about the computations involved with actually building the variable definition? Recall our researcher from before who wanted to bucket their age data into categories (“buckets”). This bucketing is a common use case for our variable creation users. In some of these cases, we think we can provide default buckets for users based on their data to get them started. Should those default buckets be computed on the frontend?

For me, the answer was to handle this (and pretty much everything) in the browser to improve responsiveness. The computations weren’t complex enough to benefit from the additional processing power in our backend, so handling computation in the browser avoided a network delay in receiving computation results.

Takeaways

I’ve only given  a few specific examples, but every stage of the development process on this feature involved consideration of other layers. And through all of those stages, I had help – my manager, my PM, our UX resource, my teammates. I’ve learned that using the resources I have available is critical to making the right decisions, especially when I don’t have the most fresh or extensive context. Thinking full-stack (and involving the experts) as I went helped me to avoid entire rewrites. I was able to anticipate at least some potential problems in advance. This is why it’s important to take the time to think full-stack in the architecture and design phases.

Conclusion

Being full-stack is a moving target, but one that I’m chasing after and you can, too. That said,  if you heard this and thought “Yeah, that sounds like a lot of work” or “I’m just not that interested in (blank) layer”: that’s awesome, too.  Every team needs specialists in certain areas because you can become the kind of rock star advisor that full-stack engineers rely on to make the best decisions. But having developers in the mix who do think full-stack help unite the team and the product by designing frontend and backend components that work smoothly at all layers in the stack that can be maintained and extended for years to come.

Resources:

 

Erin Leonhard
Erin works as a full-stack software engineer at Qualtrics on a few data analysis products, including Stats iQ, that are making statistical analysis accessible to anyone, even without a math background. She graduated from Indiana University in May 2016 with a degree in Computer Science and has been living in Seattle ever since. Outside of work, she plays recreational soccer, ultimate frisbee, and volleyball in various leagues around Seattle and enjoys playing piano, reading the news, and drinking coffee in her free time.

You may also like...