73

Houndstooth

An open-sourced text and Jekyll CMS editor.

Overview

Houndstooth emerged from a common necessity among several clients during my tenure with Bowtie.co. These clients sought greater autonomy over their company's content without relying on developers for every change. At that time, Bowtie provided a web hosting service called RazorSite and crafted multiple Jekyll websites for clients. Introducing Houndstooth into this ecosystem proved to be a significant asset for the clients we served, enhancing their ability to manage content efficiently.

Features

  • Seamlessly syncs with your GitHub Repositories
  • Auto detects collections for Jekyll sites
  • User friendly advanced file editing
  • Stage and commit changes directly to github

Since the ideation stages of Houndstooth, our team had been experimenting with different approaches of how to best engineer the app. Our primary goal was to structure the frontend in a way that would be scalable while maintaining the app’s integrity through consistent and reliable patterns of component hierarchy and state management. State management was a concern, with features like staging commits and toggling back and forth between the File Editor and Collection Editor. Both the File Editor and Collection Editor are very different environments that interact with the state differently, so we felt it would be useful to have a global state management system to allow all components to interact with a repo, collection items, and staged files directly.

For the first version of Houndstooth, we decided to solve this problem by managing state using Redux, and designing most of our React components as Class based components. As we got further into the development, the complexities grew. Our components were lengthy, complicated, and difficult to understand. This sparked conversations of exploring different and better ways to approach the structural design of the app without Redux.

Enter Recompose and the Atomic Methodology!

Component Hierarchy

Recompose was a library used before React Hooks and leveraged the higher order component (HOC) pattern of designing React components. The combination of the Recompose library and the Atomic Methodology for component hierarchy solved a lot of problems Houndstooth was facing. This pattern also made the app more performant, lightweight, and organized.

Our version of the Atomic Methodology organizes components into 4 categories:

  • Atoms: Very basic, stateless components that act as building blocks for the app. These could include basic HTML elements like form labels, inputs, buttons, etc.
  • Molecules: Built on a combination of Atoms, but they are still fairly basic and stateless. Molecules rely only on general props in order to maintain its reusability. The components are expected to be fully functional in any parent component for any application without modifications.
  • Organisms: More robust components built of Atoms and Molecules. Organisms can have state that is specific to the application, but typically just internal state that the rest of the app does not rely on.
  • Ecosystems: Ecosystems are grouped by the data they manage. You can think of an Ecosystem as the controller for a specific group of data. They control the flow of shared data to their children and routing to nested components. The views of Ecosystems should not be too complex. Essentially just a rendering of organisms and routes. Environments: Environments are similar to Ecosystems, but they serve as a wrapper for the entire application. It is what actually gets rendered by React. They manage very high level data that everything in the app needs to know, i.e. authenticated user.

With this methodology, we are able to group our data and organize our components accordingly. This also allows us to fully capitalize on the reusability of our components! The image below shows how Houndstooth ecosystems are organized:

Recompose was a utility library for React components intended to allow a user to build components based on composition, rather than class inheritance. Recompose methods create a chain of higher order components to inject logic, props, state, and handlers into a block of renderable jsx. With the atomic organization of components this becomes a very powerful combination. We are able to create only stateless, presentational components that are more performant, lightweight, testable, and abstracted, then use containers to completely separate out the logic.