Alex Richey

Software Engineer @ Amazon

On Looting

It is in one’s interest to follow the law when one is also protected by the law. But if one is not protected by the law, then what interest does one have in following it?

It is in my interest to follow the law by abstaining from stealing from others, for example, because others will not steal from me. The law enforces this, such that, if someone does steal from me anyway, then she will be punished and, if possible, my property will be returned to me. This is, roughly speaking, the way the social contract, as expressed by many many western philosophers, is to function. We give up certain freedoms (my freedom to acquire the property of someone else by force) in exchange for certain protections (the security of my property) that are enforced by the state.

But what if the law is not equally enforced? What if, for some groups of people, they do not receive the protection of the law, despite their abiding by it? What if, in other words, the social contract is breached, in that the enforcers of the law do not deliver its protections?

In such a state of affairs, I believe that looting and other forms of unlawful behavior can be understood in two ways when they are committed by members of groups whose rights are not being protected. First, they could be understood as expressions of civil disobedience whose intent is to produce political reform. In America, there is a long history of political movements that have successfully leveraged this strategy. Notable examples include the well-known stories of the Boston Tea Party, Susan B. Anthony, and Rosa Parks—all of these cases involved the purposeful breaking of the law to make a political point.

Understood in this way, I condemn looting not because it is philosophically unsound, but rather because it is strategically ineffective. There are other, more deliberate forms of civil disobedience—such as those mentioned above, which I do not condemn—that effectively persuade onlookers to take up the cause of reform and which are not susceptible to the objections of anarchy and nihilism that looting is.1

The second way that looting may be understood is that it is a natural outcome of a broken social contract. If the agreement of the social contact is not being upheld, then those who are not being protected by the law have little incentive to follow the law. For example, if the enforcers of the law allow my home to be repeatedly burglarized and do not protect my life or the lives of my children, then the law is not a protective force, but an oppressive one. Under such conditions, I should be interested in securing my life and property only by my own hand and I should feel little compunction, under such conditions, in transgressing the law to benefit myself when I can get away with it.

Understood in this second way, I condemn looting as well. Again, I do not do so because it is philosophically unsound; I do so because, in such a situation in which the social contract is breached, looting is a more-or-less aimless act that accepts and exploits the status quo rather than trying to ameliorate it. It is like looking away from wrongdoing to save oneself the time and trouble rather than doing one's duty to confront the wrongdoer.

But what if reform is not feasible? If reform is truly not feasible, then the argument for my condemning looting understood in the second way does not stand. It does not stand because it would not be possible to ameliorate the situation and it is not fair to condemn people for failing to do what is impossible. In such a state of affairs, in which the social contract is broken but reform is not possible, then looting would be destructive and poisonous to the society in which it occurs. But it would also be a reflection, under such circumstances, of the destructive and poisonous nature of such a society that does not equally uphold the agreement of its social contract.


1. One may think that I contradict myself by condemning looting generally but not condeming the Boston Tea Party riots. I think these cases can be distinguished. I define looting as the stealing goods of whatever kind such that they can be used later. According to this definition, the Boston Tea Party riots did not primarily involve looting. They involved vandalism and destruction of property. The point, so far as I understand, was not to steal English tea for oneself to use later, but rather to destroy the tea in order to make a political statement.

Docker Commands

I use Docker all the time. But still I forget common commands constantly. Here are the commands I need to look up most often.

# Build a container with the a tag
docker build . -t <CONTAINER_TAG>

# Run bash inside a running container
docker exec -it <CONTAINER_ID> bash

# Run bash in a new container
docker run -it <CONTAINER_TAG> bash

# Run a container while mounting the current directory to
# `var/www` in the container
docker run -v $(pwd):/var/www <CONTAINER_TAG>

# Run a container while exposing a port to the host
docker run -p <HOST_PORT>:<CONTAINER_PORT> <CONTAINER_TAG>

