Most of us, engineers, don’t work in a void. We write products and features that come from product managers. It is no secret that there is often tension between these two roles. Product Managers aim to push many products and features to production fast. Software engineers, on the other hand, want to slow down the pace, develop things that are more robust, tested, and designed properly.
Yes, it’s true, product managers are from Mars and developers are from Venus, however, in spite of these differences, we need to learn to work together. In this blog I’m going to share a tool with you that can help achieve this goal.
When I was fresh out of college I was lucky enough to get my first job opportunity at a company that had amazing mentors. They taught me a lot about design principles, quality, tests, basically, the dos, don’ts, and hows. It’s these exact principles that turn us from code monkeys into software engineers. For me, these ideas were not hard to accept; they just fit my personality. I’m a software engineer at heart. I worked there for over 3 years and then decided to move on.
My new reality was a small POC turned into a full-blown product, which in other words meant legacy from day one. Classes with over 2000 lines a code. Tests were an afterthought, if at all. Refactoring was sort of a hallway joke; there was no justification for the time it takes to do it. And finally, an ever-growing list of features. Every feature was either piled onto the end of a never ending list or a “stop everything you are doing and work on this now” type of feature. Naturally, this feature is as important as the current feature I was working on.
This was a world where the basic understanding of technical debt and how it will eventually shoot us in the foot, was a lost concept. My days were filled with arguments about why things like design principles and testing are important. You know, the kind of arguments you think don’t need to exist anymore. Software has been around long enough for these things to be obvious. It turns out, they aren’t, at least not to everyone. Someone like me can’t survive long in a place like this and 2 years later I was on the way to my next adventure.
Wix was a dream come true. It was everything I could have hoped for. Back then, around 5 years ago, we were around 20 backend developers, all engineering oriented, all fighting for the cause that no product manager will ever give us a deadline again.
Quality above all! Engineering over deadlines! But in the end, the perfect products that we wrote took way too long to get to our users. We weren’t able to deliver quickly enough to create value for our clients and, at the end, for our company. It took some time but we eventually realized that we need to find some balance.
As software engineers, Kent Beck, whether we know it or not, has influenced our lives in many ways. Some of his most noteworthy contributions include the notion of software design principles, extreme programming, and Test Driven Development (aka TDD). About a year ago, I heard him talk about a new concept, the 3X model. I didn’t know it back then but this concept would have a huge effect on how I think and write my code.
The 3x Model:
The idea behind this model is to look at a product or feature in phases. These phases are known as Explore, Expand, and Extract. We put these phases on a graph in order to illustrate a feature’s impact on our users and on the business. The Payoff of the feature is when it starts having an effect on the company’s KPI, whether it be more money, more users, etc. The Success of the feature is a measure of how many users actually use it.
This model is super useful because if you think about it, most of the products or features we develop aren’t heavily used. Why is that? It’s because most of them don’t come from the users themselves, but rather, from product managers or other stakeholders who believe they know what the users want.
Let’s look at a contrived, very simplistic, example just to give us a basic understanding of how the model works. It will be much easier to understand the technical real world example that follows, once we have a good grasp of the idea first.
Our Product: Something that brings our users from one place to another.
The “Full Blown” approach:
The first thing that comes to mind is a big, beautiful car. This is the perfect product. Building it definitely answers our requirements.
It allows our users to go anywhere they want, no matter the distance, as long as they don’t need to travel over a big, bridgeless body of water.
The 3X approach:
Phase 1 - Explore
This phase is about defining your MVP or Minimal Viable Product. Think about a product as a building, in order for a building to stand and not collapse it needs supporting pillars. Our MVP is exactly this, a list of pillars, or key features, whose failure to exist makes us fall short of our goal. In this case, our goal is to get our users from place to place. So we decide to start with a bicycle.
What’s cool here, is that this product is released way faster than the car, meaning our users can start getting value quickly. If our users are getting value it means our company is getting value.
We run with this product for a while and as it turns out, it’s super successful; our users are loving it. They love the fact that they can get from one place to another without thinking about parking.
Their main complaint is that the further the distance, the more complicated it becomes to travel there.
Phase 2 - Expand
This phase is about solving bottlenecks as a result of increased usage.
Based on our users’ inputs, we understand that our biggest bottleneck is distance. We solve this bottleneck by releasing a motorcycle.
Users can travel greater distances while keeping their most loved perk; parking is easy.
Our users love this upgrade. By the way, while we were busy working on it, our users were still getting value from our first version.
Phase 3 - Extract
This phase is about creating a product that is here to stay. The transition to this phase happens once we have a clear vision of where our product is going.
In our case, user’s are loving their motorcycle but their main concern is the sense of security they have when the ride. A lot of our users also have kids.
The motorcycle was problematic for them as well. However, the parking perk was something they really didn’t want to lose.
Now we have a very clear idea of the product our users want, it’s time to extract!
Similarly to the full-blown product, our final product is a car, but it’s a small one. Had we started out with the full-blown product, we would have developed a huge unparkable car. This means that we would have ended up with something that doesn’t meet the needs of most of our users.
Moreover, we would have come to this realization after a very long development cycle.
The 3X model, because of its modular nature, allows us to work within shorter development cycles; cycles that give value quickly. The value is twofold: give users a product quickly and fine-tune the product according to their needs. Remember, value to our users means value for our company.
The contrived example is great way to illustrate why most of the full-blown products/features we build, ultimately don’t withstand the test of time. We lose something very valuable, namely users’ voices. We waste tons of time over productizing and over engineering. Don’t get me wrong, I truly believe engineering standards are important, but the question is when?
If we’re out “exploring” a product that ends up “dying”, the technical debt will die along with it. If not very many users are using our product, then there is no point in over-optimizing it. The point is, we never know what’s here to stay and we shouldn’t waste time on something before we know it’s a keeper.
If you’re rolling your eyes at this point because your life experience has taught you that technical debt, once there, is hard to get rid of because product managers never feel it is justified, you’re probably right. The challenge is building a relationship with your product manager. The relationship needs to be a give and take. You need to build trust. The 3X model is a great way to do it. Why? Because it allows you to generate value, namely users using your product/feature quickly. Product Managers will love that. The condition needs to be, if users love it and we start hitting the bottlenecks, we stop and harden the product. No patches.
3X Model: The Wix Logo Maker
A theoretical example is nice because it’s very easy to grasp the idea of what 3X helps us achieve. So now I would like to take you from the theoretical into the practical.
A few months ago we developed a product called the Logo Maker using the 3X tool. Let’s see how it worked in practice.
Goal: Wix, the one stop shop for all your business needs, starting, but not limited to, a website, would like to allow a user to create a logo for their business. We aimed to get it out to our users as quickly as possible.
Phase 1 - Explore
MVP (Minimum Viable Product) - The ability to create a logo on both desktop and mobile, and get paid for it.
Svg - vector file defining the logo. Can be thought of as a logo blueprint.
Batik - apache library in charge of taking the svgs and making png files out of them
SSR - server-side rendering (Node js server)
Explore Architecture (Launch Time ~ 1 Month):
In this phase we have very simple architecture: Browser client, Node Server for SSR, Scala server for the rest of the application logic, and MySql database for our persistence needs. At Wix we have hundreds of microservices running in production. We make use of some of them here as well.
Phase 1 was deployed to production with the following known issues:
Batik library has a huge memory footprint and, therefore, we have a huge potential for out of memory (since we don’t limit the number of simultaneous users that can potentially hit the batik flow).
Batik is slow so logo generation takes minutes
Very few alerts, ie, we don’t know when things go wrong
No (or very little) error handling - this was mostly an optimistic flow
Bad Software Design - This was definitely not the poster child for good engineering. The only thing I emphasized was testing. Very few things were untested, even if the tests were big and covered way too much. I always had the confidence of deploying a change into production without breaking the entire thing.
However, phase 1 was deployed after only 1 month. 1 month! This means that even with all these issues, we already had real users giving us feedback on the product. It also meant that we’d started to generate revenue, which is a huge deal!
Phase 2 - Expand
How do you know you’ve hit phase 2? You notice growth; people are actually using your product. But that alone is not enough. We are also starting to hit some bottlenecks. In our particular case, we started receiving complaints of users not receiving their logos. Two notable bottlenecks emerged. The first is that since users complained it meant that we didn’t have the right alerts in place (it’s best to know something is wrong before the users know it is). Second, we needed to start dealing with and healing from errors.
We can see 2 new components added to the system in this phase. The first is that we started to fine-tune our alerting mechanism. After researching the problems users were having, we were able to create specific alerts for users not receiving their logos, as well as alerts that hinted of other possible problems.
The second component we added was a healing mechanism via Kafka. This allowed us to retrigger failing flows easily.
We still had a running service in production with some of the known issues discussed above. The improvements were small but very meaningful. We could now know that something was wrong before the users themselves. This is a huge win for support.
Phase 3 - Extract
The logo generation process via the node server is much less memory intensive. We also added another safeguard; we limited the traffic to this server by not sending requests directly to it, but rather via Kafka. This allows the Node server to decide how many simultaneous requests to logo generation it can handle at once.
The second component we add is a component called W.A.A.S or Website As A Service. This allowed us to give users not only a logo but also a website generated from their logo using AI and machine learning. The final component we added was an integration with a third party that allowed us to sell business cards to users from the logo they made (a heavily requested feature).
Developing a product like the Logo Maker in one month seems like a nearly impossible task. What made it possible is the very accurate definition of our pillars. Developing the “Expand Architecture” from the get go would have taken months. In addition, we would have gotten it wrong; the second Node server would have most likely been a Scala server. The limitations of Batik, namely the issue with “what you see is not what you get”, would never have been predicted during development. This feedback turned out to be vital for shaping our final architecture.
I want to sum up the ideas raised here. The 3X model is not only a good way to think about development, it’s also a good trust exercise for you and your product manager. If done well it’s a win win situation. We need to let go of the notion of a “perfect product”. There is no such thing. The only notion we should have in our minds is the notion of a “successful product”. The success of the product is dictated by our users, and therefore, the sooner they get their hands on it, the better.
In order for this idea to be feasible we need to first define our goal along with the key features that define it. Remember, the key features are the pillars of a building, those that the building collapses without. This step is probably the hardest because all features are important, but not all features are a must. We have to differentiate between the two. Eventually you will discover that many of the features you thought were important, turn out not to be.
This is true for features being developed on top of existing products as well. Define your goal, split the feature up into baby features, and out of those extract your pillars. Start with those and move on from there.
My biggest takeaway is that 3X is the ideal implementation of the saying “don’t over optimize”. Do things as they become necessary. Fix what hurts. Don’t write patches.
This post was written by Netta Doron
For more engineering updates and insights: