Goal Types & OKR Modeling

Role

Senior Content Designer

Company

Atlassian

Timeline

~1.5 years

Collaborators

PM, Product Design, Engineering, Localization

In this case study

Content Systems, Content Strategy, Localization, Cross-functional Collaboration, UX Writing, Admin experiences, Scalability

By this point, pretty much everyone knows what an OKR is. Even if they don't understand how the framework actually works, they can tell you it stands for Objective and Key Results. But as well-known as it is, it's surprisingly difficult to effectively represent the framework in software. Take Microsoft Viva Goals for example, one of our biggest competitors in the space at the time. They sunset the product in 2025. While it's unfortunate, it was all the more reason we knew we had to get this right… especially because our first attempt at it was so poorly received.

For your convenience, I've added a nice tl;dr section at the top of each chapter.

tl;dr

Before

Before: KRs don't make sense without a goalBefore: KRs similar to metricsBefore: KRs lumped in with sub-goals
1 / 3

Key results don't really make sense without a goal and aren't the same type of object as a goal.

After

After: KRs added to existing goalsAfter: Custom terms and localization workaroundsAfter: KRs visually separated from sub-goals
1 / 3

Key results can only be added to an existing goal or objective, which is done entirely different from how goals are created.

Our first attempt at OKR support in our goal-setting app failed in early access. Once we found out why it failed, we created an entirely new system to support how our customers actually structure OKRs in their organizations.

As the lead content designer, I developed a new type system which updated our content and object model to bring in a taxonmy that better supported OKR models. I focused on the symbiotic relationship between Objectives and Key results, where you cannot have Key results without an Objective. But rather than make the OKRs the default for everyone, I developed Success measures as a generalized version of a Key result that would pair with the default Object type. Then, we gave customers the keys to customize their goal types as they saw fit, so they could use Objectives and Key Results, or the more "default" Goals and Success measures, or even KPIs or BHAGs or whatever else they might want.

Which I was opposed to from a scalability perspective, but giving customers that level of customization was a better experience that addressed customer requests. But it caused a bunch of localization issues that I had to resolve in the 11th hour, and plugging in fully custom UGC began causing language clarity problems after launch.

All in all, we delivered the OKR feature and saw ~1,500 success measures created daily for the first month of launch. Feedback in both public and internal channels was mostly positive, with many enterprise clients now willing to adopt the Goals app using this new system. You can read the full story below.

Prologue: An App is Born

tl;dr There was once an app called Atlas which let you share weekly project updates and monthly goal updates. Then one day, it was split into four apps: Atlassian Home, Goals, Projects, and Teams.

Atlas header

Before I joined Atlassian, there was an internal incubator program kicked up around 2019 that they called New Product Frameworks, or NPFs. It was a rigorous process in which you pitched a new product idea to Atlassian exec leadership, and if you got approved, you'd be fully funded to develop your product with your core team. Atlas was one such product that spun out of that program, and for a while, was its biggest success story.

The idea behind Atlas was simple: streamline, simplify, and standardize status updates on your work. Based on an existing Atlassian comms ritual called "The Loop", you would create a project for whatever you're working on that's about the size of an epic in Jira. Every Friday, you'd write a short, tweet-sized update (280 characters max) about what happened in your project that week. Then every Monday, your followers will read your update along with any other projects they're following in one nice, consolidated update feed. Same place, same time every week (or month for goals), meaning less pings saying, "Whats the latest on project X?" or "can you jump on a call and update me on the progress?"

And while it GA'd in 2023 (only a few months before I joined the team as the first and only embedded content designer), it was only in May 2024 that the product was moved to the Atlassian platform and its features offered for free to any customers with an Atlassian site. At this point, the Atlas homepage became Atlassian Home, meant to be the entry point to anywhere in Atlassian. For the next year, we would eventually see that each of Atlas's features would be split into their own app experiences: Atlassian Home would remain as is, but Goals, Projects, and Teams would each become their own app. While not fully relevant to this case study, my humble brag moment here is that I oversaw the communications and in-app changeboarding for each of these new app launches.

Chapter 1: What Are Goals Even Anyway?

tl;dr Using our single-object-type model in Goals, we created a lightweight type system to introduce custom terms and OKR support. It was not well received.

Fast forward to late 2024/early 2025 when the Goals app began developing a system to support OKR modeling within goals following a lot of customer feedback requesting these features. This was all a part of our push toward enterprise readiness, since Goals was used by many tech companies most of whom used the OKR framework and any larger enterprise companies require sets of functionality, including OKR representation.

