Celebrating CSS: Testing the Versatile Yet Elusive

I love CSS despite I know there are a lot of haters out there.

The problem with CSS is not cascade. The problem with CSS is it is hard to test. We know how to test JavaScript — create a bunch of test cases and assert the outputs — but we know too little about how to validate CSS outputs (the layout) effectively. It is so frustrating, to the point that people end up demanding “simpler” abstractions on top of it to prevent mistakes.

You can read back layout in JavaScript and assert the dimensions, but not everything is exposed (like ::before or ::after,) and some states are hard to reach (like :hover or dark mode.)

Or, you can create a screenshot tool to diff the pixels. You would still face the issue above, in addition to maintaining a complex test suite across multiple browsers and multiple OSes. On, and different versions too, including underlining text rendering changes.

Regretfully, none of these are easy enough than hiring QA engineers to manually click through the pages.

In a way, CSS is a victim of its own success — it is so versatile and adaptive, allowing you to achieve a lot with a few lines of code — and cause regressions in the same few lines if you are not careful.

Maybe this is a problem of declarative languages in general. I don’t know how to write test cases for a spreadsheet either, and there are no well-known or built-in tools for that, after more than a half-century since its invention.

Cracking this problem may be the thing that could make CSS popular.

Book recommendation: Taiwan, A Contested Democracy Under Threat

Taiwan: A Contested Democracy Under Threat (Flashpoints)

You should care about that island nation called Taiwan. Not because I told you to (and I am obviously biased,) but because how your democracy engages the country reflects its value, and to some extent, your value.

You should also try to understand it through its rich, complex history and people. Not just commentaries in the news when pundits speak of U.S.—China relationships.

Taiwan: A Contested Democracy Under Threat is the best book that I know of that will tell you all about it. The book thoroughly explored how Taiwan became what it is today, how it transformed itself into a young democracy, and most importantly, a framework to look ahead.

I have been reading Lev Nachman‘s perspectives on contemporary Taiwan for quite a while. The book did not disappoint. I enjoyed the fresh new take on a topic that I’m already familiar with, especially through the lens of International Relationship studies. It was also entertaining in a way — I crackled when the authors explained how the two major parties employ their own versions of “strategic ambiguities” when cornering votes (my take, not the view of the book,) while precariously trying to avoid angering the bases. It is happening in real-time right now again, with the presidential election less than 30 days away.

I am especially appreciative of the conclusion:

Superpower politics and the conflict are the dominant lenses through which Taiwan is seen internationally, but Taiwanese agency and the complexity and diversity of Taiwanese wants and needs deserve to be heard.

Please get a copy. I am sure it is a worthwhile read.

On Software Quality

One perspective I’ve profoundly changed compared to the junior engineer in me is how I see software quality. With decades of economic expansion and Internet boom, our industry has learned a rather sloppy norm on quality. In this post, here are my takes on how you should approach software quality.

Your User is Your Customer

Only software engineers and drug dealers call their customers “users”.

— a random joke on Internet

The joke is meant to be a joke, but there is some truth in it. The term “user” fails to remind listeners that software, like everything engineered in the world, is experienced, explored, and felt by human beings. A human being that makes intentional efforts to tinker with your creation.

Some people find the word strange because “customer” implies these people are paying for the software. I would argue that this is always true, no matter your business model. Traditionally, your customer pays for software download, or the CD-ROM containing the software. Nowadays they may pay through subscriptions. Often people pay indirectly through advertisers that put ads on your UI. Even the free-tier customers of your freemium service pay with their time.

Surely there are times when you need to distinguish between “end-users” and “external developers” when your software interfaces both. Or your business software is paid for by businesses serving their employees. Yet at the end of the day, all parties are your customers.

Software engineering is one of the highest-paying industries. Like any other economic activity, it interacts with the rest of the economy, creates value, and transfers wealth. Referring to your customers as “customers” acknowledges this fact with gratitude.

Software Errors are Interruptive

Try to reload the page if you encounter an issue. Clear cookies and open the browser again.

