Posts by Barry Hess
A Good Enough Engineer
More about Barry:
https://bjhess.com
Back to all blog posts
-
Why We Built Quack (Beta)
Today we're launching a tiny beta tool called Quack. It is a simple utility for you to share a beautifully rendered version of any markdown text. Type away in our simple editor. When you're done writing, click Share to grab the link for sending to others. There are no servers in this beta. Everything you write is stored in the URL, so every time you change your writing the URL changes as well.
-
Our Favorite Video Games Right Now
While everyone at Good Enough is their own kind of nerd, thank you very much, as builders of the web you probably expect that we also play video games. And we do! Well, collectively we do, but not to an unhealthy degree. Usually.
I asked the team to share with me what their current favorite game console was, as well as the games they are playing right now. The Nintendo Switch is the big winner amongst our crowd, which is interesting because Nintendo definitely seems to abide by the mantra of good enough hardware.
-
· Barry Hess · TIL
TIL: Deploying a Sinatra app to Render.com
This morning I wanted to deploy a simple Sinatra app to Render.com. It wasn’t super obvious to me, so I figured I’d write down what worked in the end.
First, a Gemfile:
# Gemfile
source 'https://rubygems.org'
gem 'sinatra'
gem 'sinatra-contrib'
gem 'puma'* I’m pretty sure
sinatra-contrib
is not necessary.Also at this point in time you’ll need to
bundle lock --add-platform x86_64-linux
for your Render.com deployment to work.Here’s my
main.rb
"hello world" app: -
The Element of Surprise
Good Enough happens to be a remote team. This isn't from some strongly-held belief that remote is best, but rather as a side effect of how we all happened to meet each other. We met remotely, we did not end up all moving into some commune, and so to work together we must work remotely.
Recently we have been talking about what motivates us. The things we said in that conversation could probably turn into a really useful blog post, but I'm not going to write about them right now. I will share that my biggest motivation happens to be this small team itself.
To be able to be in a group like Good Enough where everyone has incredible experience to bring to bear, well, it’s just a complete joy. One of the many benefits fully remote affords is that of surprise. In just a few short months I’m already getting surprised almost daily by the things this team has built.
-
Strong Prototypes, Weakly Held
Excuse any obtuse thoughts that make their way into this writing. I sat down to type with My Life in the Bush of Ghosts by Brian Eno and David Byrne as my soundtrack. This is an album I've never listened to before, and apparently I'm supposed to love it or hate it. Mostly the Internet told me this could be a decent album to work to, so let's find out.
(I'm not going to look, but I'm pretty sure Strunk & White would tell me not to capitalize that "in" in the album title. Yet when I look at Apple Music the title has an "In." Spotify has an "In" and a "The" and an "Of." And people give Wikipedia a hard time?)
So about that title. We here at Good Enough have decided to enter a season of prototyping. Our company has a goal to reach sustainability within five years. As with all time, the end of 2027 will likely come sooner than we think. Yet we are planning to spend all of this first year as a full team on things that are not clearly going to pave the road to profitability. Goodness, why?
-
Our ChatGPT Mission Statement
What follows is an edited transcript of my interaction with ChatGPT to help craft a mission statement for Good Enough. The resulting mission statement was surprisingly good and I had some literal LOLs along the way. Though I think we'll leave out the haiku.
-
Actual Customer Support Is Remarkable
What a sad thing to write.
We believe in good software around here. There is a lot of poorly built software on the Internet and in the app stores. Our motivation with Good Enough is to try to put together a few products that feel just right to the folks using them. The things we build, especially those things we charge for, should respect the customer by streamlining something for them that used to be hard. We hope people enjoy using our software, while also not trying to dopamine-hit them such that it becomes addictive.
While we'll do our best, there are still going to be times where we fail in our mission; especially in the beginning as we're figuring out just how a software should work. Those are the times where polite, helpful customer support helps out. Whether a company decides to do this with phone, email, chat, or a combination isn't nearly as important as a human response in a reasonable time.
-
· Barry Hess · TIL
TIL: Merge nested attributes in Rails permit params
I am working on a new product that's a bit more complicated than our prior releases. Getting refamiliarized with nested parameters in Rails has been interesting. In this case imagine I have a discussion that, when creating it I also want to create the first comment. The discussion information is in a form with a nested form for the comment. So at the base you have these permitted parameters:
params.require(:discussion).permit(:title, comments_attributes: [:body])
That is fine, but I wanted to assure that the discussion and comment couldn't be messed with and would always be associated with the logged in,
current_user
. Stack Overflow told me this would be pretty straightforward these days. Unfortunately that didn't work for me. Perhaps I'm doing something wrong, but I had to get a little more…into it.def discussion_params
_discussion_params = params.require(:discussion).permit(:title, comments_attributes: [:body])
_discussion_params.reverse_merge!(user_id: current_user.id)
_discussion_params[:comments_attributes].each do |key, value|
_discussion_params[:comments_attributes][key] = value.reverse_merge(user_id: current_user.id)
end
_discussion_params
endI'd be happy to hear that there's an easier way.
-
· Barry Hess · TIL
TIL: JavaScript Turbo Stream Requests
I am working on search for Album Whale and I was very confused when my JavaScript fetch requests were not resulting in turbo_stream rendering getting displayed on my page. I checked my logs to see if the render was happening. I looked for missing
<%=
tags. Debugged andlogger.info
'd all over.Then I finally noticed the following in my Rails logs:
Processing by AlbumsController#search as */*
Oh, I expected that to say something about
TURBO_STREAM
, like:Processing by AlbumsController#search as TURBO_STREAM
This sent me on a dive into headers (I didn't have an
Accept
header on myfetch
request), response handling, and the fetch API.Here's what I came up with for our first rough cut of a working, live search field (this is Stimulus code):
-
· Barry Hess · TIL
TIL: Rails Testing
I had to figure out how to run browser-based tests in Rails again. In part that meant working around my lack of Chrome. Rails System Tests with Safari.
I also had some problems with Rails Turbo Drive taking over EVERYTHING, which required me to figure out how to deal with a Rails form redirect not rendering HTML.