At this point in time, Goals had a very simple object model:

  • You had goals
  • And you could nest them under other goals, making the nested goal a "sub-goal"
  • And you could link them to projects and Jira spaces (FKA projects, which this sentence may help explain the name change)

And that was pretty much it. While the initial intention with nested sub-goals was to act as a KR-like object, there were no distinctions between sub-goals treated as an actual sub goal and sub-goals that were KRs. Which brought us to our first iteration of goal types. Due to the typical timeline constraints and a public roadmap item we needed to meet, we opted for the simplest solution: give Goals app admins the ability to create custom goal types which would change the name without any significant functionality change. That way, you could distinguish sub-goals and actual KRs because the type label would indicate as much.

Or so we thought.

Customer feedback quote about goal types

We released the feature in early access to several customers, and received a lot of feedback that it did not fulfill a lot of our customers needs. Which meant it was time to go back to the drawing board.

Chapter 2: Feedback and Research Phase

tl;dr Customers felt the model was broken and didn't align with the actual OKR framework. They also really wanted to see OKR language in the app.

While some customers gave proactive feedback via the community group and other channels, we also had several customer conversations to dig into both the feature's inadequacies and what they were actually looking to create. From all these inputs, a few key themes emerged:

  1. 1.In our system, you could create a Key Result object without any other connections, but a sole Key Result object just doesn't make sense without an Objective to tie it to.
  2. 2.Many enterprise customers in particular wanted to see Objective and Key Result language in the UI, meaning they didn't want to see Goal objects — only Objective. More on this later.
  3. 3.While the type system distinguished between Key Result objects and Sub-goal objectives, they sat equally on a parent goal's list of Sub-goals and nested in directory lists without any indication of hierarchy or differentiation. In other words, they look as though they are equivalent, but they are not.

All in all, we had the rare combination where semantics and text labels actually mattered plus an underlying object model that was not fully clear or easy to understand. To move forward with a real solution, we had to untangle both the object model and the content model all at once.

Chapter 3: The Two-Model Problem

tl;dr Our object model in the platform apps overall were confusing compared to other premium apps. While other apps follow a normal App » Container » Collective object (primitive) » Object type model where every layer has a different name, Goals had Goals (app) » Goals (container) » Goals (primitive) » Goal (default object type).

As the content lead, I took the lead on sorting out this out by starting with the content model. One of the core problems was how we structure concepts within apps at Atlassian. The typical hierarchical structure that most of the Atlassian apps abide by is as follows:

  • App » Jira
  • Container » Space (FKA Project)
  • Collective object (primitive) » Work item (FKA Issue)
  • Object type » Bug, Story, Task, Epic, etc.

The 3rd layer, which we called a "Primitive", was where a lot of the content problem was happening. Looking at the above example, the "Work item" primitive refers to any of the following types collectively, giving a way to group several types under one term, which was particularly helpful in UI elements and microcopy. But for Goals, and actually all of our platform apps, they followed a… more confused pattern.

  • Goals
  • Goals
  • Goals
  • Goal
  • Teams
  • Teams
  • Teams
  • Team
  • Projects
  • Projects
  • Projects
  • Project

Backing up to the prologue where Atlas was debranded and split into 4 individual apps, it was decided (at a level above my paygrade) that each app would retain a smaller feature set (compared to a Jira or Confluence) and would adopt their core function as the name rather than get a branded name (like Focus or Confluence).

To go even further, each app (apart from Home) did not have containers built into the app—each app only featured a directory page with filters and saved views, but no other way to meaningfully group objects together.

Unlike Confluence and Jira, Goals did not have spaces or other container methods to group objects together. Just filters and different ways to slice the directory details.

Without any real containers, the next best thing was the title of the page, which you can see in the screenshot above is just the object name… again.

Until this point, none of these apps have had object types to poke holes in the content model. Because naming the default object type after the primitive isn't actually a problem when there are no other types. But once you have the collective Goals primitive and then there's a Goal type and an Objective type but both are Goals, it becomes unclear when to use what and whether the Goals primitive refers to just the Goal object or everything in the app.

While an entire content model overhaul across all three of our platform apps was not in the cards for this project, the next best thing was creating an object type system to move forward, with the intent of adding in as much scalability as possible for the other apps.

Chapter 4: Approaching a Solution

tl;dr We introduced Success measures which were only attached to a parent goal. This solved 2 of the 3 problems.

With all of this context and feedback and current state in mind, what did we actually come up with? We prioritized by the feedback first and foremost, then explored how the solution could scale to the other apps:

  1. 1.In our system, you could create a Key Result object without any other connections, but a sole Key Result object just doesn't make sense without an Objective to tie it to.
    a.SOLUTION: We needed to introduce a functionally different object that would nest under a goal and could not exist without it.
  2. 2.Many enterprise customers in particular wanted to see Objective and Key Result language in the UI, meaning they didn't want to see Goal objects — only Objective. More on this later.
    a.SOLUTION: We'd need a way to show custom terms in the UI where applicable, and ideally support whatever language experience customers want.
  3. 3.While the type system distinguished between Key Result objects and Sub-goal objects, they sat equally on a parent goal's list of Sub-goals and nested in directory lists without any indication of hierarchy or differentiation. In other words, they look as though they are equivalent, but they are not.
    a.SOLUTION: By resolving problem #1, we should theoretically resolve this one as well. Either way, we would list them differently and distinguish them in directory views.

In addition to supporting OKRs and other custom terms as types (similar to our original iteration), we knew that in order to properly support Key results in a framework-accurate way, we'd need to build something distinct from the goal object. Working in close collaboration with the PM and Product Designer on the project, we landed on Success measures, which were meant to function as both the primitive and a type in the same way Goals does.

The object model for Goals showing success measures as a separate primitive

Success measures, used interchangeably with Key results, would live primarily on the parent goal and be treated differently from sub-goals. They could only be created on the parent goal page and therefore could not exist without a parent attached.

As part of the content design practice at Atlassian, I defined Success measure as a new, dependent object type, owning the definition in the Atlassian System of Work library, an internal record of all the objects and concepts we use in our apps. I was already responsible for several other concepts, including how verification works at a systems level, but I'd developed the content perspective on Success measures from the ground up and solidifying it in the library felt like seeing it through to completion.

Functionally distinct ✅. Treated differently than sub-goals ✅. Now, if we could only solve that OKR language problem…

Chapter 4.5: Speed Bumps Incoming…

tl;dr In order to appease customer requests, we decided to insert custom user terms into our UI. It went poorly with localization, and we had to scramble for a solution, which ended up being a lot of manual "short-term" resolutions to abide by localization requirements.

The much trickier problem was figuring out how to incorporate OKR language in the UI without full clarity on how much OKR language our customers actually wanted. From our customer conversations, it seemed like a mix of opinions, with some wanting even the app to be called OKRs, some wanting UI labels to reflect "Objective" instead of "Goal". What we did know for sure was that "Key results" had to be in there in a significantly more meaningful way so customers would immediately know its purpose. And that's where Success measures started to fall a bit short.

While Goals had the benefit of being generally understandable in our cursed content model, Success measures was entirely made up and could not be easily understood without specificity. It was also long, so referring to Success measures as a primitive to include Key results would be awkward and not immediately be clear, not to mention customers who would only want Objective and Key result object types and nothing else.

I proposed three different options, with varying degrees of feasibility:

OPTION 1: Adopt Success measures as the primitive anyway, because this was the most scalable solution, the literal reason we have primitives, and it was already decided that Goals would still be the primitive even with Objectives as a OOTB type.

OPTION 2: Dynamically insert custom terms in the UI, which I did not recommend because of the unpredictability of custom terms in UI contexts ends up breaking a lot of contexts.

OPTION 3: Change the default object types to Objectives and Key results and let Goal and Success measure only be primitives. Not ideal because PM didn't want to force all our users into OKR structures.

So anyway, I lost this battle and PM decided to go with Option 2. This meant we'd have to flag all the places in the UI custom terms would be plug into and use Key results as a placeholder since it was the most commonly anticipated term to be plugged in.

Chapter 4.75: …Followed by a Sinkhole

I had a regular, fortnightly meeting with the localization PM who covers our apps. I shared the new flow using custom terms, and as expected, they flagged many concerns, most of which boiled down to these:

  1. 1.As part of our solution to include custom terms, we added a field for the plural form of whatever they chose. But for localization, some languages have several plural forms depending on the context.
  2. 2.For many languages, words may have different forms depending on the context of the sentence, similar to how verbs conjugate differently depending on the subject of the sentence. With the way the tool translates words, it may just spit out the custom term in the entirely wrong form, or worse, as just an error in the middle of a sentence.

