How do you build a product now in a way that will make future developments easy?
How can you ready your code so adding future features will be easy?
How do you ensure that if you need to refactor code later, the process will be as smooth as possible?
Find out about building scalable products from someone who actively chooses to scale challenges. Sagnik Nandy, the President, Technology and Chief Technology Officer of Okta, shares what he learned about building scalable products from his time working at Google - having been with Google Analytics in its early days as it went from its small scale as Urchin to the free, widely distributed Google Analytics we have today.
Here are some of the tips he shared on the alphalist CTO Podcast.
Products usually evolve in a standard way - no matter the industry.
This process will repeat itself, advanced features will always need to be developed, and code will always eventually need to be refactored. It's inevitable.
Therefore it's important that when coding any product- the coder has this in mind:
Plan to make room for new features that will need to be added over time
The expectation that what is the ‘best’ solution now will be the ‘old solution’ in a few years.
Components will need to be built neatly to streamline the eventual refactoring.
Repeatable/automated procedures should be in place to maintain code quality throughout.
It is important to think about the next level of scale when building your system.
What happens in systems is that growth is organic, it grows incrementally, and each time you make a change to ‘patch’ it. However, it will be a lot neater if you build from the outset in a way that is already ready to scale. Sagnik gives an example of a system built for K users where users increase in 10% increments and after each 10% growth, the engineers make changes to serve the additional 10% of users. Soon you have 5K users but its codebase/architecture is a patchwork of all the fixes the engineers did to serve the additional 10% of users. Things would be a lot neater if when building your initial product for K users, you build it in a way that it can smoothly scale to 5K users.
By [proactively] planning and anticipating for that next level of scale, [it] allows you to build and evolve technology for organizations in different ways over time.. -Sagnik Nandy, CTO of Okta speaking on the alphalist CTO Podcast
Referring to the Product Evolution mentioned earlier, the best products offer a simplified interface with complex functionalities.
It is difficult to balance our simplicity and complexity in product design. After all, by simplifying it, you usually remove options from users and when you add options, you often make it overwhelming for basic users. How do you cater to both basic users and to advanced users with a scalable solution that can be reapplied when each new feature is developed?
One way to do this is through a tabular architecture, whether you have a widget framework that allows you to drag and drop or something else, doing this in advance allows you to be extensible without paying that upfront costs or creating a large barrier to entry. - Sagnik Nandy, CTO of Okta speaking on the alphalist CTO Podcast
When you design the UI, it is important to keep in mind making space for future add-ons and functionality.
Keep in mind that someday you'll probably have users who will use very different parts of your product. Design your UI in such a way that it's easy to add on a different frontend UI design. - Sagnik Nandy, CTO of Okta speaking on the alphalist CTO Podcast
Make room for fringe use cases.
Of course, when designing your product, you build to satisfy the most users. Yet bear in mind, there might be a set of users who use just 20% of your product in one unexpected way and a different group of users who also use just 20% of your product again in a different way from the primary use case. How do you then evolve a UI in that paradigm that the main use case you designed for the majority of users does not hold back the fringe use cases used by the minority- with neither feeling like second-class citizens?
The problem is apparent in a dashboarding application like Google Analytics.
It needs to be simple enough for basic users yet complex enough for advanced users to hone in on specific parameters.
To suit the advanced users, you give everyone the tools to make their reports as you don’t know what people’s requirements for each report are.
But this makes it more complex for simpler use cases when users don’t even know what question to ask or where to start in building a report.
This creates a huge barrier to entry.
You do some market research and come up with 15 reporting templates for various use cases, which people appreciate. Yet more templates might be requested for more use cases, and soon you might have an overwhelming 30 reporting templates that people need to choose from.
So now you need to take a step back and go with a more tabular approach - one default app to start with that users can configure a tab and add more tabs Tabs would also be able to share with other users who can extend it as well. This gives flexibility. Then you can put the next 10 reporting templates in another tab without overpopulating the first one.
Can you keep the basic product as simple as possible and uplevel how advanced it is? This is also an issue in the backend. Many products do this through a very seamless tag-based integration that also provides additional hooks for advanced users. This might take the form of giving advanced users access to logs or the ability to do things server to server. These advanced technical features will differ from product to product so Sagnik advises building for the advanced technical features 80% of users would be interested and over time developing the advanced features for the other 20% (who might even grow to 30% by that time).
But the question is, how do you know where your product might take you? Sagnik sees it as a pre-build exercise to sit down and think of all the potential ways a product might grow. He also advises to keep in touch with the users - both by speaking to them pre-build but also always have an ear open to user feedback.
I like talking to customers to validate ideas. It's important to do this on an ongoing basis because when it comes to user trends and user assumptions—everything changes. E.g. Trends. You see waves. Today's right might be tomorrow's terrible. Today's great can be tomorrow's obsolete. I've seen this multiple times where users evolve a new use case or their user mix evolves; [while] your product might be expanding to areas that are different behaviorally from the needs of the users. So it's very important to always stay in touch and keep a pulse of ever changing trends. - Sagnik Nandy, CTO of Okta speaking on the alphalist CTO Podcast
He has also seen much success in forums where the product engineers interact directly with end-user challenges. It helps both the customers who either get their feature request prioritized or an alternative solution suggested and also the engineers who get the satisfaction of seeing their product changing lives.
As you add more features and layer on the complexity, be aware that the time will come when you will need to refine your whole stack, refactor it taking into account all the new features. You might change which features you want to include in the core product and which ones you want to include as optional add ons for power users. Frameworks do this a lot.
Sagnik brings the example of Ruby on Rails which as its popularity grew, so did its complexity, and soon it was just one big bloated product. Until one day, it was refactored into a smaller core that simplified the inclusion of some new features and left other complexities as optional add ons. People preferred the shrunken product over the complex one that had evolved over time.
This is a part of the product evolution cycle. As you add new features, you will also have to refine existing code to remove bloat. This means that the existing codebase should be written in a way to make the refining process as simple as possible. This brings us to the next tip - build for deprecation. Build your code for deprecation.
Build for deprecation: Build solutions in a way that when it needs to be replaced, it can be replaced easily.
Add deprecation support as a first-class thing in your system’ says Sagnik. This is key advice he heard from his mentor.
Many times when a company does a complete overhaul, migration, or just a drastically different solution that solves a lot of problems - engineers think ‘finally, we have a solution that solves all problems.’. But in reality, no solution will ever solve all problems infinitely. There will always be a need for new features.
New technologies will develop, and eventually, what is the ‘perfect solution right now will need to be replaced. It is therefore important that the person building the current best solution has in mind the future engineer who will be replacing it with a better solution down the line. Replacement gets harder as it goes lower down the stack. Take storage, for example, where formats are often so intrinsically attached to higher layers.
Take, for example, a company building a new API or exposing a new API at a certain point. The engineers need to not only have to build it so it solves the challenges of the old API, but they also need to think “someday someone will have to move away from this API. How can I design my API in such a way that it's eventually if this has to be replaced, it makes that replacement that much easier? “
There are things that every team, every company does exceedingly well. You don’t want to lose that quality as you scale, especially because today's excellence becomes tomorrow's expectation. How does one linearly maintain outstanding quality as they grow? To try to do it manually is simply unsustainable.
So how do you scale excellence?
Everyone should think “How can I do that same thing with maybe 10%, less effort, 20% less effort. How can this thing being done well now be done equally well or better in an easier way”. This kind of thinking usually leads to improvements like automation, better tooling, which allows excellence to be repeatable even as the company scales.
In this article, we learned about building scalable products from the CTO of Okta. He pointed out ways one should code the product from the beginning to allow for feature expansion, code deprecation, and how to encourage excellence is maintained throughout.
This article was based on an alphalist.cto podcast episode.
The alphalist podcast is a podcast for busy CTOs, VP Engineering and other technical leaders. The alphalist podcast features interviews of CTOs and other technical leaders and topics range from technology to management. Guests from leading tech companies share their best practices and knowledge.
The goal is to support other CTOs on their journey through tech and engineering, inspire and allow a sneak-peek into other successful companies to understand how they think and act. Get awesome insights into the world‘s top tech companies, personalities and trends by listening today on Apple, Spotify, Google, Deezer and more.
Also published here.