# Above two combined
docker run -v $(pwd):/var/www -p <HOST_PORT>:<CONTAINER_PORT> <CONTAINER_TAG>

# Stop all of the containers
docker stop $(docker ps -aq)

# Remove all of the containers
docker rm $(docker ps -aq)

# Delete all of the images
docker rmi $(docker images -aq)

# Delete all of the volumes
docker volume rm $(docker volume ls -q)

# Copy stuff from the container to the host
docker cp <CONTAINER_ID>:<CONTAINER_PATH> <HOST_PATH>

Bringing Meural's Frontend to the Bleeding Edge

My article on my.meural's redesign originally published on Meural's Product Blog.

When we decided to redesign our flagship web app at Meural, we took the opportunity to rethink our approach to React and other frontend infrastructure. We ultimately decided to migrate from our own home-cooked server side rendering solution to Next.js, to change our approach to data handling with Redux, and to adopt styled-components. These decisions enabled us to develop and deploy our new frontend in just two months. In this article, I’ll talk about the upshot of these choices and about how things have worked out in production.

Next.js

Next.js is a framework for React apps that handles both server and client-side code. It offers a number of features, including server side rendering and automatic code-splitting in production; and hot module replacement in development. I know from experience that implementing these features from scratch is far from trivial. Therefore, the notion of starting a new project with Next.js at the foundation was attractive.

In addition to these flagship features, there are also positive externalities. Since Next.js is open source and has an active community behind it, common problems are faced at the community-level and standard, well-tested solutions emerge. These solutions can be found in the Next.js repo in a folder called /examples. Inside are skeleton projects with commonly desired integrations such as with Redux, styled-components, and others. Having these examples available significantly reduces mental overhead in implementing such integrations in one’s own project. This accelerates development as a result.

The price one pays for these features is to surrender control of routing and considerable portions of application architecture and configuration. Next.js jettisons the de facto routing standard of React-Router and requires your React application to be divided into what it calls pages. A page is a top-level React component that is associated with a URL. The notion of a page is also what enables automatic code-splitting — bundles are split at each page and preloaded on the client with <link rel="preload">.

We decided that the features of Next.js, coupled with its positive externalities, outweigh the loss of control of our application architecture. Moreover, we found that adopting Next.js’ architecture simplified our application. By distinguishing between pages — those are, top-level components — and ordinary components, the directory structure of our frontend codebase became more easily comprehensible.

Redux

One of the challenges we faced in adopting Next.js is how to persist data across pages. Since Next.js’ architecture is based on pages, and since pages themselves are React components, which are unmounted on navigation events, their state is lost with every page navigation. We solved this problem by persisting state across page navigation events in a Redux store. What’s more, we broke away from standard Redux use patterns by using it only for persistent data.

Roughly speaking, use patterns of Redux can be placed on a continuum where, at one extreme, every bit of application state is stored in Redux and every mutation of state is achieved through a Redux action. At the other extreme, state is managed entirely at the component level and there is no store of global state.

In our previous frontend, we tended toward the former use pattern. This pattern offered some advantages — all data was fetched consistently through Redux actions with Redux-Thunk; and every connected component could gain visibility to any other area of the application. But we decided to abandon this approach for two main reasons. First, the excessive boilerplate that Redux requires makes extending functionality more work than it needs to be. Second, we often found ourselves dispatching actions that essentially mimic ordinary component lifecycle methods. For example, suppose that on componentDidMount, I fetch some data and save it in the Redux store. Then, in order to prevent the user from seeing stale data when this component loads again, I dispatch an action that clears this area of the Redux store on componentWillUnmount. It seems much simpler to store this data in the component state, where it will be naturally destroyed when the component unmounts and naturally fetched on componentDidMount, than to store it in the Redux store where it needs to be manually destroyed.

