The Pragmatic Engineer - Notion: going native on iOS and Android
Episode Date: December 11, 2024Supported by Our PartnerDX → DX is an engineering intelligence platform designed by leading researchers—In today’s exciting episode of The Pragmatic Engineer, I am joined by two members of th...e Notion mobile apps team, Austin Louden and Karn Saheb. Austin and Karn joined Notion in 2019 when Notion was revamping its mobile apps. Notion is a versatile productivity and collaboration platform that combines note-taking, task management, and knowledge organization into a single workspace. It is available as a web app, as well as iOS and Android apps for mobile use.In our conversation today, we take a deep dive into how the Notion mobile team operates and discuss the following: • What the engineering culture is like at Notion • Why the mobile team focuses so much on app performance• The incremental shift from Cordova to Native • Notion’s tech stack and frameworks they rely on • How the mobile team maintains consistency across iOS and Android• Unique features of the development process, including a public beta, using modules, and practices around feature flags• … and much more!—Timestamps(00:00) Intro(02:03) The RFC process at Notion (06:00) How Notion uses internal channels to share RFCs(07:57) Some of the unique ways the mobile team works(11:07) Why they don’t do sprint planning at Notion—and what they do instead(12:57) An overview of the size of Notion and teams at Notion(13:15) The beginning of mobile at Notion(14:40) A simple explanation of Cordova(15:40) Why Notion decided to revamp mobile in 2019 and shift to Native(18:30) How the mobile team evaluated performance as they made the shift to Native(22:00) Scaling mobile and iterations of moving to Native (26:04) Why the home tab project was so complex(30:59) Why the mobile team saved the editor for last and other future problems(34:35) How mobile works with other teams (36:50) How iOS and Android teams work together (38:28) The tech stack at Notion(39:30) How frameworks are used(41:57) Pros and cons of different frameworks and why Swift was the right choice(45:16) How code reviews work at Notion(48:23) Notion’s mobile team’s testing philosophy(50:18) How the mobile team keeps compile time so fast(52:36) Modules in the iOS app(54:50) Modules in the Android app(56:44) Behind the scenes of an app release and the public beta(1:00:34) Practices around feature flags(1:03:00) The four dev environments at Notion(1:04:48) How development apps work (1:07:40) How and why you can work offline in Notion mobile (1:10:24) Austin and Karn’s thoughts on the future of mobile engineering (1:12:47) Advice for junior engineers(1:16:29) Rapid fire round—The Pragmatic Engineer deepdives relevant for this episode:—Where to find Austin Louden:• GitHub: https://github.com/austinlouden• LinkedIn: https://www.linkedin.com/in/austinlouden• Website: https://austinlouden.com/Where to find Karn Saheb:• GitHub: https://github.com/Karn• LinkedIn: https://github.com/Karn• Website: https://karn.ioWhere to find Gergely:• Newsletter: https://www.pragmaticengineer.com/• YouTube: https://www.youtube.com/c/mrgergelyorosz• LinkedIn: https://www.linkedin.com/in/gergelyorosz/• X: https://x.com/GergelyOrosz—References and Transcripts:See the transcript and other references from the episode at https://newsletter.pragmaticengineer.com/podcast—Production and marketing by https://penname.co/. For inquiries about sponsoring the podcast, email podcast@pragmaticengineer.com. Get full access to The Pragmatic Engineer at newsletter.pragmaticengineer.com/subscribe
Transcript
Discussion (0)
how hard can it be to just render a list?
Turns out it's quite complicated, especially because Notions data model is very complicated.
One of the things that people really love about Notions Data model is that if you have a
to-do block, you can convert it into a heading or you can convert a heading into a call-out.
And a lot of these blocks are interchangeable, and they're interchangeable in a way that sort of
preserves the content in those blocks.
And on top of all of this is that notion is very reactive.
So a lot of the changes that you see or that you make in your Notion workspace are in near real-time
reflected on your other devices. So there's a lot of like zero to one work that we were doing to
build out the real-time connectivity, build out the reactive patterns, and then all while keeping things
fast and efficient. Notion is a productivity app and platform with more than 100 million users.
In today's episode, we go to behind the scenes into the nitty-gritty details of how Notion built its
mobile apps. Notion's native iOS and Android mobile apps are used by tens of millions of mobile
users, and about half of new Notion workspaces are created on mobile. At the same time,
Notion's mobile team is surprisingly small.
Currently 11 engineers, even split between iOS and Android.
For today's conversation, I set down with two long-tenured engineers on the Notion mobile team.
Austin Loudon is an iOS engineer and a tech lead manager for Notion's mobile platform.
Carnes the Hub is a software engineer focused on Android.
In today's episode, we cover what the engineering culture is like at Notion and why the mobile team focuses so much on app performance,
why Notion decided to rewrite their mobile app from using web views to native components,
and why they did this incrementally,
Notion's mobile tech stack,
approach to code reviews,
release and testing process,
and many more details on how the mobile team operate.
Whether you're familiar with mobile engineering
or you'd like to learn more about how large mobile apps are built and operated,
this episode is full of insights hard to otherwise come by.
If you enjoy the show,
please subscribe to the podcast on any podcast platform and on YouTube.
So today we have here with us from the notion team,
Karnsaheb and Austin Loudon.
welcome to the podcast.
Thank you for having us.
Yeah, thanks for having us.
How is notions engineering team different in some ways that you work compared to some of your previous workplaces?
I'm kind of asking like what are some things that feels like it's kind of a unique notion engineering culture, maybe not as common elsewhere?
Yeah.
One thing that I haven't seen elsewhere is just this RFC process where the vast majority of product change.
especially earlier on in Notion's history were kind of driven by engineers through RFCs or requests for comments.
And this meant that kind of end-to-end the product was being driven, like, you know, through engineering essentially.
And then those RFCs were shared company-wide where, you know, anyone could comment on them, you know,
leave feedback, things like that.
I mean, that is the request for comments.
And that practice is more or less continued today where whenever we want to introduce a new set of changes, it's up to,
you, you know, as the engineer to write out the RFC and then tag everyone that you feel like
would have an opinion on this product change for them to review it. We kind of still see engineers
driving kind of the process from beginning to end for a lot of futures. So yeah, I think that's
something that's fairly unique. Then obviously the document is notion, right? And the tagging is
notion, a commenter notion. Yeah. Yeah. It's very helpful that everything is in notions and just
makes it easier to navigate.
Yeah, whether that, I mean, I think that would be one major takeaway.
Like, you know, whether you're using Notion or not, obviously we hope you use Notion.
But having one tool that your company is using, the efficiency gains are very difficult
to describe.
It is just immense because there's no question about, you know, where do you create tasks
or where do you find a specific document?
Like, 100% of it is in motion.
And, yeah, that just ends up saving a lot of time in the long run.
I think part of, you know, like the engineering culture to, like, sort of, like, write these, like, RFCs are just documents.
And, you know, Austin mentioned that anyone can comment.
You know, we mean anyone can comment.
For a long time, there weren't a lot of, like, product folks at Notion.
Oh.
And, you know, folks from, like, different functions were sort of in these documents, leaving feedback and helping it sort of iterate on sort of the thinking that we had or that we were sort of describing.
And, you know, whether it's like senior leadership or.
engineering managers or like other engineers in like different functions or, you know,
park marketing, growth, you know, everyone was sort of involved in these processes. And I think that like
part of what made some of like our work very successful was that having this sort of high
ownership, high buy in environment for everyone to feel empowered to contribute at this level, you know,
in the design documents and in the technical specs and say like, oh, is this the thing that we want
to be building for our users. This episode was brought to by D.S.
a platform that helps organizations measure and improve developer productivity.
The DX team includes notable researchers behind the frameworks like DevX and Space,
so they're constantly asked by leaders, what metrics should we use to measure developer productivity?
To help simplify the landscape, DX just recently published the DX Core 4,
a unified framework for measuring developer productivity that encapsulates Dora, space, and DevX.
The DX core 4 includes four dimensions including speed, effectiveness, and
quality that provide a focused set of metrics that help track productivity at all levels of the
organization. You can learn more about the DX score four and how it's being using companies like
Dropbox, Etsy, Versal, and Pfizer at getdx.com slash core four. Again, that's getdX.com
slash core four. I imagine there must be a lot of visibility in a sense that it's one thing to have
a document but people need to know about it. Is it like advertised somewhere or just you use search
or like teams have it, you know, like in a well-known places.
How do you do that?
Or use email?
I think there was, for us, I think now our process is just like, you know, we use
internal channels to communicate this.
And, you know, if you're interested in like reviewing specs, obviously we're like
kind of at a stage now where it's not feasible for everyone to have an opinion on things.
But now, you know, there's like internal channels for us to communicate that like, hey,
here's a new document that we want to get feedback on.
So like internal chat channels.
Yeah.
So we have a Slack channel, for example, where,
all like major RFCs that are published are shared in that channel. And so there are a lot of folks
that are just kind of watching that channel as they come through. We also have like rotations where
engineers are kind of on the hook for reading all of the RFCs that come through or like within a
particular domain. And so, you know, for a period of maybe like six months or so, you might be on
kind of like this RFC review committee. That way we ensure that. Yeah, essentially, I think that's
necessary to balance things out in that, you know, with mobile, for example, like, we used to see
a lot of RFCs where, you know, there wouldn't be a mobile section at all in the RFC, you know,
like they would talk about the products, but like there would be no mobile considerations.
And so now it's helpful having somebody from the mobile team on that review committee that will,
you know, surface that as an issue if it comes across.
Yeah.
As team sort of scale, I think it becomes important to have like a distinction between like the
voices that are sort of important to the decision making and folks who are playing a sort of like
supplementary role. And I think like the review committee is like a one example of where,
you know, we sort of outline these like nice boundaries around who's helping make decisions and
sort of drive decision making. Yeah, but I'd like to hear how you just added it and as it made
sense, right? You're going to start it with a free form and then you slowly just like change it to
make it work for you. What are some unique things that the mobile team specifically does?
at notion that are like, you know, like part of the mobile engineering culture.
And I think earlier you told me there is like something around like your,
you have meetings on Mondays?
Yeah.
We do have, we do have a Monday meeting.
One thing that probably is unique, at least I haven't seen before, is we do like a
weekly performance review where we look at all of our top line performance metrics.
Also like mobile app performance.
Yeah, mobile app performance specifically.
Wow, nice.
And yeah, I think that just kind of came out of this time period where, you know, we really weren't happy with the performance of the mobile apps.
And so it's just kind of that mindset where you have to look at the metrics that you want to improve every week to actually get, you know, yourself to make progress on them.
And so, yeah, for the last four years, I would say we've been looking at, you know, our top line mobile metrics, specifically performance-related metrics every week.
Yeah, the Monday meetings are definitely like one of them.
my favorites. I think it's a good way to sort of start up the week. And, you know, to sort of expand
on how we think about meetings, we have like two main meetings at week. I think we're, you know,
a lot of companies do like daily stand-ups or they have like sort of like recurring sinks, sort of
multiple days of the week. But I think at notion, especially on the mobile team, I think we're very
much like very mindful of like the time that engineers have to do heads down work. You know,
there's like a lot of interruptions in the day and like one meeting at the wrong time slot is.
is like kind of throw off your entire day.
And so we have these sort of like two main meetings,
the Monday sync is like a great way for us.
So like catch up, review performance and then sort of chat about the things
that are important to the team.
We have this like section called like the tactical meeting,
which is sort of like these small items that we want to chat about.
And we spent sort of like two or so minutes in sort of like a group setting.
And then sometimes, you know, discussions last longer than that.
And we move them async.
So it'll be like a slack thread somewhere about.
about sort of a continuity around the sort of thing that we were discussing.
And then there's, you know, these Thursday things that we have,
which are sort of like projects in progress meetings where we review the work that's being done
and how we're moving towards the sort of deliverables that we have for either the sprint
or for the milestone or for the project as a whole.
It gives us also time to like reflect on some of the KTLO work that we're doing
and manage like external dependencies that we need to sort of be aware of.
And then I think my favorite part is like demos.
We talked about performance a little bit.
But, you know, as Austin mentioned, we weren't really happy with our performance at a certain point in time.
And so some of the things that we built in was if you're ever looking at like a performance regression,
one of the things that you do is you demo your investigation in these like sort of Thursday sinks.
Oh, nice.
And that's a good way for us.
I think like, number one, to like share knowledge on like how to do these investigations.
Because, you know, doing performance investigations are kind of hard.
And to spread the knowledge and have people sort of ramp up on performance investigations is like kind of like important.
And so these demos are like a great way to do that.
And there's also like sort of like design demos and sort of like future looking things, which makes sort of like the Thursday meeting super exciting.
But you mentioned sprint, but you also told me earlier that you don't do sprint planning.
How does that add up?
Yeah, we don't really formally do sprint planning, but we do have kind of higher level.
sprint commitments. So we do work on like these two weeks cycles. And at the beginning of the two
weeks, you basically say, you know, what do I want to get done over the next two weeks? And so this is
much, much higher than the task level. And usually only is like, you know, two or three bullet points
enough to describe like, I want to build this section of this feature or eventually later on it gets
to the point more of like, I want to ship my feature to dev or, you know, ship it to production,
launch the experiment. And then, you know, after the two weeks goes by,
I will go through and people will talk about, like, you know, were they actually able to
kind of make progress in their sprint commitments? You know, if they weren't able to make it,
you know, like, what do we not account for, you know? So I think that cadence works out pretty
nicely. So would you mind sharing some context on Notion in terms of the number of users you have,
how big we can imagine this app to be in complexity users, that kind of stuff? Yeah, so we recently
crossed 100 million users, and we have around tens of millions of users on mobile.
About half of new Notion workspaces are created on mobile.
So it's a pretty substantial top of funnel for Notion generally.
A lot of users will start on mobile and then potentially move to using it across multiple
devices, like on desktop web.
In terms of the team, Mobile Team has 11 engineers, and that's roughly split between iOS and
Android. Notion altogether has around 600 employees. Wow. So that mobile team is not really
thick. Is it a more senior team? Is it a mix of juniorities? How can we imagine that?
Yeah. So in general, Notion started out pretty senior heavy, I would say. We wanted to look for
folks that were kind of around five plus years of experience to start. And now I would say we're
evening out a bit more. We've started an internship program recently and a lot of interns.
have converted to full-time.
So we're getting a bit more of a balance, but initially, yeah, Notion overall was quite
senior heavy.
When did Notion first ever have a mobile application?
And I understand this was before you joined the company, right?
Yeah, I think it was before both of us joined the company.
The original Notion mobile apps, I think, were around 2017, where we kind of like published
the first versions of the apps.
And they didn't really see a lot of active development until around 2019 when we started
investing a little bit more in the mobile experiences.
And for a long time, it was just like a small wrapper on what is effectively like the browser app.
Can we talk about that?
What was this first version of the app?
What technology did it use?
And, you know, how was this wrap around?
Was it a WebView wrapper or something else?
Yeah.
So the initial app used Cordova.
So it was effectively just a wrapper around our mobile web app.
but for a couple of, you know, OS-specific things,
we were able to use Cordova to hook into that.
And then later on, we moved from Cordova to React Native.
Although I wouldn't necessarily consider this React Native in the traditional sense.
It just used React Native purely for those kind of like OS hooks.
So, for example, if we wanted to make the app like vibrate or something like that,
you could use like the React Native API for it.
But it was predominantly using just a single web view.
component that was rendering, you know, our mobile web view, essentially.
And for people who are not as familiar with Cordova, because these days it's not as popular,
would you mind just a refresher of what it is and, you know, why not just, you know, use the
traditional web view? Like, what advantages did it give at the time? Yeah, so Cordova provides
a way of writing kind of cross-platform code to where you don't actually have to write native
Swift or, you know, Objective C, C, Kotlin, Java. And instead, you can,
just kind of write plain JavaScript and have those hook into, you know, like native APIs, essentially.
So it provides kind of a lightweight way of using a, you know, web view predominantly for your app,
but then like, you know, using some of the OS capabilities, like if you wanted to force the phone
into landscape or, you know, make it vibrate, things like that.
So Notion had this app.
It sounded like a somewhat more simple app back than 2017.
and then the two of you joined in 2019
and you decided, all right, let's do something more native.
How did this happen?
And how did you even make this decision?
Because that's a pretty big decision to say we're going from some,
you know, HTML wrapper, pretty basic stuff.
We can reuse a lot of our web logic to starting from what sounds fresh.
Yeah.
I mean, you bring up a good point,
which is that like we already had a bunch of like existing work done
to make the mobile apps sort of like relatively
good for the Notion experience.
And if you've ever used Notion, you know that it's like a relatively complex product.
It's not just like, you know, text blocks or to-does.
There's, you know, collections and embeds, which kind of make it a very complex offering.
And so, you know, on this time, sort of like 2017, 2018, if you look back at that time and
you ask users, like, how they thought about the mobile apps, I think one common complaint
you'd probably hear is that the performance wasn't that great.
And if you think of using Notion in the way that most people use Notion, so if you're like, especially on your phone where you're like, you might be at the grocery store and you're like, I need to take down some notes and like, you know, put a new grocery items or you're on the go and you want to take, or you're on the go to like work and you want to take down some notes just something to remember.
Having a sort of poor experience isn't ideal.
And it makes it sort of frustrating for users to continue to use a product.
So one thing that we wanted to do is kind of address this like performance problem.
And a lot of our sort of decision to go to native was premeditated on this idea that like if we moved things to native, it would get faster for us.
And, you know, I remember I think it was like 2021 sort of like the end of the year.
We'd sort of come out of this offsite with what we felt like was a sort of crisp vision statement on how we thought we wanted the mobile apps to appear.
And what we'd set along at the time is like everything except to the editor would be native.
And that's kind of like what was our guiding principle going into like making things native.
And over time, you know, we were like building out these tabs, you know, the home tab, the inbox and search tabs,
which are kind of the prominent entry points into the different parts of notion.
And we'd start there and we said if we slowly convert these to native, we can see the performance benefits.
And it was also like a, you know, a good way for us like stress test native.
We'd start small, build incrementally, and then, you know, sort of like verify our findings
and see if we were actually making the apps better.
And, you know, what we found was that they were moving to native made things better for us.
Now, I just want to push you a little bit because I've heard this a lot of when mobile engineers say,
I'm kind of putting my hat as a CTO on, for example, mobile engineers come like, oh, let's do native
because it will be more performant.
But this was around at a time, right, in 2019 or 2020,
let's say a company like Coinbase said we're moving away from native
because we think React Native is performance enough.
How did you, you know, what did you look at at performance?
What did it mean for you to say, okay, we're going to measure this
and we're seeing that it is indeed more performant?
Yeah, I think it really comes down to like app start time.
And so for us, like a metric that we look at pretty closely is something we call initial home render,
which is just the time it takes from you to tap on the app icon to Notion to appear and all of your items in the home tab to be visible.
So we knew that there was effectively a ceiling as to how fast we could make it if we kept the web layer around essentially.
And the reason why that's slow is because we have to boot up a web view and then we have to kind of load our entire Appjs bundle.
I think there are ways that this could be done a little bit faster.
You know, if you've modularized to the extent where you're not really loading a large bundle,
but we're effectively loading all of Notion when we launch the app,
which means, you know, our launch times were a second and a half or two seconds,
which is, you know, fairly slow for industry standard.
And so we felt like we would never really get to the point of like an industry standard mobile app
without kind of substantially, you know, moving the needle.
For things like React Native or, you know, like alternative technologies like that,
I think we still didn't, we weren't convinced that we could go as far as we wanted to go
without being purely native.
I think there's still kind of a ceiling there with those types of technologies.
But that wasn't, you know, it didn't really meet where we wanted to go with it.
I mean, clearly there's a ceiling for every technology, but do I have a ceiling?
I sense correctly that what you're saying is that by going native, you can keep it at the
bare minimum, right? You do have the option of cutting back everything. You know, you have to
give up a bunch of stuff to have the fastest boot up, you know, with the Hello World application.
But you can actually control and tweak and make those tradeoffs yourself, right?
Yeah, I think that's kind of what we were thinking would be like the biggest benefits of moving
to native is that we'd have more granular control on like what exactly our startup path
look like. And if you think about like web technologies or, you know, just like React Native or
Kredova, for example, they're usually just these like shim layers on top of the OS. And it's like
anything that we could do to kind of get rid of the shim layers was an improvement in our part.
And that would help us improve like startup performance. Yeah. Especially with, you know,
Notion is competing against a lot of personal apps. Like, you know, we compete against like Apple
notes and Google Keep, which are all fully native. And so, you know, for certain companies, you know,
like Coinbase you mentioned, it might make sense for them to be able to use something like React
Native. But for our market, I feel like, you know, if we're competing against Apple Notes, we have
to be, you know, near to as fast as Apple Notes. Otherwise, we don't really feel like it's feasible.
Yeah. Or you even try to be faster if you can, obviously. It's a high bar. But yeah, that makes a lot
of sense. And I think it's a good reminder, right? Of like, there's no universal things, right?
right as you said, it depends on who you're competing against, what your priorities are.
But one thing that is a bit tricky to do with native development or one of the pushback that most
companies have these days is, well, it takes a larger team.
How big was a team when you started this project?
You told me it's like 10, 11 people.
But back when you started, how many of you were there?
Was it just two of you?
Was it more people?
I think it was four people total at the time.
It was like two iOS, two Android.
and yeah, a relatively small team to start.
But over the course of the projects that we were doing to kind of like move things to native,
we were also starting to like scale the teams.
So we didn't kind of like do it with four people the entire time.
It slowly grew and like more people became sort of like instrumental to different parts of the project.
And can we talk about how this, I guess, rewrite happened?
We're even thinking of it as a rewrite or was it a new?
project or because it sounds like you kind of, you know, you had something, but you kind of
slowly moved over to a point where now it's all native or almost all native. How did you
even think about this? Yeah, that's right. We were trying to make it incremental in some form.
And so we were looking for like what is the largest like meaning or the smallest meaningful
chunk that we could move to native. And for less that was the home tab. So that's the first thing
that you launch into.
And so I mentioned earlier, like initial home render,
that's the most prominent metric in terms
of perceived performance of the app.
So we started with this Home tab slice.
And then later on, we were able to move to the other tabs.
So after that, we shipped search natively,
and then we shipped inbox natively.
But yeah, Home tab was kind of the major part of the rewrite,
because at that point, we had no native code at all.
It was purely just a web view.
And so that meant that we had to like start from scratch effectively.
Like I remember at the time we didn't have a way of making authenticated like network requests
natively.
So we literally had to write like, you know, the network layer, like all of the service layers
that were kind of required to run notion to start.
So that was kind of what was seen as a rewrite for us because basically nothing existed
at the time.
but search and inbox were a little bit easier because we were able to build out the service layer
in the meantime.
Yeah.
I think it's pretty common in the industry to hear horror stories about like full rewrites
taking like multiple years.
And I think like that's like a bit of like a failure mode that we wanted to like guard ourselves
against and make sure that we were shipping something that we could complete an unreasonable
time frame.
And then also just like vet whether the approach that we'd,
we were taking was going to work.
Like it was entirely possible that we like move things to native and it like performance
got worse or startup got worse or like it just wasn't compatible in the way that we wanted it
to to work.
So yeah, I think like that was a common failure mode that we wanted to like guard against.
And how how long did this whole project take?
So like in 2019 you said like, all right, let's start with the home tab and then later you
added search and some of the other things.
At what point did you get to a point where you're, either the whole thing was native or most of the thing that kind of matters were native in your mind, right?
Yeah.
So the Home Tab itself took about nine months.
And so we started in 2021.
We wanted to ship like Christmas.
Oh, God.
So you start to make a plan like when you joined like, all right, we're scheming.
We'll try to make something.
Yeah.
So we knew like because of this incremental approach like HomeTab once once that was shipped, we were able to take a step back and then, you know, move.
to these other tabs later on.
End to end, that whole process has basically taken four years, but we've shipped other things
in the meantime.
The Home Tab project itself was the only part where basically the entire team was working
on it and we could do nothing else until it shipped.
Effectively, like it was blocking everything else on mobile.
And just to explain what the Home tab is, because I have my Notion app here open.
Like, can you tell me like, you know, why is?
It sounded like it's a big project, but why was it so complex?
You know, I just look at it here, and obviously, I don't have my inspector right on, so I don't see the elements.
But I do see recent documents.
I do see a lot of quick notes.
I do see task lists, et cetera.
So the home tab for folks who don't have context into like what Notion's HomeTap looks like is if you've ever used Notion, there's a bit of a sidebar on the web experience, sort of adjacent to the editor.
And the sidebar is sort of like your central navigation hub.
It has all the sections for your favorite pages, your shared pages, teams.
team spaces if you're part of like, you know, like larger workspaces.
And it's kind of like your central hub for all the information that you have in your particular
workspace. So on mobile, that's kind of like the home tab. It's that sliver of the notion
experience. It's your entry point into the rest of the your like work and your documents.
And so, you know, the obvious thing here is like it's just a list. Like how hard can it be to just
render a list.
Turns out it's quite complicated, especially because Notions Data Model is very complicated.
One of the things that people really love about Notions Data Model is that if you have a
to-do block, you can convert it into a heading or you can convert a heading into a call-out.
And a lot of these, like, sort of blocks are like interchangeable.
And they're interchangeable in a way that sort of preserves the content in those blocks.
Now, this extends to other things like titles.
So a common example is like you have like a title with a mention for like today or you have a mention for like a particular person.
And in other cases you might have a mention to another page.
And so there's this sort of like recursive structure that we're trying to build out.
And on top of all of this is that notion is very reactive.
So a lot of the changes that you see or that you make in your notion workspace are sort of in near real time reflected on your other devices.
So part of what we needed to build.
was not only just like a list rendering, but also the reactivity around all the rows and the sort of content that you had in your sort of notion home tap.
So there's a lot of like zero to one work that we were doing to build out the real-time connectivity, build out the reactive patterns, and then all while sort of keeping things fast and efficient.
So I know it was like it was going from what was effectively nothing to rebuilding notion sidebar and navigation sort of primitives.
So you build a sidebar, you built navigation.
Sounds like you built like the real time processing of events, updating of the UI.
Did you do some like UI elements or like some, some sort of the internal design
system or that kind of stuff as well?
Yeah.
I think like, you know, part of like building out these home like the sort of like these tabs
and moving to native, we had to be like very intentional about what we wanted to like scope.
As part of the work that we were doing because it could easily blow up into like a like
a very large project.
And you can think of like design system.
as being one of those things that are like nice to have.
But as a product scales,
it's like becomes more and more important
to ensure sort of a consistent experience.
And, you know,
design system is something that we only like built out
in like the last couple years.
When we first started,
we were in kind of like a MVP sort of mode.
And so a lot of the stuff that we built out
was just very bare bones.
We were like, can we match the specs that we have?
That's good enough for us.
Yeah.
To give another example of the complex.
So, Notion is local first in some sense, in that, you know, when you make edits to a document,
we want those to be preserved and then sync later.
So there's kind of a similar effect on Home tab as well.
So like one action that you can do is favorit a page.
And in most applications, you kind of expect this to be pretty straightforward where, you know,
you tap favorites and then it makes an API request with like the page that you want to favor it.
But in Notion, this is considered a transaction.
And a transaction is like any modification to a piece of data.
So if you are typing in a page, you're transforming kind of that text from one state to another state.
So favoriting is just an example of another transaction that's possible.
So instead of making an API request for this, we needed to build out this whole layer of syncing transactions.
So when you favorite a page, we'll create that favorite transaction structure.
And then we write it to SQLite.
and then that's periodically flushed.
So you were already building your local data model, right?
And I'm assuming later you would use this in other places as well, obviously.
Yep.
Okay.
Yeah, these are the things, right?
Like I think even I'm sure non-technical people don't always appreciate it.
And they're asking, you know, why does it take so long for engineering?
But even as an engineer, that was a bit surprising to me.
And I'm going to ask you a question that's kind of been on my mind since you told me how long the homepage took.
What about the editor?
Like if I think of notion, if if I would have to make an educated guess based on what is the most complex part of this application, I would just burn out.
It must be the editor because you can add all these things, add all these blocks.
There's tables.
There's there's all sorts of text manipulation.
I'm sure there's like rendering of fonts.
There's scrolling.
There's all these these hard problems in software engineering.
I mean, if you like build something rendering.
How does that either compare to the home page or is it actually easier or is it harder?
And where does that fit into the project?
To me, it seems like it's just a big part of what you must have built.
Yeah, definitely.
I think the editor, the reason why we took this approach of sequencing at home tab,
search tab and inbox and then saving the editor for last is because it is the most complex part.
And we so far have built out a few things that will.
help us when we ultimately would like to get to moving the editor to native as well. So, like,
as part of the inbox project, for example, we're beginning to render certain rich text
blocks natively. So that means, like, blocks that have, like, code annotations or, or, like,
app mentions, things like that. All of these elements that are part of our text editor normally.
So we're already now, I would say, at the phase where there are certain chunks of the editor
that we could just kind of do natively,
but we need to figure out where the right user experience would be
to handle the more complicated parts.
So, Notion supports these things called collections,
which are essentially like mini databases inside of a page.
So doing that would kind of be a whole other long project.
We also have a lot of embeds.
So you can embed, you know, Figma designs, for example,
within a Notion page.
And, you know, scrolling,
in a native view with multiple web views embedded would be quite complex. So that's another problem
that we're, you know, we'll need to deal with at some point. But yeah, that's just a really
interesting thing to think about it. I'm glad you brought it off because I think it's just not
obvious from the outside, right? That it is, this is a game of tradeoffs, you know, like you have a
small engineering team. And for example, now I start to understand why you start with the biggest kind of
the most frustrating parts, the app startup, the home tab.
So I think this is a really interesting takeaway for anyone,
not even in your domain necessarily,
but if you're embarking on a difficult technical challenge,
you're kind of leaving the, yeah, as an engineer,
I would assume that it's most tempting to start
with the most complex problem,
but the fact that you're phasing it out
actually makes so much sense.
I think it was also helpful that part of what made that decision
a little bit easier was that we knew that the,
booting up the web app was the slowest part.
But once we had the web app booted, it was like relatively okay.
We could get things going and scrolling was good.
But it was that initial sort of chunk that was the most difficult for users.
Well, and I'm assuming that by having a pretty fast start and having full native control,
you can now do stuff in the background should you want to do that pre-fetched,
those kind of things.
Yeah.
And that's exactly what we do is while you load the home tap in the background,
we're loading the sort of like web app.
so that by the time you click into the page that you want to go to, it's already ready for you.
Super.
Now, you're a small mobile team, and there will be some people listening to Mobile Engineers,
but can you explain to us a little bit how you work with other teams and what other teams do you work with on a day-to-day basis,
both in terms of engineering teams and not engineering teams?
What does your typical week look like for a more typical mobile engineer at an ocean?
Yeah, we work pretty closely with other teams.
teams, I think, like, our sister team would be probably a web infrastructure, essentially,
because they're also a platform team. Although, you know, we're kind of in the middle where
we support both platform and features. So generally, this plays out through planning where, you know,
other teams are planning to take on a particular new feature that, you know, needs a mobile experience.
And so then we try to figure out, should these things ship separately? Yeah, I think we're primarily,
like we sort of function as consultants on these on these teams just because our bandwidth is a little
bit more constrained and so our job is to sort of help out where we can and I think it's helpful
for us because we've established a bit of like a good ownership model so a lot of web teams are
still responsible for their surfaces specifically at the web ones that appear on either mobile
web or mobile native and so we'll continue to provide consulting and make sure that you know
folks are on top of building out features that are compatible with sort of these different form factors.
But then there's, you know, these like native surfaces that we've converted and spent a lot of time building
where we take more of sort of like a lead and we'll take the requirements from other teams and
figure out how we can best port them into our our native infrastructure and build the sort of relevant
things that are necessary to carry out those requirements.
interesting i don't often hear mobile as a consultant set up it does make sense right but i think it
just comes to show that that every team and every company is different there's no one size fits
all i am interested to hear a little bit about your mobile development approaches in terms of
how ios and android work together and what kind of guidelines you set for yourself may that be
code reviews or other engineering approaches and what kind of collaboration does this pretty
small team have within the two big native platforms, which are quite different, right, iOS and Android?
I think for a long time, what we did was every feature that we wanted to build, we'd have an Android
person working on it and then an iOS counterpart. And this was sort of our push for a very long
time is let's build things together and build them sort of like simultaneously. This would be super
helpful because because we were a small team, a lot of us would be DRIing our own individual
projects and collaboration was kind of limited to just like the platform that you were working on.
And so to kind of make things a little bit easier and to build on both platforms at the same time,
we kind of did these in like pairs or at least specifically like the smaller projects that we
worked on. These are larger projects at the home tab and inbox usually have like multiple people
working on it. But in terms of like our collaboration at least between the platform teams,
like iOS and Android.
It was, you know, we tried to do things as much as possible together.
Yeah, I'd also say the structure of the apps.
We tried to kind of mirror them as closely as we could.
Because we were doing this rewrite kind of in tandem,
like the services and the modules that we created
are kind of a one-for-one match on iOS to Android.
So like the service that interacts with SQLites
or the service that like syncs our transactions,
you can go in the iOS code.
base and kind of find roughly a similar file structure as you would see in the Android
codebase since these were all kind of planned together.
Can we talk about the tech stack specifically the languages, technologies,
frameworks that you're using, and iOS and Android and maybe for shared if there's
anything shared?
Yeah, I think Austin touched on sort of like an important part here, is that we tried to do
things a lot like very similarly between the two platforms despite having different
languages.
So like our persistence layer is like SQL Lite.
It seems sort of like ubiquitous across the industry to use some version of SQLite somewhere in your applications.
You're saying you're not using core data on that.
There's like small tidbits where we're using these sort of things.
But our primary use cases are like SQL light for our persistence layer.
Obviously we're like a sort of Kotlin Swift, at least on the mobile side.
And then you know, web views power the sort of like hybrid portions of the apps.
Yeah.
Yeah, on iOS, like I mentioned, we're using Swift exclusively except for the parts that are in WebView, which are all in TypeScript.
We reply pretty heavily on Combine and, like, flows in Kotlin because of the reactivity of notion.
Could you just explain what those frameworks do?
Yeah, sure. So it's really a way of working with streams of data.
So if you've ever worked with, like, RX, you know, there's RX, Java, things like that, reactive pipelines.
So it kind of puts you in this mindset of instead of working with, you know, a static set of data that you are working with a stream that is expected to change.
So, you know, an example that Carr mentioned earlier, if you're looking at your home tab and somebody is updating the title of that page, it will update in real time, like, as you're looking, you know, at home tab.
And so kind of handles re-rendering and things like that or is a way of piping data to the view layer that.
that is reactive.
I think also in the view layer,
where like Jetpack Compose SwiftUI
and we're like pretty early adopters
when we first started some of our
migrations to native.
We picked Jetpack Compose and SwiftUI as
sort of the bets that we had.
But you made that better early, at least with Swift UI.
It was very new, right?
Same with Compose.
Yeah.
Both of them were like relatively early
and whether that was the right
call, I think, is just like, we have a bit of like survivorship bias, I guess, because it
sort of worked out for us. But, you know, it was sort of like pretty rough and sometimes
sort of like building out with these like pre 1.0 frameworks, especially for like what is
effectively like the most critical parts of your app. And there's like, you know, these like
examples of like things that we would do to like circumvent, like issues that we were seeing.
So one of the things was like composed was really slow at the start.
Like performance wasn't a big part of like the libraries or sort of like the library designs
or like what they wanted to like prioritize.
And so we'd see these like esoteric bugs show up.
Like scroll performance would be like really bad.
Oh.
In like certain cases.
And we would spend these like time doing these investigations.
And one of the things that we found was that materializing that.
click handlers on these like rows was like really slow as you were scrolling.
And so we do these like fun hacks like disable the click handlers as you were scrolling.
And then once you stop scrolling, we would like reattach the click handlers just so we can get
those like marginal improvements in performance and work around these like weird issues of like a pre 1.0
framework.
But knowing what you know now, would you, you know, like that compose, for example,
had these issues, would you still choose it and go around and fix it or we just go with something
that's kind of boring, not as functional, but kind of more stable? Because like this is really
interesting because when you don't know, you just go with the punches, right? You kind of do it.
But would you change it? I think on Android, probably not. I think despite these challenges,
I think we made the right bet in hindsight. I think most of sort of like Android development,
as at least modern development, is moving towards Compose in Kotlin.
And so I think being early adopters helped us,
not only as engineers ramp up on this new framework,
but it helped us sort of change the way we thought about building UI,
like Jetpack Compos and Swift UI, like declarative UI frameworks.
And they, you know, you sort of build UIs a little bit differently than you would.
And sort of like a good way to at least to solidify my thinking around this
is that like if you ask someone,
want to build a list in Kotlin and you wanted them to use or sort of like on Android and you
wanted them to like use like the old XML style versus the new Jetpack Compose style. One of them
is way easier to do. And I think that that is just like an apt example of how we thought about
sort of moving to compose. I don't know. Austin, what do you think about Swift? Yeah, I would say that we're
in a similar position with Swift where it feels like the iOS community is all moving towards
Swift UI. This is where the documentation is all being written, you know, blog posts. This is what Apple
was talking about throughout WWDC. And they are making some changes to UI kit, but, you know,
Swift UI seems to be kind of the predominant area of focus. So it seems like developers are kind of
stuck in this middle ground where like they're worried about kind of these risks associated with
Swift UI. But, you know, this is where the community seems to be heading. And so I think there's almost
a cost to not choosing it at that point because eventually, you know, you will sign your
yourself up kind of for a rewrite later, you know, down the line. But yeah, I would also say
that there were, there were some pain points. You know, we had to work around some, some odd bugs
with Swift UI. 90% of the views, I would say, were very easy and straightforward to write. And I think
that's where there's kind of a major developer velocity improvement with these frameworks and
similar with Jetpack and Pose. But then there's that 10% of views where, you know, the API
doesn't exist yet or there's just some odd bug. With it.
in particular that that may incur quite a bit of cost.
But overall, I would still say that I would make the same decision again to go with SWIFGUI.
But it's encouraging because I think it is good, you know, right?
When you can move with the industry and looking back, say like, you know what, it was the right call.
Because it sounds like if you chose the existing stuff, you know, UI kit or or just, you know, like XML,
you would be pushing a migration ahead of you at one point, which will be painful and, you know,
it's a more mature system.
So it's a good reflection.
I have to ask you, code reviews.
Do you do code reviews?
Do you do cross iOS Android code reviews?
How do you do it?
Because you're such a small team.
It's very unique, right?
Most mobile teams will, when they're bigger, is kind of pretty straightforward Android engineers
review, Android's code, iOS, etc.
there's no cross pollination. What do you do, though?
Yeah, we occasionally do cross-platform code reviews. If people are working on kind of the same
feature, you know, you're in this scenario where you're writing what's essentially the same set
of lines of code across both platforms and you kind of go PR for PR. And so you are kind of in sync
with, you know, your iOS or Android counterpart like throughout that process. But otherwise,
I would say maybe 80, 90% of the time, code reviews are done within the platform.
But, yeah, I would say we follow a fairly standard process.
Although one thing I've noticed the notion is that we are quite quick on code reviews.
Like we try to keep that timeline from like a PR goes up to it being reviewed.
It'd be very fast because just that kind of unblocks the next step.
So does this mean that people prioritize to kind of stop what they're doing?
or interrupt their own flow to unblock somewhat.
I mean, obviously, not as a guideline, but like, you know, there's a trade-off, right,
between like, all right, I'm focused on myself versus I'm going to help this person out for like a few minutes.
Yeah, I think generally people would glance at it right away.
And if it's short, then maybe they'll, like, kind of stop what they're doing.
For longer PRs, though, I would say we try to take about a day or so SLA.
You know, that tends to speed up the whole process.
we've also started using a tool called graphite as well so people are beginning to you know stack
PRs and that helps as well you know like we actually have a deep dive on stack diffs and on on graphite
into pragmatic engineer so we'll link it into the show notes below that that is awesome to hear
yeah i mean i think that helps because it puts a little bit less pressure on on reviewers
to kind of get it out right away and yeah graphite is is great in that you know you can
pretty easily switch between parts of the stack to update like that specific part.
One thing I'll add is that I think the mobile team, you know, because it was originally like
a little bit senior, I think folks would move pretty quickly on on the diffs and I think that was
like helpful because you don't need to ramp up as much. And then the other real benefit was that
because we were a small team, almost everybody was reviewing PRs. And by sort of like proxy,
you would learn a lot about the rest of the code base because you were just like so heavily
involved in like the code review process.
And that kind of like snowballed and like over time, you would just become easier and easier
to review PRs because you had more and more context.
And well, you know, hopefully we'll see that continue to happen as the, you know, as the teams
grow.
But I think that's kind of like what contributed to things moving a little bit quickly as well.
And in terms of engineering practices that also make code reviews easier.
What is your take on automated test, linting, static analysis?
because, you know, like, there's this tradeoff where the more of those things you have,
A, the slower your builds are, B, the more confidence you might have that, you know,
like, if the code review checks all those automated tests, it's probably going to be okay.
Like, what balance have you chosen there?
Yeah, I would say earlier on kind of throughout this rewrite, we weren't very upfront about writing tests
for, like, things that we didn't feel like were very critical, I guess.
We would try to write tests for like service layer things.
So, you know, syncing transactions, stuff like that that we felt like absolutely could not break.
Now I think I'm trying to get us to a point where all of our modules that, like, their public API or their public methods that they expose are tested.
But that's kind of a long-term idealistic goal.
But, you know, making slow progress towards that.
Yeah, I think we're definitely picking and choosing what we thought was going to work for us in terms of like testing and bills.
And you mentioned that like, you know, the tradeoff is that over time your bills just become more complicated.
And, you know, we're a TypeScript shop like at Notion as a whole.
And, you know, type tracking on Notion just takes a long time because it's like a very big code base.
And there's like, you know, dedicated efforts to make sure that those checks are efficient, both on like the TypeScript layer.
And, you know, for us in the mobile teams is, you know, code reviews are just one part of developer velocity.
The other part is making sure that your changes are merging as quickly as possible.
Because the longer diffs stay open, the more likely there is for merge conflicts.
And, you know, the more likely that things just sort of drift.
So we want to like sort of close the gap on on those sorts of like preventable, you know, developer velocity issues.
Yeah.
And there's this saying, which I just made up, but it says never asked who.
woman her age or a mobile engineer their mobile project compile time. How long does it take
to compile the iOS and Android app from a clean state? Clean, I would say, maybe about 45 seconds,
which is quite fast. You know, our company is still relatively small. Yeah, yeah, it's still relatively
small, you know, and we've come, both Karn and I have come from companies where the clean build are
probably like two, two minutes to even five minutes.
But even that, I feel like we're kind of trying to get ahead of it by modularizing to
the extent that we do.
So we kind of take this approach where like every single service, so like, you know,
our network layer, our transaction sync layer, those are all modules that can be built
independently.
And compile time for that is, you know, a second, two seconds.
And so if you're working in.
That's awesome.
Yeah.
If you're working in a particular area of the code base, then you can just kind of switch
your target to that module and build it.
And, you know, potentially that would set us up to migrate to something like Basel or
Buck if we wanted to in the future.
Yeah.
I think folks underestimate, like, how important it is to have, like, fast build times.
You know, you hear stories of folks who are, like, I hit build on Xcode or enter a studio and
then, like, I left to go get coffee or something because it takes so.
so long. And, you know, rapid iteration cycles are like a key part of like, I think, what
engineering culture at notion is, is about. So we're like very intentional about making sure that
we don't sort of regress build performance. Oh, yeah. Another thing that we're kind of putting
ourselves in position to do is like instead of just building a particular module, you could even
slice out a particular feature and build, say, just the home tab, for example, and like all of its
dependencies. I've seen, um, if you've heard of point free, Brandon Williams, Stephen Seles,
They run kind of an iOS like video series.
But they've talked about this approach where they've kind of carved out specific sets of the app.
And so they can just build a subset of the app.
Like if you're just working on the Home tab, for example, you know, you can build that feature
and all of its dependencies kind of in a single view.
And that's another strategy of just, you know, speeding up build times by cutting out all
of the unnecessary modules.
So you mentioned modules.
Can you give me a sense how many modules the current Notion app has?
And when did you introduce these modules?
Because it's a lot of work to introduce modularization.
And my naive approach would be you sold me, oh, the Clean Bill takes 45 seconds.
We can probably hold that off until later.
But clearly you didn't do that.
Yeah.
So the iOS app has about 100 different modules currently.
And what it means to be a module, it's pretty lightweight.
Really, you know, we're just defining modules through our package.
SWIF file.
And so being a module essentially just means it has its own folder.
We explicitly specify its dependencies, like what are, you know, what other modules it depends on.
And then, you know, because it's specified in this way in Packaged.comptuift, it can be built independently.
And we've kind of taken this approach where every unit is either like a feature or a service or a model and kind of falls into one of these categories.
And you said, just clicking on what you said.
So you said it's either a module, a feature or a service.
I understand module.
What do you mean by feature or service?
Sorry, to clarify, our modules, all of them kind of fall into these categories.
So a module could be a feature or a service or a model.
I think that might have been.
Oh, I understand.
So this is like the three categories of what a module can be.
Yeah.
We also have like helpers and UI.
There are a couple of different categories.
I understand.
Yeah.
Generally, its category kind of helps us understand where it might live in the dependency
tree. So if it's a helper, ideally it does not have very many dependencies or if it's a model.
Basically, it has no dependencies. But things like features, they're expected to have quite a few
dependencies. So they'll depend on services and models and other things. And this way, you know,
this is kind of what helps keep the build time for specific modules very low. Because if you want to
build a service, you know that a service is generally only going to depend on maybe some helpers,
maybe some models, but nothing higher than that in the dependence of tree.
On the ender's side, I think we're trailing a little bit.
I think we're at like 50 or so modules.
And I think what you asked earlier was like, how are we thinking about creating these modules?
And I think for a long time, especially during like the early development of features,
we were saying that like, oh, every new feature would potentially have its own module.
And as we built out more features, we would like split things out a bit more intentionally.
But, yeah, as Austin mentioned, I think it's like kind of lightweight.
We sort of do it when we think it's the right time to do it.
And Android do also have this categorization of model, service, feature, helper.
Yeah, I think we try to keep it consistent because it's just helpful to understand the code base.
Both as like an Android engineer looking at iOS code or an iOS engineer looking at Android code,
it's very helpful to have like a similar structure despite having different languages.
And for us, I think it's like the best thing we can.
do is sort of keep the gap as close as possible for folks kind of like pivoting through the
different different stacks. Yeah. One other thing it helps with is like kind of you can you can do
migrations on a module by module basis. So for example, Apple just released or the Swift team just
released strict concurrency. And so this is like a flag that you can enable to add extra compile time
checks for whether or not you're kind of using their concurrency tools in the correct way.
And this can be enabled on a module by module basis.
So it means that we can kind of incrementally go throughout the code base and turn it on,
which makes these types of migration so much more easier than they would be otherwise.
It's interesting because I feel there's,
it's not a one-on-one mapping,
but there's a little bit of similarities between microservices on the back end or services,
depending on how you call it and modules on mobile.
not one-on-one, but both require planning, both have upsides, both have upkeep, but both can,
you know, if you do it well, it can, it can just, you know, make you go faster as a team.
So how do you release, build and release the app?
Because this is something, again, as a mobile engineer, I think we know how painful it can be,
but, you know, it's not mobile.
You just see like the notion app appears every week or every two weeks in the app store.
What goes behind the scenes of going into that release?
There's going to be some sort of, you know, bills, QA, some sort of other gates.
What steps does it take to get it out there?
And how often do you push it to the app store?
Awesome, do you want to take this?
Oh, sure, sure.
Yeah.
Yeah, so we release the apps once a week.
And we cut a build on Wednesday night.
We start the release then on Friday, but these are all like a progressive rollout.
So it sounds kind of odd to release.
on a Friday, but what we release on Friday is just out to 1% typically. So that's actually
that kind of the least risky part of the release. Then it kind of picks up by Monday we have
maybe around 20% or so. And then it increases throughout the rest of the week. One very unique
part about Notion is that because we have this hybrid, you know, native and web client,
we're bundling a version of our app JS when we cut that build on Wednesday.
that is continuously upgraded.
So when you're running notion, you know, just using it normally,
we're checking in the background every once in a while, like,
is there a new version of the web client?
And then it will download and update that.
So our web app is continuously deployed essentially.
So, you know, at any given time, basically, you could have a native version that we know
your web app is at least as new as that Wednesday cut.
But then potentially you could have a web version that's,
a little bit newer, you know, at least a week newer.
So that introduces a set of challenges, you know,
and the differences between those two things that we've tried to have engineer around.
But, yeah, that's kind of the general release process.
We also have a public beta on test flight and the Play Store that releases nightly.
So anyone's able to join.
And we generally, you know, enable sets of new features.
And we're looking at kind of crash logs from,
from those betas a bit more closely.
So you have a nightly public beta.
So if some people who join the public beta,
they will get the nightly cut build.
Wow.
That's cutting edge.
Most companies would do that internally,
or a lot of companies do it internally,
but few would do it externally.
That's great to hear.
Yeah.
Yeah.
I think we felt that not having it nightly
was not giving us enough signal.
I guess to say that in another way,
If we cut once, if we're already releasing once a week, if we were to release a Tesla like a public build earlier, then we would only have, you know, maybe two or three days of signal and, you know, kind of depends on the adoption rate of the build.
So, yeah, being nightly helps.
Yeah.
We can, you know, I think some of the benefits of it is also just like, it gives us a bit more granular information on what's happening between releases.
As you can imagine that if you're releasing once a week, there's a bunch of commits going into your code,
and then that is being rolled out to users.
And so you effectively have a large chunk of commits going into a single release,
and if something regresses, now you have to sort of like work backwards from that sort of like entire chunk
and figure out where things are.
Having bills go out nightly gives us smaller diffs that sort of are rolling out
and helps us detect issues a bit sooner in the sort of like.
release process.
What is your usage of feature flags?
Because, you know, classic tool and native mobile because you can only release once a week
or few places do more frequently.
You could, but there's drawbacks is you just wrap stuff into feature flags.
You do stage rollouts onto them.
How is your thinking around that or how is your, you know, like practices around that?
Yeah, I think it's gotten pretty common in the industry to just like heavily rely on future flags.
I think gone are the days of like six month release cycles where you can like vet and build
your features in one one chunk and then, you know, be relatively confident that you're shipping
things like that work.
With mobile releases going on every week and like nightly for the, you know, the betas,
it means that there's a lot more sort of like things that can go wrong and feature flags
help us guard against those issues.
I think at Notion, we use them in a couple of different ways, but I'd say primarily we use
them to first gate features that are going out or the ones that are being like actively
developed because, you know, the folks are merging PRs, their stuff is sort of like being developed
behind the scenes. And then there's the sort of second type of feature flag, which is something is
being rolled out, maybe in a staggered rollout, sort of like, you know, 10%, 50, whatever. But then
we find out that something is like going horribly wrong. Like there's a particular crash mode
that's causing data loss, for example. That's like a really bad scenario. We want to get ahead of
that. And, you know, because we're doing these like weekly releases, we can't have things
slinger like that in production for that long. And so feature flags become sort of like a very
important mechanism to control these sort of failure modes. Can you give a sense of like at any
given point of time like what the number of feature flags might be roughly are we talking about
in tens or hundreds or even more across the notion app of you know, active things that are
being potentially flagged or the potential to even turn them off if things were wrong?
Yeah, that would be in the hundreds, I would say.
I think it's just a general practice if you're, you know,
developing something to wrap it in a feature flag.
And that's probably one of the first things that people generally do when starting a new project
is, you know, they'll set up the experiment, set up the feature flag,
and then like begin development, like within that.
So, yeah, it just seems to be generally good practice.
we have a dev environment.
So we haven't really touched on deployes yet.
We have a dev environment that all of the employees are using.
And so generally we enable quite a few feature flags in that environment that are not enabled in production.
And then we have a staging environment that is tested by QA that mirrors production as closely as possible.
So just just just.
Just to make it clear, would you mind like clarifying, like, how many environments do you have and, like, what they're called?
Yeah.
So I guess we have four environments, although there are really three important ones.
First would be local, and that's just kind of what you're developing on locally.
The next one would be development.
And so development is what all of the notion employees use.
So whether you're on the mobile apps or on the desktop app, there is a particular environment that hosts kind of our notion internal workspace that all of employees are
kind of working within. That's like kind of where we get all the dog-frooted feedback from.
Then there is, and that is deployed continuously throughout the day, so like very frequently.
Then there's the staging environments that QA tests, and that is tested nightly. And so they go through
kind of a variety of flows, basically making sure that the core experiences are working throughout
the app. And then there's production. And so as we,
go from dev to staging to production, we try to catch kind of various things throughout
the process. I would say the vast majority of things are caught in dev by employees because
you know, Notion employees are using Notion to build Notion so heavily. A lot of things are
caught in this dev environment. And then I would say probably the only, like the things
that get through are things where you have like a feature flag that's enabled in dev that's
often staging. And so then ideally QA.
would catch it. I would say that that's probably the number one case where things do get through
is, you know, employees don't see it because of some kind of feature flag configuration. And then
it happens to be something that's not covered by QA testing and staging. And then that's how it gets
through to production. But in general, we're able to catch most things. And just understand the
environments. I think it's pretty clear in the back and what it means is like different, you know,
like servers. If it's staging, there's there's services that the code is,
deployed in in we're talking about mobile uh environments right like how is this differentiate is it
a different app that is downloaded or or is it based on user different flags being enabled in the
environment like how can we imagine this these you know the difference between the dev environment
and you know like production or staging yeah i think you're i mean a lot of companies do it differently
um some folks have the sort of like dynamic configuration or like
like depending on the user, it like signs you into a different environment.
But at notion, we shipped sort of like different apps.
We have like sort of separate listings on like the Play Store and the app store for these
apps and we ship them to sort of like our internal testers, which are just like our sort of
internal employees.
Yeah, I think the setup works pretty well because we're able to like turn on certain
compile time flags when we build those apps.
So basically like we have a development build of.
the app and if you ever are using you know like macros things like that uh you can enable those at
the very start of the bill essentially and um then like that is submitted separately so they're
they actually exist as like separate entities in you know app store connects and in play
environment will be a different binary like a dev binary the dev binary and obviously with
combined with a user gets like if it's an employee they get like different feature flags
Yep, exactly.
So these apps are just never submitted publicly.
Yeah.
Yeah.
There's also like a bunch of like debugging information that we include, like extended logs,
like more crash reporting.
So, you know, they're a little bit heavier in the sense that like we're sort of measuring more things and like handling errors a bit differently.
And, you know, the apps that we ship to production are a bit more sort of minified, more efficient.
Just because like our user base is a little bit different.
But do I understand it correctly that kind of notion deliberately made this decision to allow for offline work, even if the network drops across web and mobile?
Is this one of the reasons why this quite unusual backend structure and kind of client decisions have been made?
Or if not, what was the reason?
With a lot of like technical decisions, sometimes it's just like historically, that's the decision that was made and that's kind of like what we ran with.
and then you do this like sort of like long-term evaluation to say whether oh it was the right
decision we'll continue to do it this way or we need to like rewrite things in our case I think like
the model startup started out like this and to provide a little bit more context you know the the
transactions API or the syncing API is like the two major API endpoints that that notion has
you don't really have a lot of like other ones and these do a majority of the heavy lifting so
if you wanted to like add things to your favorites or create a new block all these kind of
go through that singular save transactions API, which is kind of like what we hit.
And the sort of request that we're sending is like super flexible.
So it supports a like a wide variety of use cases.
And the same thing is true for like syncing is that we can just sort of like fetch that data.
And so to sort of your earlier question, like was this like an intentional decision that we made and chose it to be offline or like to support offline better?
I think, you know, as Austin mentioned, I think it was part of the motivation around it.
But also, we just wanted to support this super flexible data model and have it be able to
handle these cases that are sort of like core to a user's workflow.
So you can think of like a good example being that notion is a like, you know, you're saving
a lot of your like knowledge and content there.
You want some guarantees about what, where that information is going to be stored.
And, you know, having things fail when you're like trying to save them, like take notes,
feels like a really bad user experience.
So we want to sort of like adjust for that and then sort of build it out upfront.
It's just fascinating how important the data model is for, you know, years later.
Like it's just an interesting learning that I would have not thought about it.
But it kind of makes sense, right?
If a product is successful as successful as notion has been, it's going to be around.
And the documents will hopefully, you know, there will be users who've been using it from day one
working on the same documents even.
And you need to support that.
Yeah.
And, you know, if you think about sort of the counterpoint, which is that, you know, we talked about tradeoffs a little bit.
But, you know, Notion's data model being this flexible also makes it, you know, a little bit difficult to do other things that users might expect us to be able to do.
And so, you know, you're always deciding what, you know, what is the layer that you want to operate in and what decisions do you want to make to support these core use cases that are important to the product that you're building.
Taking a step outside of Notion, where do you see?
see the mobile engineering industry heading if we let's say try to forecast for the next five
years and what what areas do you think we're going to see progress on on android and on ios
if you want to start austin yeah sure um the first thing that comes to mind for me is uh like on
mobile app architecture uh car mentioned earlier you know the switch to jetpack compose and swift ui
these are these declarative frameworks um that i feel like fit with a little bit different of a model
they're closer to react than they are to like what we have been working with historically on mobile.
You know, for example, at the time that Swift UI was released, I think the predominant architecture pattern was MVM or like Model View View Model.
That came from like Model View Controller.
But now I see it much more frequently people using kind of a store slash like Redux pattern that you
you kind of see on the web where you have some store class that holds a state struct or something
like that.
And then you might even add on like a reducer to handle the actions.
And I think that's just like a byproduct of the way that compose and Swift UI like handle view
re-rendering as, you know, a process of like state changes to state.
So I feel like that gives you a lot more control out of, you know, state changes.
And I also feel like it's nice in that, you know,
we're getting closer to parity with web in terms of architecture.
So I'm interested to see what patterns emerge of the next few years.
Yeah, I'll add that I think, like, mobile has been around long enough now that we're
starting to see sort of like more mature patterns emerge.
And sort of similar to like web, I think a lot of folks when they're like now exposed to
mobile have like good guiding principles on how to build a mobile app or how to think about
mobile architecture.
Whereas maybe like, you know, five or 10 years ago,
it was kind of like the Wild West.
You could just do whatever you wanted to and you'd be sort of relatively okay.
But I think now if you're thinking about like scaling a mobile product,
you know, thinking about architecture is like a core part of how you think about
building that product.
And so having more mature architecture is I think kind of where I imagine we'll go in the next
five or so years is just better guidance around how to, you know,
think about mobile and mobile at scale.
And what advice would you give to mobile engineers who would like to grow
or let's say a mid-level engineer who would really like to get to that senior,
potential that staff level thing.
And you're working on either iOS or Android.
What would you suggest for them to keep growing professionally?
Maybe I'll start by saying that, you know, early in your career,
I think a lot of your role is just being a good executor and just taking, like, you know,
the tasks that you've been assigned or the projects that you're working on or that you're
responsible for.
and just like shipping them on time and then, you know, doing sort of like a really good job with like craft and quality.
That's sort of like sort of the foundational work that you're doing sort of early in early on in your career.
I think what I found particularly helpful is, you know, think about growing into like more senior roles
is thinking more about problem finding and thinking about how the work that you're doing relates to the sort of outcomes of the business,
thinking about how you can sort of move the needle on the objectives of the business and the work that you're doing can drive those outcomes.
So if you're like sort of thinking about that shift between like, you know, kind of like early career to like later career is keeping that top of mind and being sort of intentional about the projects that you work on,
always asking like why is why is this the project to do at this time?
You know, I think that's like a good guiding principle.
Yeah, I would I would agree with that.
I think a big distinction that we make between senior and staff at Notion is, like, are you just executing well versus like, are you, you know, kind of moving business metrics?
And so, like, your ability to identify those business metrics and then make an impact, I think makes a meaningful difference.
I would also say transitioning from, like, executing well personally to helping others or providing frameworks or tools for others to, you know, make their jobs easier, essentially.
So that could mean documentation or, like, building.
out, you know, frameworks that are used by multiple people. That can kind of take a variety of
forms, even just pairing with other folks on the team or like helping new people ramp up.
There are kind of like a lot of opportunities to work outside your current, you know, product
or feature that you're working on. Yeah, that's why the ways. I think you still have to be a good
executor on top of that. Yeah, of course. Yeah. So you're doing that in addition to execution.
And would you recommend on focusing on just, you know, the mobile technology or your mobile
stack that you're doing less, so you're doing Android, just focus on Android, or to kind of branch
out a little bit and, like, dip your toes here and there as well. Yeah, I think it can depend on
your circumstances. I do feel like going deeper in mobile is still a pathway to growing as an engineer.
You know, but throughout this conversation, we kind of talked about a lot of depth that exists within
mobile. And if you're working on an app where you have an opportunity to do something like that,
where you can either go deep on something like performance or on these service layers,
like, you know, syncing transactions.
Like there's a lot of complexity that still exists within mobile.
But I think there are other circumstances where, you know, you can expand to doing both,
where you're basically working on mobile, but then maybe you also start to set up API endpoints
or build out a basic version of the backend.
You know, one of the first projects that I worked on at Notion was like upgrading to
Notion Plus on the mobile app.
So we had to build out the backend for that.
So there are opportunities to work on, you know,
kind of projects that expand just beyond the scope of mobile.
Awesome.
Well, thank you.
So with this, let's just wrap up with rapid questions, if that's okay.
And these are just really true.
So for the first one, I'll ask, you know, like both of you and then I'll have the
the ones separate for the thing.
So rapid questions.
Do you use an AI coding tool for your day today?
And if so, which one? Austin.
Yeah, we started using Cursor at Nocean, and I'm super excited about it.
You know, it runs on top of Cloud 3.5 Sonnet, which I think works really well.
I think the differentiator really for Cursor is the interface of like how you really think about like AI completions.
Like there's a running joke at the org where we're just like hitting tab the entire time to like accept the suggestions.
And you know, the reality is that like,
These tools will only get better.
So, you know, if you're not using an AI coding tool, like consider it, play around it,
and see if it works for you.
Yeah.
And I'm impressed to hear because mobile is one of the areas where the tooling is just,
it's not, you know, it's a lot more sophisticated.
We know there's a lot of other IDs.
So the fact that you're using it, to me, is very encouraging.
And the fact that you have, like, such positive experiences.
And, yeah, like, I think I can, like, try it out if you're not already doing it.
Now, my next, next question is a bit more kind of devising.
So Austin, Swift or Objective C and why?
Yeah, I would definitely say Swift, no hesitation.
I've spent a long time working in Objective C, and I would say Swift is what motivated me to continue as a mobile developer to a large extent.
Okay.
The community around it, I think, is really great.
And I guess just like certain aspects of the language, you know, I feel like it's continually being improved, you know, recently the addition of stuff like Async Away.
I feel like there are a lot of exciting things
around the language that keep me with Swift.
All right.
And Carn, to you, Java or Kotlin?
I mean, that's not even a fair question,
but I'm going to ask it anyway.
No, I think Kotlin is definitely like the winner here.
To me, Colin feels like just like a better version of Java.
I started programming by learning how to write Java.
And so, you know, it has a special place in my heart.
But, you know, it's like the languages are maturing.
now, the Kotlin just feels like, you know, it has so much of the syntactic sugar that just makes
development a breeze. And, you know, first-class primitives for things like concurrency and reactivity
or like just like cherries on top of what Kotlin offers.
Great. And finally, can you share a non-fiction book that you've recently read and you've
enjoyed? Yeah, I recently read SkunkWorks by Ben Rich, which is about the engineering team
at Lockheed Martin.
During a period of very critical years,
they worked on the SR-71 Blackbird,
a lot of very, very complex projects.
And, yeah, I feel like it's just very inspirational
for engineering teams in general,
a lot of very difficult problems to solve.
Yeah, that's a great book.
I highly recommend that one, too.
But I've been recently rereading
a philosophy of software design by John Osterhout.
And, you know, it's about sort of managing
complexity and software and sort of like the tricks that you can use to sort of reframe some of your
problems so that the problem itself is simpler to solve. But yeah, highly recommend as well.
Awesome. Well, thank you very much for being here and for sharing all these insights.
Thank you for having us. I appreciate it.
Thanks very much to Austin and Karn for sharing all these details and going deep into the
specifics on mobile engineering at Notion. If you enjoyed the podcast, please do subscribe
in your favorite podcast platform and on YouTube. And if you're interested in learning more about
unique mobile engineering challenges, you can also check out my book, Building Mobile
Apps at Scale, linked in the show notes below. Thanks and see you at the next one.
