Paramjit Singh

Sep 17, 2022

Implementing a chess transcriber in React

React is today one of the most popular frameworks for coding UI layers of modern web apps. By the moniker “modern”, I mean an era where best practices have matured for the vast majority of use cases & some level of declarative programming has been achieved (you code what should happen, instead of how to do it).

I think there are two fundamental aspects of React’s popularity (especially compared to the frameworks / libraries used before it):

  • Component architecture. Stemming from the CS notion of separation of concerns, React simplifies building complex apps by encouraging modularity (plug-&-play), reusability (DRY) and clear abstraction. This aspect has been kept in mind in the former frameworks as well, and React continues to implement it (much to the benefit of engineers for whom React is their first framework). Note the emphasis of React’s separating concerns despite coupling HTML/CSS and JS.

  • Reactive programming. This is a declarative paradigm to create systems where asynchronous functions automatically handle updates to static content, without the programmer having to explicitly implement the updates. Over the last decade, this has transformed the engineering world with the rise of the internet (aka asynchronous land). Event loops/queues & efficient updating of declarative code has been extensively used to design reactive systems and React is a library bringing similar patterns to web UIs. Like in much of engineering, while imagining a system where only the updated UI pieces (only things to be done) are re-rendered (get done) is easy, implementing it in reality is hard (browser DOM operations are expensive & not designed for it). React tackles this by using a reconciliation algorithm on a virtual DOM (a JS object representing the DOM tree) to handle this reactively.

Chess transcriber

Here I want to talk about how I implemented a chess transcriber using React (source).

  • Designing component architecture. The UI has a decent level of complex logic to it. At first, I divided the app in a Left Sidebar, main Chessboard and the Right Sidebar. The Left Sidebar should state instructions on how to use the app & let you choose functionality, the Right Sidebar should give functionality-specific instructions. And the main Chessboard is where all action should happen.

  • Implementing the Chessboard took some thought and really capitalizes on the abstraction model of React. The entire Board (enclosed in a wooden box) has 64 Tiles, where each Tile’s props characterize it’s color, an onClick event listener, the piece on it & options to highlight it. I used the chess.js library to handle the underlying chess logic (the library has been coded over 10 years and provides an excellent API), and designed the UI dataflow keeping the library’s interface in mind.

  • Handling the application state. At first, I tried passing props around to handle the UI updates, but it quickly became too complex to deal with. Not that it couldn’t be done, but the resulting design was ugly (not well abstracted, lots of re-implementation of code & lots of passing data to places where it doesn’t exactly need to be). I researched a bit, and indeed there are central state store implementations (often with the Flux architecture), which people like to use for complex component trees. I chose Redux to store where the pieces exist on the board & which are the highlighted tiles for a move, etc., and made the app work.*z4zTg1NIUHNFEtPLnOuD-w.png

My chess transcriber web app

A second look & re-architecture

The more I learnt to think in React (and since I wanted to improve the app), I thought through exactly which component needed which data flow and how to arrange them in a well-organized dataflow-lean way. I decided to re-architect the app making the following changes.

  • Component architecture. At first, I had divided the components focusing on UI, but that seems like a mistake. I have now divided the components based on functionality. The UI is an implementation / representation of the underlying UI logic — the main app (in JS) which says what is happening. This app (like any application code solving business logic) is divided into functions (i.e., by functionality). It often happens that this translates to separate UI components, but it’s important to note that the underlying driver of this abstraction is functionality, not UI. (For example, you can have a UI mixing up all outputs of various components in a well-written React app).

  • State management. I realized that my app (much like a lot of apps out there) don’t really need to use Redux or even React’s Context API. This came in time when I realized that using Redux really makes sense when you want the actions (state changes) themselves (whether for bug reports, persistent storage or syncing UI across network). That is, in a way, Redux helps to decouple the actions from the components themselves. Even deep component trees which on first glance seem like they would benefit from a central store (via Flux or Context) can often be rearranged in a way that encourage component composition with appropriate local state initialization / usage.

This app has been pretty useful to appreciate the underlying design choices of React and to understand when exactly to use (or not) Store libraries. Clean code comes from clean architecture, which requires having a clear idea of what exactly various tools offer, and when they make sense to use. Try out the app, and let me know your thoughts!

This article was cross-posted to Medium &, so you can also follow there or post comments.
Sep 5, 2022

Your users are not your sole audience

One of the first things beginners in software engineering learn is to dote on their source code. As if getting up to speed with the latest tech stacks & platforms was not challenging enough, the industry (not without reason) places great emphasis on how you code. One hears about phrases like human centric design & testability, and wonders what the problem is if one’s software just works.

Why can’t the thing just work?

One needs to undergo a mindset shift to realize that code must be written not only to make the end product work, but also to be readable to other developers. That is, of course, if one does not wish to solo their way through the entire project lifecycle (not a great idea for anything long term).

So the idea to internalize is that your source code is also a product. That’s the product you use to demonstrate your skills (sell) to your future employers/collaborators, with whom you then collectively sell your software to users. Once you have this mental model set up, it’s much easier to make sense of software engineering culture and **understand where the vast amount of literature (blog posts, video, podcasts, etc) comes from.

Social trumps all

Human beings tend to get social about the things they do, no matter how technical or mathematical they are. That’s called Conway’s law or something. Namely that organizations design systems that mirror their own communication structure. What happens if you apply this law to an industry? See what I mean?

People generally also care more about the social aspect of their work than just technical correctness, or even mastery. That’s why opinions, conventions and standards start to matter. Developers have tastes and it’s easier to work together when those tastes are in tune. That’s one reason (among others) why you hear empathy talked about so much in developer circles.

Organizational thinking

There’s another important aspect. Any large influential project or organization must necessarily involve many people. While it may naively seem that multiplying effort multiplies output, it takes great foresight & management skills to make one plus one greater than two.

Behaving oneself

Most of the non-programming skills engineers need to master are just that. Project management skills in the context of software. While much of this is commonly learnt like gospel, in a “this is how you do it” sort of way, there’s value in sticking to the basics and realizing that professional engineering is a social process, and there are notions of manners. While many of these manners aim to improve productivity / simplify architecture, some of them have idiosyncratic origins. And that’s ok. Just important to distinguish them from the technical skills, to understand the motivations behind workflow choices.

This article was cross-posted to Medium &, so you can also follow there or post comments.