I went back to the core root of the problem, as most of the feedback we'd gotten wasn't to include any custom term—it was only OKR language from customers who exclusively used OKRs and similar frameworks. What felt like the better, longer term solution was creating a split experience where goals language (besides the app name) were aligned to OKR language entirely. But this would mean pushing out our dev time significantly, not to mention the requisite design activities for swapping Goal out for Objective.

Working with the lead product designers on our team, we decided to follow Jira's solutions for including custom terms in the UI, which largely required separating out the custom term from any other content as much as possible. That would mean standalone microcopy with just the custom term and other workarounds to make it localizable. It wasn't ideal, but with the public roadmap deadline approaching and dev time being wasted waiting for final designs, we had to move forward.

This is what we originally designed and was ready to ship before localization problems arose
And this is how I adjusted the content labels in the UI to allow localization to proceed.

Chapter 5: And Finally, We Launch

tl;dr We met our deadline and launched to mostly positive results, with enough feedback to give us a clear path forward.

In the first month of launch, we saw ~1,500 success measures created per day, which was strong considering we released near the end of the calendar year. We deliberately left the onboarding experience on for about 2 months, which is longer than usual but would give returning users in the new year the opportunity to see it and experiment with the feature ahead of planning for following quarters and the fiscal year.

We managed to meet the roadmap deadline with a progressive release to our customers. While the announcement was met with mostly positive sentiment, ongoing feedback pointed out further gaps in our experience that showed we were generally moving in the right direction, at least moreso than our original release. We'd already been testing this model at different points in the design process, but we managed to get in a final round of usability testing a few months before our actual launch.

Usability testing quotes from customers

From the comments on the community thread announcing the feature and individual posts after the announcement, we can glean the following sentiment breakdown:

Positive

~9 posts (~15%)

Comments on the announcement post expressing excitement over the feature.

Mixed/positive

~22 posts (~37%)

Posts where the direction was praised, but questions, concern, or feedback were noted.

Negative/critical

~18 posts (~30%)

Posts that express frustration over functionality changes or specific aspects of its implementation.

No sentiment

~11 posts (~18%)

Posts that were troubleshooting, bug reporting, or seeking help/assistance.

A lot of the feedback and criticism was directed at the way progress and metrics rolled up to the overall goal's progress. Previously, sub-goals would inform the goal's progress, which we opted to maintain for any existing goals to prevent as much disruption as possible. Going forward however, goal progress would be informed by its success measures or key results with no option to go back to sub-goals. This, plus other feedback gathered from other channels, gave us clear next steps and fast follow improvements that I was actively working with PM and Product design on before my time at Atlassian was cut short.

Epilogue: Live to Write Another Day

In developing the sub-goal rollup feature, it became clear just how unsustainable our solution to the localization problem actually was. I was writing surfaces with the knowledge of localization this time around, but we were actively losing clarity by not being able to mention either Key result or Success measure in the guiding contexts of the feature. It wouldn't be just for a few surfaces either, every new feature we'd build would always come up against the same problem until we actually went with a longer term solution, which I believed was the experience toggle where users (likely admins) could select whether they wanted to see goal language or OKR language. Microsoft Viva Goals did it this way, so I'd begun thinking about how we might apply this to our own app.

To be clear, I don't think introducing custom terms was the wrong choice. It was a clear ask from our customers, and we knew we'd have to address it to keep up. But if we'd brought this up much earlier in the process, and possibly did more holistic assessments of how localization might've affected our plans when we were still exploring solutions, we might've been able to avoid a lot of these issues. Heck, our solution might've looked entirely different if we'd addressed localization and the OKR language problem a lot sooner.

I like this project as a case study, mostly because it took the better part of an entire year to work through, but also because it reinforces something I keep running into with content systems work: the hardest problems aren't the ones that look hard on the surface. The localization issue looked like a translation problem. The object model issue looked like a naming problem. But neither of them were as simple as it might've seemed on the surface—instead, the problem was in the structure and structural problems don't get better by throwing more words and labels at them. They only get better when you take the time to define the right structure first, even when the roadmap is breathing down your neck. That's what this work was really about. Not OKRs, nor goal types or success measures. Just the slow, careful work of getting the foundation right so that everything we build on top of it actually holds.