These considerations led us to the strategy of using Redux only for data that is truly global. As a result, we now have an extremely thin Redux store that stores only user, device, and configuration data. All other data is fetched and managed at the component level. We’ve found that this approach both makes our React components easer to comprehend and dramatically reduces boilerplate.

Styled-Components

The final change to our frontend stack was to adopt styled-components. In some ways, styled-components represent the terminus of a new paradigm in web development. In the old paradigm, the best-practice was to keep markup, JavaScript, and styling separate, on the grounds that these were separate concerns that should be isolated from each other. React changed this by bringing markup into JavaScript which made programmatically rendering markup less cumbersome and more easy to reason about. Styled-Components takes the philosophy that React developed and extends it to styles. It brings styling into JavaScript as well, where it can also receive the benefits of programmatic handling. The result of these developments is that concerns are grouped by component rather than by language.

Prior to using styled-components, our strategy was to include a sass file for every component and to bundle everything together with Webpack’s sass and css-loaders. This strategy was successful, but it often made styling components overly cumbersome. There were also the typical issues of globals and specificity in css.

Adopting styled-components solved these problems for us and, more significantly, it has made predicting and reasoning about the visual behavior of each component easier. We now keep all of the code related to one component in a single .jsx file that contains markup, JavaScript, and styling. This makes each component much easier to comprehend and, from a logistical point of view, easier to change because one no longer needs to open three or four files at the same time to handle just one locus of behavior. Now, I can open several components at once and think about their interrelations and the signatures that each one should have. In other words, I can reason about the application in a more abstracted and powerful way.

Production

The strategies that I described above enabled the web team at Meural, which, at the time, consisted of myself and one other developer, to build and deploy our new frontend in just two months. I believe that our focus on reducing mental overhead by making our codebase easier to comprehend enabled us to deliver on schedule. Nevertheless, we have noticed some issues in production.

The primary issues that we have seen are related to performance and stem from Next.js and styled-components. For all of their virtues, the combination of Next.js and styled-components creates large JavaScript bundles. At the time of this writing, our main.js bundle is just under 800kb and other split bundles range from less than 10kb to more than 100kb. This increased our page time to interactive from under 2.5 seconds to over 5 seconds, which is not acceptable.

With gzip, we can reduce the size of these bundles by roughly 75%, which would get our page load time back into an acceptable range. The problem is that Next.js does not serve static files in a straightforward way. Static assets are built and saved to the /.next directory, but the directory structure does not match the URLs that the client requests. These requests must be routed through the Next.js application to be resolved to the correct static asset. This prevents us from easily gzipping and serving these files independently from the Next.js application.

The solution that we developed is to leverage NGINX’s caching capabilities. For many reasons, we run our Next.js application behind an NGINX server. We decided to use the proxy_cache directive to cache responses at the /_next/ location. The way this works is that the first request for any asset at /_next/ will be forwarded to the application with proxy_pass, but the resulting response will be saved in NGINX’s cache. Subsequent requests will then be served out of the cache. Here are the relevant parts of the configuration.

http {
    # Cache setup

    proxy_cache_path /data/nginx/cache keys_zone=one:20m; 
    proxy_cache_valid 200 60m;

    # Gzip settings

    gzip_static on;
    gzip on;
    gzip_comp_level 5;
    gzip_types application/javascript ...;
    gzip_min_length 1000;
    gzip_proxied expired no-cache no-store;

    server {
        listen 80;

        # ...

        location /_next/ {
            proxy_pass http://application:8000;
            gzip_proxied any;
            proxy_cache one;
            break;
        }

        # ...

    }
}

Conclusion

We have been running our new frontend stack in production for a little over two months and, so far, have had an easy time updating and extending our application. All of the decisions we made regarding Next.js, Redux, and styled-components seem to have paid off and it has been easy to live with the few inflexible areas of Next.js. After we deployed our new NGINX configuration, page load performance was restored to our target range and our application, at least in my opinion, has a wonderful, speedy, and modern feel.