BRYAN TRAVIS HOOPER
May 23, 2021

I Hit the Road

With COVID restrictions loosening up, for better or worse, and with my vaccination well established, I decided it was time to venture out of the quiet spaces of Vermont where I have been for over a year now. So I set up some lunches with family and friends and headed down to Connecticut. Not a huge trip - but a good chance to test my traveling abilities before some longer road trips this summer.

As I left Vermont, I realized that it has been a long time since:

  • I saw a billboard sign. I haven't seen a billboard sign in over a year.
  • I saw a Tesla charging station....in Meriden, CT! The electric revolution is coming.
  • I drove in traffic. I was even cut off!
  • I talked to strangers. This seemed to be a universal issue, as everyone I encountered seemed quite chatty.

It was great to see friends and spend time with people I haven't been able to spend time with. It was nice to see a different part of the earth. And it was nice to drive old familiar streets in Hartford.

May 10, 2021

Overstatement is Now Built with Zola

Every year or so I revisit this blog and think of a new way to do it. Mainly I view this as a learning exercise, so I try to find something new and interesting that I would like to try.

Recently I have been interested in static site generators. The previous version of Overstatement was build with Jekyll, a Ruby-based static site generator that is very popular. Since I know a little Ruby, it made sense to me to use Jekyll. Jekyll is robust, with a large community behind it. If you need help, it's easy to find. If you are looking to implement a feature, someone else has probably already implemented it.

There are two downsides to Jekyll in my view. One is that it is slow. Compared to other options, Jekyll generated even my little web site noticeably slower. Since you only generate the site when you have to update it, this isn't a really big deal for me, but for more active sites this could be a deal breaker.

The second downside, and this is an issue with a lot of software these days, is Jekyll's dependencies. A static site is by nature a secure site, generally speaking. But Jekyll has had a few security concerns with some of its dependencies in the past. Of course, things were patched and updated. But if I have a choice between a lot of dependencies or not many dependencies, I say the fewer the better.

So for this new version of Overstatement, I went with Zola. Zola is a fairly new option, and instead of Ruby it is built with Rust. I was interested in Rust because it is a lower level programming language, which means it is fast. Rust generates my current site in 85 milliseconds. That's almost instantaneous. Rust is also open source and is being developed in a transparent manner. I think it is one of the more interesting programming language projects going on right now, for what little I know.

Oh, and Zola has no dependencies at all. Zero. It's just Zola. That keeps it fast and simple.

Zola's biggest downside is that because it is newer, and a little niche, it has a smaller community. It was harder to find help online, and the documentation, while good, is incomplete. I figured everything out for the most part, but it would have been helpful for me to know a little Rust. Another thing to learn!

Zola is also pretty simple. It does not have the robust feature set that Jekyll has. My site is simple, so Zola being simple is perfect. But I imagine a more complex site would be challenging to implement in Zola. I hope Zola continues to grow and gain more support and features, while remaining fast and reliable.

One feature I really liked was "shortcodes", a concept the Zola team stole from WordPress. These little micro-templates make it super easy to reuse code and pass parameters around as needed. I used shortcodes for my vimeo embeds and to generate a gallery. I also like the way Zola encourages you to store assets and blog content together. At first this was counter-intuitive to me, but it made more sense as I used it. Images and documents are stored in a folder with blog content making it super easy to include them in the blog post and also keeping everything logically together.

One other change I made with this version of Overstatement is I converted all the CSS to Tailwind. I have used Tailwind on a few projects now and I'm starting to really like it. It's biggest advantage to me is how easy it is to change and update. You can design almost anything with it, and you can customize things as you need to. So, it feels like it can be the super-framework for a good long time. I can completely change the look of Overstatement without changing my framework at all.

All in all this was a fun project. I love learning new things. I look forward to seeing how/if Zola evolves. Hopefully, this version of Overstatement can serve the Overstatement community for a few years. Or until I want to learn something else.

April 7, 2021

Coming to Terms with React Router

When I first learned about modern approaches to routing user requests to the appropriate resources I was learning Ruby on Rails and working under a RESTful paradigm. Next, I learned a bit about NodeJS and Express, which seemed to me to work in a very similar fashion. When I started learning React Router it seemed very different from those two, and I finally concluded that that's because it is!

