A Brief Account of the Past Decade-Plus
The last time I wrote a blog post was in 2013, more than a decade ago. The last time I updated my personal homepage was in 2016, almost ten years ago, and by then I had already listed my blog as “Retired blog.” But recently, I’ve increasingly felt that some things are worth recording and sharing, which led to the idea of starting a blog again.
However, I never found a suitable platform. I didn’t want to rely on commercial publishing platforms like Medium and Substack, and I found setting up my own blog to be a hassle. Plus, in recent years, I’ve become more confident in my English and Japanese, so I wanted to try building a multilingual blog, but no blog system offered satisfactory support for it. Some time ago, I learned about a frontend framework called Astro, which is suitable for static content like blogs, and this sparked the idea of building a blog from scratch with this framework.
A lot has happened in the past decade or so. For this first post, I’ll just jot down a brief account, and I’ll save the story of how this blog was built for another time.
After graduating from university in 2013, I came to Australia to pursue a Master’s degree in Software Engineering at the University of Sydney. Finding the coursework rather boring, I started thinking about finding a job after just one semester. By a stroke of luck, thanks to my previous contributions to Firefox, especially the implementation of the CSS Counter Styles module1, I received an invitation to join Mozilla. So, in the latter half of 2014, I left my studies and joined the company.
To be honest, working at Mozilla and contributing to open-source software was my dream job. I achieved my dream at the very beginning of my career, something I never would have imagined at the time.
Mozilla
Mozilla didn’t have many people in Australia, nor did it have an office2. But even back then, Mozilla had a remote work culture; it was said that up to half of the engineers worked from home. Apart from my first week when I flew to the San Francisco office for a brief onboarding, I worked from home thereafter. The company provided me with two Dell U2413 monitors and let me expense a Herman Miller Embody office chair3, both of which I still use today.
There were also many opportunities to travel back then. Besides the company’s biannual All Hands meetings, my direct involvement in implementing web standards gave me the chance to attend W3C’s TPAC and the CSS Working Group’s F2F meetings each year. Sometimes, my team would also organize extra off-site work weeks to bring everyone together. I visited quite a few countries in those years: the United States, Japan, Taiwan, Canada, New Zealand, and the farthest I went was the United Kingdom. Being young, I didn’t know how to cherish these company-funded trips. Most of the time, I’d just work for a week and fly back without taking extra time to explore and have fun locally. Looking back now, it’s such a pity.
After joining Mozilla, my first project was to implement the CSS Ruby standard. Coincidentally, I had started learning some Japanese in university, and with my native Chinese background, I had some understanding of this annotation format, which greatly helped me understand and implement the standard. Of course, implementing this standard had many challenges, including correctly handling line breaks, correctly handling whitespace in different positions4, and maintaining synchronization between multi-line annotations. After ruby support was enabled by default, I even wrote an article on Mozilla Hacks to introduce it. There are still many parts of this standard that I found difficult and didn’t implement back then but still consider very important today, such as support for overhang and merge. In any case, Firefox’s support for ruby, at least in terms of feature coverage, should still be the best.
Besides ruby, I also implemented other features commonly used in East Asian languages, especially Japanese, such as emphasis marks (text-emphasis
) and horizontal-in-vertical text (text-combine-upright
).
My next major project was improving fullscreen (Fullscreen API) support. This included a redesigned fullscreen flow that removed the user permission prompt, the implementation of the top layer mechanism, and most importantly, optimizing the speed of entering and exiting fullscreen.
The main security concern with the Fullscreen API is that a website could mimic the user’s screen content, bypassing all browser and operating system security measures to trick the user into entering sensitive information. The design, after balancing security and user experience, was to display a fullscreen notification every time switching to a fullscreen window, and to have the entire screen fade out and in when entering and exiting. The screen fade became a controversial design; many users disliked it, and it wasn’t fully compatible with all window managers on Linux, so this part was eventually disabled by default on Linux.
When optimizing fullscreen speed, I used YouTube’s fullscreen as a benchmark. I found that during the fullscreen transition, the entire page would reflow several times, for instance, when :fullscreen
starts to take effect, when the fullscreen event is triggered, and when the page area switches between window and fullscreen sizes. The solution was to freeze page layout updates once the fullscreen change begins, halt the dispatch of all related events, and apply all changes at once after the fullscreen transition is complete. If necessary, the expected final viewport size would also be provided in advance to minimize the number of reflows.
Another challenge in improving fullscreen support was the ongoing e10s project, which was transforming Firefox into a multi-process architecture similar to Chrome, separating the UI process from the content rendering process to enhance security and stability. However, entering and exiting fullscreen requires a lot of coordination between the UI and the content. When they are in different processes, many procedures rely on message passing, turning synchronous operations into asynchronous ones, which greatly increased complexity. Furthermore, the operating system’s support for fullscreen was also a hassle. For example, on Linux, the order of a window’s fullscreen event and the resulting window resize event was not guaranteed, and it wasn’t even guaranteed that they would occur at all, posing a significant challenge to stability.
Later, I joined the Stylo project team, which was porting Servo’s style engine into Gecko to speed up style processing. This was the first time I collaborated with many people on a project, and it was also when I started writing Rust code in my work. To get Servo’s style engine into Gecko, it needed to pass all existing test suites. For this, I created a crude DSL to classify tests to determine which ones Stylo was still failing, and then gradually closed the gap between the new and old engines based on that.
Overall, my time at Mozilla was very enjoyable: I had a good salary, traveled the world every year, contributed to well-known and widely used open-source software, and even participated in the development of web standards.
Although developing Firefox at Mozilla was my dream job, there’s always a gap between ideals and reality. Due to some previous project collaborations, I had some contact with many colleagues in the Taipei office. Before the All Hands in the UK, I even spent a week touring the UK with some Taiwanese colleagues. For this reason, Mozilla’s decision to close the Taipei office and lay off all the Taiwanese colleagues came as a huge shock to me. Not long after, the manager who had invited me to join Mozilla also left the company. In addition, as Firefox’s market share continued to decline and criticism of Firefox became rampant online, all of this was very harsh to my ears and brought me a lot of stress. For all these reasons, I began to think about leaving.
Just then, a recruiter from Canva contacted me, introduced me to this Australian-native unicorn company, which was already valued at a billion dollars at the time, and invited me for a visit. I then joined Canva as a frontend engineer, leaving Mozilla after four years of work.
Canva
Many people change jobs to get a salary increase, but when I moved from Mozilla to Canva, my salary didn’t change much. The base salary was the same, and my bonus was replaced with stock options, so the cash I took home actually decreased. But my reasons for joining Canva were multifaceted: for one, after developing browsers for a long time and seeing how complex and obscure frontend code had become, so different from what I used to write, I became curious about what frontend development was really about. Secondly, having worked from home for four years, I wanted to try what office life was like. Thirdly, I can’t deny that I also fantasized about joining a startup and achieving financial freedom through the appreciation of my equity.
After joining Canva, I joined the Editing team, which was involved in developing the editor and was, in a sense, the most core team. When I joined, the E2 project to rewrite the entire editor with React had just been completed, so my main tasks were mostly implementing small features. A memorable one was optimizing the editor using Intersection Observer to prevent it from rendering pages outside the viewport. This optimization helped increase the editor’s support from just 20 pages per document to 100.
Although the Editing team was said to be a core team, it was once disbanded, and all its members were scattered into different teams, though we still had regular meetings to coordinate and discuss. During that time, I was assigned to the Collaboration team, where I helped develop element locking, in-editor commenting, and displaying the avatars of online collaborators. It didn’t take long for the company to realize that not having an Editing team was unworkable, so the team was reassembled six months later.
One of the first major projects I participated in was probably EditorX, part of the larger WebX project. This project aimed to make the web version run on mobile devices, replacing the natively implemented editor in the mobile clients. This would provide a more consistent experience and unify the codebase, eliminating the need for large numbers of iOS and Android engineers to each maintain a separate version of the editing and rendering code. Many mobile engineers were retrained as frontend or backend engineers. A major challenge of this project was battling with different platforms. The WebViews on iOS and Android had many differences, a significant one being the soft keyboard—its size, when it appears, its effect on page layout, and its side effects (like pushing the entire page up) all varied. A lot of time was spent understanding their behaviors and finding common technical solutions as much as possible.
Another major project I was involved in was Whiteboards. The two biggest challenges for the Whiteboards project were performance and the lack of a fixed page size. To enable the existing codebase to support whiteboard pages, extensive internal refactoring was done, which also introduced a lot of technical debt that we spent the next several years paying off. Performance is an unavoidable issue for a whiteboard product, as its infinite canvas naturally encourages users to add more content. One of Canva’s main technical directions is to use React+HTML for design rendering. While this approach offers many implementation conveniences thanks to web features—such as native text selection, seamless embedding of external components with <iframe>
, and easier support for complex text rendering features (like vertical text) and video playback—it is also limited by browser implementations, leading to issues like cross-platform rendering inconsistencies. A more significant problem with this method is performance. Each element in a design requires many React and DOM nodes for various reasons, so as the number of elements grows, performance drops sharply. Because of this, even after many optimizations, we still limited the number of elements on a whiteboard to 1000 at launch, far below competitors’ products that were based on <canvas>
rendering.
Later on, I participated in the Doctopus project as a lead architect. This project was released to the public earlier this year as “Visual Suite 2.0 in one design”5, allowing different sizes and types of design pages to be embedded within a single document. Many features within Canva were tied to a concept called “doctype,” which indicated whether a document was a presentation or an A4 print, for example. For a long time, Canva’s editor assumed that only one doctype would exist throughout its entire lifecycle, so many features determined their behavior based on this fixed doctype at page load. However, Doctopus completely broke this assumption by migrating the doctype from the document level to the page level, thus requiring these behaviors to be determined dynamically. This meant many features needed some degree of refactoring, and some parts even had to be rethought from a product perspective, involving many teams across the company. But as an architect, apart from writing the initial technical documents and some early foundational code, I mostly just communicated with others, providing ideas and direction, while the truly heavy implementation work was done by other team members and colleagues from many more teams.
I’ve worked at Canva for six or seven years, longer than my time at Mozilla, and have been involved in many projects, big and small. As the company’s organization changed and my own position became more senior, the time I spent writing code decreased, with more time spent on code reviews and communicating with different people, understanding their needs, and providing technical guidance. It was then that I truly realized a software engineer’s job isn’t actually writing code, but communication: communicating with your past and future self, with other engineers, with product and design staff, with the computer6, communicating through video conferences, in person, on instant messaging tools, and by writing documents and comments.
Canva is a great company, and I feel very lucky to have joined it, so I am grateful to the recruiter who brought me in.
The company has a very product-focused culture, constantly conducting detailed user research. This isn’t just about surveys or data analysis, but also directly interviewing users, observing their behavior one-on-one, and understanding their thought processes. There are also dedicated people who track user feedback; whether it’s direct reports or comments on social media, it all gets compiled and fed back to the product teams for consideration. I think this is perhaps one area where Mozilla was lacking. Mozilla has many incredibly talented engineers and a great engineering culture, but its attitude and approach to product, as well as the top-level understanding of users and product direction, were, at least from what I observed, severely lacking.
Excellent benefits are another one of its strengths. There’s a varied breakfast and a delicious, hot, and different lunch every day, plus a constant supply of various snacks, drinks, and ice cream. Teams also organize activities from time to time, either to celebrate achieving a goal or simply for team building. The activities are diverse, from remote teams playing games and doing crafts together to in-person gatherings for escape rooms and go-karting. The company has a dedicated team that finds all sorts of different and interesting activities to suggest to teams. In addition, for clubs that meet certain criteria, the company provides a monthly activity budget based on the number of participants7. Furthermore, the company gives everyone three “Force For Good” days off per year, which can be used for volunteer activities, and the company also partners with charities to organize group volunteer events to use these days.
In the years since I joined the company, it has grown rapidly. The number of employees is about ten times what it was when I joined, and the valuation has increased forty-fold. With the expansion of personnel, the organizational structure and management style have naturally been constantly changing. When I first joined, there were basically no titles or levels; a software engineer was just a software engineer, and my manager (or “coach,” as Canva calls them) was also a software engineer. There wasn’t much organizational structure back then, just various teams, it seemed. Our team used to have a weekly Show & Tell meeting on Friday afternoons to report on new features and fixes from the past week. In the beginning, the founders would also attend and praise our achievements. Later, groups were introduced above teams, then supergroups and subgroups, and recently, another level, orgs, was added. In terms of the work we did, our team back then is now two groups. Job levels were also introduced, and later, the levels of all engineers and engineering managers were made public through different titles.
In these years at Canva, I have truly felt my own growth. I’m no longer just someone who buries their head in writing code; I have a deeper understanding of architectural considerations for large-scale projects, I’ve been exposed to many aspects of product and operations, I communicate with more people, and I have increasing responsibility and influence (and, of course, stress and burnout).
Outside of Work
For the past decade or so, most of my time has been dedicated to work, leaving very little for anything else. After starting to work, I feel like time flies; years pass in the blink of an eye. This makes me miss my student days, when there were at least two long holidays each year to plan my own things. Although I have annual leave, I always feel reluctant to take it, and even when I do, I feel I should make good use of it to travel and have fun, so in the end, there’s still no time for other things.
Over the past decade-plus, my main form of entertainment has been watching Japanese anime, almost at a fixed rate of three episodes a day. If there’s a new series I want to watch, I watch it; if not, I catch up on older ones. I’m very satisfied with this form of entertainment: it doesn’t require much extra preparation, it’s unlikely to fail, and it’s easy to control the time spent. Although I do play some games or read some manga and light novels from time to time, they don’t have clear episode-like breaks like anime does, making it hard for me to control the time I invest, and I can easily get addicted and find it hard to pull myself away.
One side effect of consistently watching anime is that I’ve become more and more familiar with Japanese. So much so that a few years ago, when I thought about maybe trying to take the JLPT (Japanese-Language Proficiency Test), I found that the difficulty of the highest level, N1, was such that I could easily pass it without any specific preparation8. So I signed up for that year’s test. Although I thought I could pass it without studying, I also wanted to use the test as an opportunity to further improve my Japanese, so I bought vocabulary and grammar books and studied actively for the six months before the exam. In the end, I passed with flying colors, as expected. Because my Japanese comes mainly from anime and my English mainly from work-related communication, I even feel that my Japanese might be better than my English when it comes to understanding daily conversation.
I’ve been a fan of the Rust language since around the release of Rust 1.0, and to this day, it’s still my default choice for personal projects. At Mozilla, I started using Rust for work when I joined the Stylo project. At Canva, although I didn’t use Rust for a long time, I once co-hosted a Rust training session with colleagues and even convinced the company to implement a project, originally prototyped in C++, in Rust instead. For many years, I also managed a Rust community on Telegram called “Rust众” (Rust Crowd), but I ended up closing the group due to burnout from work and disagreements with group members. Looking back, I invested a lot of time, energy, and emotion into that group, like developing evalbot and compiling an FAQ. The group’s username, rust_zh
, was once reclaimed by Telegram, and I had to spend money to buy Toncoin to bid for it back. But closing the group was probably not a bad thing for me personally; at least, I feel like a huge mental burden has been lifted. For a long time, the first thing I did every morning was to check if any issues had come up in the group overnight. After disbanding it, I no longer worry about that. I guess I’m really not cut out for management-type work, even if it’s just for a group.
Around 2020, I came across the Beancount project and started bookkeeping. Although I had used some mobile apps in the past, I never stuck with them. Using Beancount for double-entry bookkeeping introduced me to some accounting concepts and ways of thinking, such as accounts receivable being an asset and accounts payable being a liability, and how to amortize expenses. Some people keep books to understand their spending for better budgeting, but I’m mostly interested in having a more comprehensive understanding of my financial situation. However, having a ledger has also helped me better prepare my annual tax returns and manage my investment portfolio. Over the years, I’ve written quite a few plugins for this ledger, such as a plugin to automatically calculate credit card rewards, a plugin to defer credit card transactions until after the statement date, and a plugin to display a cash flow report. Of course, the more I use it, the more I find things I’m not satisfied with in Beancount’s design, but that’s a topic for another time.
After moving two years ago, I installed a large set of solar panels and a battery at my new home and connected to Amber to start using real-time wholesale electricity prices.9 This has made me pay more attention to the electricity market and news related to renewable energy generation. Because Australia actually has too much rooftop solar generation, the wholesale electricity price is often negative, meaning you have to pay the grid to export power. So, to limit my solar generation, I started setting up Home Assistant. However, once I deployed this system, I began to think about connecting more and more devices and data to it. Many of my recent personal projects have been built around it, including a custom-designed dashboard and information reporting services for some end devices.
A lot has happened in the past decade or so, and what I’ve written here is only a small part of it. Many things I’ve already forgotten, and some I remember but either feel they aren’t worth writing about or don’t want to write about. In any case, what I’ve written is already very long for me, so I’ll end it here.
Footnotes
-
At the time, Gecko was the first browser engine to implement this module. It was supported in Firefox as early as 2014, while Blink didn’t implement it until seven years later in 2021, and WebKit even later in 2023. ↩
-
It seemed like there was only one other person in all of Sydney besides me, while Melbourne had a few more. Although New Zealand didn’t have many people either at the time, there was an office in Auckland. ↩
-
I have to say, Herman Miller’s after-sales service is truly excellent. I found out ten years after buying the chair that they offer on-site repairs, and the repair person even pointed out other things that could be fixed and told me to file another service request. ↩
-
The handling of whitespace in CSS Ruby is very complex. The standard adds five new containers:
ruby
,ruby-base-container
,ruby-text-container
,ruby-base
, andruby-text
. A space appearing in different positions between these containers is handled completely differently. Some spaces need to be ignored, while others require the creation of new anonymous containers to wrap them. All of this must be handled precisely to ensure the subsequent algorithms can execute correctly. ↩ -
And it recently won Fast Company’s Innovation by Design Award. ↩
-
In the past, I mainly communicated with the computer through code; now, I increasingly communicate with LLMs as well. ↩
-
Of course, I think some people abuse this club system a bit, like the Genshin Impact and Honkai: Star Rail clubs doing group gacha pulls, and many food clubs dining at various restaurants. ↩
-
When I did the first official sample test, I got 1/3 of the grammar and vocabulary questions wrong, but I got almost all the listening and reading questions right. ↩
-
The investment in solar panels and a battery is quite substantial. If you look at the return on investment, it’s definitely a failed investment. I no longer expect it to pay for itself. ↩