— literally every troubleshooting article

No, your website shouldn’t stop working because you fail to bust the cache. Your app shouldn’t crash because you fail to handle an edge case. Period.

Sure, it is hard on the web to deliver assets atomically. Formal methods are not realistically deployable yet. But those are the problems our industry needs to collectively solve, not hand-waving them and leaving the problems to the “users.”

During the boom, such an attitude is tolerated, because software creates much more value to the economy predates it. Software engineering is the economy now. It occupies a much critical role in people’s lives, than that gimmicky website for ordering books.

Assume people’s lives depend on your software doing the right things indirectly even if the use cases don’t suggest that. We are not all software engineers working on avionics software, but you never know how your software would be repurposed.

We are, ultimately, all software customers. You wouldn’t want to spend 5 minutes resetting the light bulbs every other day, don’t you?

Respect your Quality Assurance Engineers

The next inspector is the customer.

— a banner that should be in your office

For some reason, QA engineers are being paid less than software engineers in general. That translates to an unhealthy disrespect to QA engineers — pushing back on what they found, questioning their value to the project, etc.

It is true that QA engineers is the easiest entry point into software engineering (the next being, err, web front-end engineer.) The best QA engineers are, however, generalists — they know a little bit of everything to effectively ensure software quality; they self-motivate and constantly reinvent themselves for the next best way to identify customer-facing issues. They do much, much, more things than manual test case runs.

Sadly, I do not see this notion changing any time soon. Life finds a way, many QA engineers end up taking the title of “automation engineers” or “build and release managers,” as an attempt to shed the stigma of the plain title with whatever supporting responsibility the team shoves on them.

Assume the QA engineer in your team does more than manual testing, and stop treating them with whatever feeling arises when you hear the title “QA engineer.” We are all responsible for quality. Given how critical software errors may be, identifying them before shipping could very well save lives.

Quality Metrics can be Automated, but Release Cannot

A computer can never be held accountable. Therefore a computer can never make a management decision.

— a memorable quote, allegedly from IBM in 1979

Tests can definitely be automated and they should be automated. Quality metrics and observability are software engineering problems with software solutions. However, eventually, someone needs to make the judgment call on quality and releases.

Software release/sign-off quality is, and forever will be, the managerial decision that can’t be automated away. This is a responsibility that falls under QA engineering, which makes their job indispensable.

Even if your project has no dedicated people responsible for QA or testing, someone is making a go/no-go decision based on quality. That someone, by definition, is subsuming the role.

Developer Experiences is a Means, not an End

Especially in Web Engineering, people lose the big picture when engaging in developer experience (DX) discussions. Unidirectional or bidirectional data flow. Static typed or dynamically typed. Test case paradigm on continuous integration pipelines. Git flow or GitHub flow. The list goes on.

There is no point in arguing any of these if people can’t agree that the end goal is to elevate software quality. Developers’ quality of life is important, but it is secondary to that goal. For me, the best developer experience is what allows me to make fewer mistakes, in the same development timespan.

There will always be “rockstar developers” showing up and telling you their next project is the best thing ever, or their methodology is perfect. Give them a hard look through the lens of software quality — many of them fall apart pretty quickly.

One persistent DX argument is “fast.” Faster tool does contribute to software quality by tightening the feedback loop. Regretfully, the adoption and maintenance cost of a newer, immature tool often offset the gain.

Compared to “fast,” I am much more interested in “correct” — like a programming language that can eliminate use-after-free, or prevent TypeErrors in JavaScript alone. Only you are in the position to judge adoption and the maintenance cost though, no one else.

Conclusion

Software provides values like any other machinery driving the world. Its excellence is measured by quality, and quality is measured by the experiences of those who interact with the software.

As software engineers, we are mortal code-typing intelligent monkeys, sitting in front of a keyboard trying to ask silicons to do the right thing. We are undoubtedly empowered to figure out “how” we can be better at doing it — but we should do so without losing sight of “why,” and treating others better.