First of all, let me explain what I think the purpose of a router is in a web application. A router is the collection of tools that interprets a request from a user, usually by parsing a URL, and directs the server to the controller or method that is designated to respond to that request. Usually, this results in a server response to the user that provides the requested resource. In a RESTful app, this would look something like this:

  • User requests http://xyzcompany.com/products in their browser.
  • Router has a GET route for /products that instructs the server to execute the #index method in the Products controller.
  • The Products controller retrieves all the products from the database, formats the data in the desired format (usually HTML or JSON) and returns the formatted data to the user. (More formally, the controller sends the data over to a view which handles the rendering, but nevertheless.)

But with React Router, there is no back end server at all, so everything is handled in the user's browser. Since it always seemed to me that the key feature of a router was the routing part, I found this a bit confusing. I found it useful for myself to think of React Router as more of a filter for components, that does its filtering based on the URL. React Router does more than this, but in terms of how it simulates a traditional Router, this is a key point. New components are shown based on a pattern matching algorithm that matches URLs and updates the browser's history to simulate page refreshes and different resources loading.

An artificial example will illustrate this point.

See the Pen React Router Example by Bryan Hooper (@bthooper) on CodePen.

If you examine this code, you will notice a list of links working more or less as a navigation menu. The links are created using React Router's <Link> component, which creates the <a> tag for the link. Each link points to a simple URL. Then, down in the App component, the <Route> components, also from React Router, direct traffic to render content depending on which route you are requesting. It seems simple enough, but React Router does some funny things with matching the URL and the paths. First of all, if you head over to codepen where you can play with this code, you will notice that every route you choose always renders the "/" route - namely the word "Home".

You might conclude that React Router is just matching whatever meets the minimum requirement to match the route. If it starts with "/", as all routes do, than the Home route will always match. You can see this behavior again when you click on More About. Here, the URL is "/about/more" and that matches "/" and "/about" as well as "/about/more."

But when you click on More Yet, things get a little fuzzy. The URL is "/about/moreyet" but only "/", "/about" and "about/moreyet" are matched. What wasn't "/about/more" matched? My guess is that React Router doesn't look at the URL as a string, but rather as a collection of strings separated by "/". So each string is comparaed aginst the other string within that segment enclosed by "/"s. The other somewhat unexpected behavior is demonstrated when you click on Blog. Two routes are pointing to "/blog" and so, when you click on that link you get both routes back! I guess it isn't that surprising, but one can see how it might produce unexpected results.

React Router provides a Switch component that can address some of these issues. Switch works by finding the first match and then only rendering the first match. However, it too can produce some surprising results if you aren't careful. Simply adding the Switch component around our routes will resutl in ONLY the home route displaying, since it is always matched. The "exact" keyword can be used to only match a URL exactly to overcome this problem.

In my mind it was helpful to think of React Router less as a routing tool that loads assets when requested by a user and more as a conditional rendering tool, that renders components based on matching the URL. Instead of a "router" I thought of it more as a conditional render tool. Routes are more like conditions or "if/then" checks that decided when to disply a component based on a given URL. Once I started thinking of React Router this way, it's behavior made much more sense to me and I was able to build more reliable React Router routes.

React Router is a powerful piece of software that does more than just "direct traffic." It also manipulates the browser history to maintain the appearance of a true router and preserve your URLs just like a real URL even though it is all rendered in the browser. I have only started scratching the surface of React Router, and I am eager to engage with it some more.

March 8, 2021

A Lectionary Browser

Recently, I have been working on an interactive Lectionary Browser. A lectionary, in case you do not know, is a collection of scripture readings used in the planning of Chrisitan worship in some Christian communities. The most common lectionary is the Revised Common Lectionary, which is the focus of my little app.

The RCL consists of a three-year cycle. Each year contains a year's worth of readings for every Sunday of the Christian Year and also some special days. And each day is part of a particular season that corresponds to the time of the year. The seasons are the same every year, but the readings for each day are different.

The RCL names it's years with a complete lack of creativity. The first year is named "Year A." Guess what the others are called? Year B and Year C! So clever. But they are somewhat thematic as each year tends to focus on one of the synoptic Gospels (Matthew, Mark and Luke) and all of the years turn to John for special days.

The seasons used by the RCL are Advent, Christmas, Season After Epiphany, Lent, Easter, and Season After Pentecost. The Season After Epiphany and the Season After Pentecost are somtimes referred to as "Ordinary Time" but the use of the word "ordinary" is confusing. It does not mean that they are dull. Rahter, it means they are "ordered" or "ordinal" and thus follow the pattern prescribed by the lectionary.

For my app, I first created a Ruby on Rails back end that served as an API for the lectionary readings. My application supports muliptle lectionaries, though I only modeled the RCL. In the future, I could add additional lectionaries easily. The Lectionary Browser also provides a RESTful interface, so resources are found via logical URL structure. All requests made to the RESTful API are responded to with standard JSON responses.

For the frontend of my app, I wrote a React app that uses Redux for state management. Redux was the most difficult part of this project for me because it is conceptually a little complex, but as I build the app and started using it in a real application, I started understanding how it works.

I made a nice video to show you how the app is supposed to work:

The hardest part of this project for me was getting my head around Redux and how it is supposed to work. Redux is a tool for managing state, which is something React does natively, but the React model is somewhat limiting. With Redux, you can provide pieces of your state to your components as you need to from a centralized store where all your state is stored. In order to accomplish this, the Redux packing provides tools for creating your store and manipulating it. Another package, called "react-redux" makes Redux integrate nicely with your React components by connecting them to your Redux store - with a function cleverly called "connect."

Once you have your components thought through, and the data they will need discerned, you can connect them to your Redux store and retrieve the data you need for that component. Changes can be made, but you have to be careful that you don't mess up your state, so Redux uses Actions and a Dispatch function that manages your changes to your state. Your actions are simple functions that describe your changes, and dispatch is a function provided by Redux that safely updates your state. While it sounds complicated, and it is a bit, it actually makes state management much simpler.

I hope to continue working on this project, adding a user model and note taking capability among other features. So, perhaps, if I find time, I will make this app more useful.

October 20, 2020

My First Hackathon

Last week I participated in my first ever "hackathon."

A hackathon is an event where teams of programmers and nerds address a particular problem with a technological solution over a set time period. Often these are 24 hour or weekend spanning experiences that encourage sleep deprivation and poor diet choices. Ours however spanned the whole week since it was conducted virtually to accomodate the COVID age.

The Future of Forestry Hackathon focused on the forestry industry in New England and was partially sponsored by Do North Coworking where I sometimes hang out. I was part of a three-person team randomly put together as part of the hackathon. Getting to know each other and work well together in such a short time frame was one of the challenges of the hackathon, but we ended up working well together over Slack and email. We decided to tackle the first problem statement:

How can environmental and geospatial data be used to evaluate potential logging margins to ensure they are commensurate to the financial risk associated with harvesting wood? Reliable margins in logging can be challenging to come due to unforeseen environmental factors. In many cases, market value of the harvested wood doesn’t reflect the time and risk associated with the harvest for specific trees. Whether the most valuable trees are two miles in through dense forest requiring significant time and fuel or the tree is on steep slope making it very dangerous or challenging to harvest, the market pricing doesn’t reflect these factors, nor do loggers have the tools to do this evaluation.

Our solution focused on providing a core set of tools for assisting in the process of valuing standing timber and risks associated with harvesting that timber. We used GIS data provided for us as part of the challenge to map a small farm and provide information related to the timber on that farm and how to navigate the terrain. We also created a calculator tool that allows for inputs from a harvester to calcuate the potential financial value of a paricular tree.

A number of problems arose as we worked on this project. I was surprised at how difficult it is to find regional pricing information for harvested timber. I assume these prices are confidential and that lumber mills who buy harvested wood don't really want to share their prices. It would be a neat project to find a way to report pricing information or to work with an industry group to encourage more pricing transperancy. I think more clarity about pricing would assist harvesters in evaluating the potential reward for their efforts and also find suitible buyers for thier produce.

It was a lot of fun for me to work on this project and I look forward to another hackathon in the future. For my contribution to the project, I configured a Linode server and installed the necessary software. I set up NodeJS and used ExpressJS to build out a webserver. I also created the Tiber Tally calculator feature. My partners did the heavy lifting on all the GIS stuff and the CSS/design pieces. There is currently a server up and running, but I won't be able to leave it up forever since it's cositng me a little money.

Since we are in the Northeast Kingdom of Vermont, not a lot of teams finished their projects. Despite quite a bit of initial interest, only three teams submitted final projects and one of those teams was not able to present because of internet problems. Nevertheless, I am proud to report that our project was selected the winner! Not bad for my first hackathon.