Dispatch 5 (and various misc. updates)
This commit is contained in:
88
content/journal/dispatch-5-july-2023/index.md
Normal file
88
content/journal/dispatch-5-july-2023/index.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
title: "Dispatch #5 (July 2023)"
|
||||
date: 2023-07-02T16:55:57-04:00
|
||||
draft: false
|
||||
tags:
|
||||
- dispatch
|
||||
references:
|
||||
- title: "My thoughts on Helix after 6 months - Tim Hårek"
|
||||
url: https://timharek.no/blog/my-thoughts-on-helix-after-6-months/
|
||||
date: 2023-07-02T12:53:51Z
|
||||
file: timharek-no-ah7ilz.txt
|
||||
- title: "What App is That?"
|
||||
url: https://maggieappleton.com/apps
|
||||
date: 2023-07-02T12:53:51Z
|
||||
file: maggieappleton-com-7am49k.txt
|
||||
- title: "Modern software quality, or why I think using language models for programming is a bad idea"
|
||||
url: https://softwarecrisis.dev/letters/ai-and-software-quality/
|
||||
date: 2023-07-03T00:54:57Z
|
||||
file: softwarecrisis-dev-7c7z9g.txt
|
||||
- title: "The small web is beautiful"
|
||||
url: https://benhoyt.com/writings/the-small-web-is-beautiful/
|
||||
date: 2023-07-03T00:52:08Z
|
||||
file: benhoyt-com-vfdv1s.txt
|
||||
- title: "Why You Own an iPad and Still Can’t Draw"
|
||||
url: https://maggieappleton.com/still-cant-draw
|
||||
date: 2023-07-03T01:05:26Z
|
||||
file: maggieappleton-com-fube9k.txt
|
||||
---
|
||||
|
||||
June was dominated by work and travel. Weekdays were filled up with a client project we were working hard to wrap, weekends by plans with friends and both of our families: [Running of the Bulls][1], canoe camping near Saxapahaw, our yearly trip to Beaufort with Claire's college friends, and then a cruise in the Caribbean with Claire's family followed immediately by a trip up to DC to see mine.
|
||||
|
||||
[1]: https://bullcityrunning.com/our-races/running-of-the-bulls-8k/
|
||||
|
||||
<!--more-->
|
||||
|
||||
<div class="image-set">
|
||||
{{<thumbnail IMG_4041 "200x150" />}}
|
||||
{{<thumbnail 11B423F8-5D03-4155-B548-185E04A04595_1_105_c "200x150" />}}
|
||||
{{<thumbnail IMG_9457 "200x150" />}}
|
||||
{{<thumbnail C65C4973-3266-4155-9786-F7B379BD8DD9_1_105_c "200x150" />}}
|
||||
</div>
|
||||
|
||||
Most everything else fell by the wayside, but that's OK -- these were all awesome experiences, and I'm excited for a (relatively) quiet July.
|
||||
|
||||
After getting the trailer hitch installed last month, we picked up a [bike rack][2] and a [seat for Nev][3] and brought the bikes with us to Beaufort. This was **awesome** -- Beaufort's an idyllic coastal town in just about every way but one: parking sucks. Being able to zip up and down the main street on our bikes (and parking them right at our destination) was such a joy, and Nev seems to enjoy the rack-mounted seat a lot more than the trailer we've been using.
|
||||
|
||||
I'm still enjoying using Obsidian to collect link and make notes, though mostly in the "capture" phase[^1], collecting information and starting to put some structure around it. When something comes up and I think, man, I read something good about that at some point in the past, I'm using that as a cue to create a dedicated note, with the hope that the _next_ time it comes up, I'll have a useful thing to reference.
|
||||
|
||||
I also read some good articles about [Helix][4] and [Procreate][5], and I'm hoping to give those some attention this month.
|
||||
|
||||
[2]: https://1up-usa.com/product/2-super-duty-double
|
||||
[3]: https://www.thule.com/en-us/child-bike-seats/rear-mounted-child-bike-seats/thule-yepp-nexxt-maxi-_-12080211
|
||||
[4]: https://timharek.no/blog/my-thoughts-on-helix-after-6-months/
|
||||
[5]: https://maggieappleton.com/apps
|
||||
|
||||
This month:
|
||||
|
||||
* Adventure: dust off the road bike, fill the tires, grease the chain, throw it on the rack, and get out for a long ride
|
||||
* Project: publish an article on [testing][14] on my company's website
|
||||
* Skill: learn [Helix][13] movements, see if it'd be a good Vim replacement (I still love Vim, and I'm pretty good at it, but my config's dated and I'm wary of how much effort it'll take to modernize)
|
||||
|
||||
[13]: https://helix-editor.com/
|
||||
[14]: /notes/good-tests
|
||||
|
||||
Reading:
|
||||
|
||||
* Fiction: [_The Golden Enclaves_][6], Naomi Novik
|
||||
* Non-fiction:
|
||||
* [_Rapt_][7], Winifred Gallagher
|
||||
* [_Visual Thinking_][8], Williemien Brand
|
||||
* [_The Manual: A Philosopher's Guide to Life_][9], Epictetus
|
||||
|
||||
[7]: https://bookshop.org/p/books/rapt-attention-and-the-focused-life-winifred-gallagher/7485226?ean=9780143116905
|
||||
[6]: https://bookshop.org/p/books/the-golden-enclaves-naomi-novik/17789027?ean=9780593158357
|
||||
[8]: https://bookshop.org/p/books/visual-thinking-empowering-people-and-organisations-through-visual-collaboration-williemien-brand/12408256?ean=9789063694531
|
||||
[9]: https://bookshop.org/p/books/the-manual-a-philosopher-s-guide-to-life-epictetus/15150488?ean=9781545461112
|
||||
|
||||
Links:
|
||||
|
||||
* [Modern software quality, or why I think using language models for programming is a bad idea][10] -- I refer people to this article a lot in discussions around <abbr title="large language models">LLMs</abbr> and software development
|
||||
* [The small web is beautiful][11]
|
||||
* [Why You Own an iPad and Still Can't Draw][12]
|
||||
|
||||
[10]: https://softwarecrisis.dev/letters/ai-and-software-quality/
|
||||
[11]: https://benhoyt.com/writings/the-small-web-is-beautiful/
|
||||
[12]: https://maggieappleton.com/still-cant-draw
|
||||
|
||||
[^1]: Tiago Forte's _Building a Second Brain_ outlines a four-step process: Capture, Organize, Distill, Express.
|
||||
@@ -15,6 +15,10 @@ references:
|
||||
url: https://cerebralab.com/Imaginary_Problems_Are_the_Root_of_Bad_Software
|
||||
date: 2023-06-20T16:28:39Z
|
||||
file: cerebralab-com-qy5zqs.txt
|
||||
- title: "When to Build Millennia Sewers"
|
||||
url: https://taylor.town/millennium-sewer
|
||||
date: 2023-07-03T00:32:43Z
|
||||
file: taylor-town-5siv9a.txt
|
||||
---
|
||||
|
||||
### Thoughts on priorities in software development
|
||||
@@ -28,7 +32,9 @@ references:
|
||||
* [The Grug Brained Developer][1]
|
||||
* [Even Amazon can't make sense of serverless or microservices][2]
|
||||
* [Imaginary Problems Are the Root of Bad Software][3]
|
||||
* [When to Build Millennia Sewers][4]
|
||||
|
||||
[1]: https://grugbrain.dev/
|
||||
[2]: https://world.hey.com/dhh/even-amazon-can-t-make-sense-of-serverless-or-microservices-59625580
|
||||
[3]: https://cerebralab.com/Imaginary_Problems_Are_the_Root_of_Bad_Software
|
||||
[4]: https://taylor.town/millennium-sewer
|
||||
|
||||
@@ -47,6 +47,7 @@ I find [Go][1] really compelling, even though it's not super applicable to my jo
|
||||
* [SyncThing][5]
|
||||
* [Restic][6]
|
||||
* [Gotenberg][7]
|
||||
* [Shiori][8]
|
||||
|
||||
[2]: https://gohugo.io/
|
||||
[3]: https://caddyserver.com/
|
||||
@@ -54,29 +55,30 @@ I find [Go][1] really compelling, even though it's not super applicable to my jo
|
||||
[5]: https://syncthing.net/
|
||||
[6]: https://restic.net/
|
||||
[7]: https://gotenberg.dev/
|
||||
[8]: https://github.com/go-shiori/shiori
|
||||
|
||||
### Project Ideas
|
||||
|
||||
* Bookmarking app (Pinboard replacement)
|
||||
* Note-taking / journaling app
|
||||
* [StevieBlocks][8]
|
||||
* [StevieBlocks][9]
|
||||
|
||||
{{<thumbnail project1 "400x" />}}
|
||||
|
||||
[8]: https://gist.github.com/dce/f975cb21b50a2cf998bf7230cbf89d85
|
||||
[9]: https://gist.github.com/dce/f975cb21b50a2cf998bf7230cbf89d85
|
||||
|
||||
### Resources
|
||||
|
||||
* [Standard Go Project Layout][9]
|
||||
* [The files & folders of Go projects][10]
|
||||
* [Why David Yach Loves Go][11]
|
||||
* [One process programming notes (with Go and SQLite)][12]
|
||||
* [Go Project Layout][13]
|
||||
* [Gopher Wrangling. Effective error handling in Go][14]
|
||||
* [Standard Go Project Layout][10]
|
||||
* [The files & folders of Go projects][11]
|
||||
* [Why David Yach Loves Go][12]
|
||||
* [One process programming notes (with Go and SQLite)][13]
|
||||
* [Go Project Layout][14]
|
||||
* [Gopher Wrangling. Effective error handling in Go][15]
|
||||
|
||||
[9]: https://github.com/golang-standards/project-layout
|
||||
[10]: https://changelog.com/gotime/278
|
||||
[11]: https://cloud.google.com/blog/products/application-modernization/why-david-yach-loves-go
|
||||
[12]: https://crawshaw.io/blog/one-process-programming-notes
|
||||
[13]: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2
|
||||
[14]: https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/
|
||||
[10]: https://github.com/golang-standards/project-layout
|
||||
[11]: https://changelog.com/gotime/278
|
||||
[12]: https://cloud.google.com/blog/products/application-modernization/why-david-yach-loves-go
|
||||
[13]: https://crawshaw.io/blog/one-process-programming-notes
|
||||
[14]: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2
|
||||
[15]: https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
title: "Good Tests"
|
||||
date: 2023-05-12T23:40:19-04:00
|
||||
draft: false
|
||||
references:
|
||||
- title: "A year of Rails - macwright.com"
|
||||
url: https://macwright.com/2021/02/18/a-year-of-rails.html
|
||||
date: 2023-07-03T02:52:03Z
|
||||
file: macwright-com-o4dndf.txt
|
||||
---
|
||||
|
||||
_(Notes for a Viget article I'm putting together)_
|
||||
|
||||
728
static/archive/benhoyt-com-vfdv1s.txt
Normal file
728
static/archive/benhoyt-com-vfdv1s.txt
Normal file
@@ -0,0 +1,728 @@
|
||||
[1]Ben Hoyt
|
||||
* [2]Home
|
||||
* [3]Resume/CV
|
||||
* [4]Projects
|
||||
* [5]Tech Writing
|
||||
* [6]Non-Tech
|
||||
* [7]Email
|
||||
|
||||
* [8]benhoyt.com
|
||||
* [9]benhoyt@gmail.com
|
||||
|
||||
The small web is beautiful
|
||||
|
||||
March 2021
|
||||
|
||||
Summary: I believe that small websites are compelling aesthetically,
|
||||
but are also important to help us resist selling our souls to large
|
||||
tech companies. In this essay I present a vision for the “small web”
|
||||
as well as the small software and architectures that power it. Also,
|
||||
a bonus rant about microservices.
|
||||
|
||||
Go to: [10]Software | [11]Web | [12]Server-side | [13]Static sites |
|
||||
[14]Dependencies | [15]Analytics | [16]Microservices
|
||||
|
||||
About fifteen years ago, I read E. F. Schumacher’s Small is Beautiful
|
||||
and, despite not being interested in economics, I was moved by its
|
||||
message. Perhaps even more, I loved the terse poetry of the book’s
|
||||
title – it resonated with my frugal upbringing and my own aesthetic.
|
||||
|
||||
I think it’s time for a version of that book about technology, with a
|
||||
chapter on web development: The Small Web is Beautiful: A Study of Web
|
||||
Development as if People Mattered. Until someone writes that, this
|
||||
essay will have to do.
|
||||
|
||||
There are two aspects of this: first, small teams and companies. I’m
|
||||
not going to talk much about that here, but [17]Basecamp and many
|
||||
others have. What I’m going to focus on in this essay is small websites
|
||||
and architectures.
|
||||
|
||||
I’m not the first to talk about the “small web”, but, somewhat
|
||||
surprisingly, only a few people have discussed it using that term. Here
|
||||
are the main web pages I can find that do:
|
||||
* [18]Rediscovering the Small Web by Parimal Satyal: a fabulous
|
||||
article about the joy of small, independent (and sometimes retro)
|
||||
websites in contrast to the “commercial web”.
|
||||
* [19]What is the Small Web?, by Aral Balkan of the Small Technology
|
||||
Foundation: more of a manifesto against the surveillance of Big
|
||||
Tech than something concrete, but still interesting.
|
||||
|
||||
Why aim small in this era of fast computers with plenty of RAM? A
|
||||
number of reasons, but the ones that are most important to me are:
|
||||
* Fewer moving parts. It’s easier to create more robust systems and
|
||||
to fix things when they do go wrong.
|
||||
* Small software is faster. Fewer bits to download and clog your
|
||||
computer’s memory.
|
||||
* Reduced power consumption. This is important on a “save the planet”
|
||||
scale, but also on the very local scale of increasing the battery
|
||||
life of your phone and laptop.
|
||||
* The light, frugal aesthetic. That’s personal, I know, but as you’ll
|
||||
see, I’m not alone.
|
||||
|
||||
So let’s dive in. I want to cover a bunch of different angles, each
|
||||
with its own subheading.
|
||||
|
||||
Small software
|
||||
|
||||
If we’re going to talk about a small web, we need to start with small
|
||||
software.
|
||||
|
||||
As a teen, I learned to program using x86 assembly and [20]Forth –
|
||||
perhaps odd choices, but my dad was heavily into Forth, and I loved how
|
||||
the language was so simple I could write [21]my own bootstrapped
|
||||
compiler.
|
||||
|
||||
In terms of career, I started as an embedded programmer – not as in
|
||||
“embedded Linux” but as in microcontrollers where 16KB of RAM was
|
||||
generous. My current laptop has 16GB of RAM, and that’s not a lot by
|
||||
today’s standards. We were building IP-networked products with one
|
||||
millionth the amount of RAM. Those kinds of micros are as cheap as
|
||||
chips (ahem), and still widely used for small electronic devices,
|
||||
sensors, internet-of-things products, and so on.
|
||||
|
||||
You have to think about every byte, compile with size optimizations
|
||||
enabled, and reuse buffers. It’s a very different thing from modern web
|
||||
development, where a JavaScript app compiles “down” to a 1MB bundle, or
|
||||
a single Python object header is 16 bytes before you’ve even got any
|
||||
data, or a Go hello-world binary is 2MB even before you’ve added any
|
||||
real code.
|
||||
|
||||
How do you create small programs? I think the main thing is that you
|
||||
have to care about size, and most of us don’t think we have time for
|
||||
that. Apart from embedded development, there’s an entire programming
|
||||
subculture called the [22]demoscene that cares about this. They have
|
||||
competitions for the smallest 4KB demos: who can pack the most
|
||||
graphical punch into 4096 bytes of executable. That’s smaller than many
|
||||
favicons! ([23]Elevated and [24]cdak are two of the highest-rated 4K
|
||||
demos.) Many demosceners go on to become game developers.
|
||||
|
||||
It’s not just about executable size … when you’re developing your next
|
||||
command line tool, if you use Go or Rust or even C, your program will
|
||||
be much faster, smaller, and use less memory than a Python or Java
|
||||
equivalent. And easier to install. If you don’t understand why, please
|
||||
do learn. (It’s out of scope for this essay, but to summarize: Go,
|
||||
Rust, and C compile to ready-to-execute machine code, don’t carry
|
||||
around a virtual machine, and don’t have memory overhead for objects
|
||||
like integers.)
|
||||
|
||||
But why not apply some of the same principles to web development? In
|
||||
the web world, I think the main trick is to be careful what
|
||||
dependencies you include, and also what dependencies they pull in. In
|
||||
short, know node_modules – or maybe better, no node_modules. More about
|
||||
this [25]below.
|
||||
|
||||
Niklaus Wirth of Pascal fame wrote a famous paper in 1995 called [26]A
|
||||
Plea for Lean Software [PDF]. His take is that “a primary cause for the
|
||||
complexity is that software vendors uncritically adopt almost any
|
||||
feature that users want”, and “when a system’s power is measured by the
|
||||
number of its features, quantity becomes more important than quality”.
|
||||
He goes on to describe Oberon, a computer language (which reminds me of
|
||||
Go in several ways) and an operating system that he believes helps
|
||||
solve the complexity problem. Definitely wirth a read!
|
||||
|
||||
I’ve been mulling over this for a number of years – back in 2008 I
|
||||
wrote a sarcastic dig at how bloated Adobe Reader had become: [27]Thank
|
||||
you, Adobe Reader 9! It was a 33MB download and required 220MB of hard
|
||||
drive space even in 2008 (it’s now a 150MB download, and I don’t know
|
||||
how much hard drive space it requires, because I don’t install it these
|
||||
days).
|
||||
|
||||
But instead of just complaining, how do we actually solve this problem?
|
||||
Concretely, I think we need to start doing the following:
|
||||
* Care about size: this sounds obvious, but things only change when
|
||||
people think they’re important.
|
||||
* Measure: both your executable’s size, and your program’s memory
|
||||
usage. You may want to measure over time, and make it a blocking
|
||||
issue if the measurements grow more than x% in a release. Or you
|
||||
could hold a memory-reduction sprint every so often.
|
||||
* Language: choose a backend language that has a chance, for example
|
||||
Rust, C or C++, or for servers, Go. These languages aren’t right
|
||||
for everything (like data transformation scripts), but they produce
|
||||
small executables, and they’re good for CLIs and desktop apps.
|
||||
* Remove: cut down your feature set. Aim for a small number of
|
||||
high-quality features. My car can’t fly or float, and that’s okay –
|
||||
it drives well.
|
||||
* Say no to new features: unless they really fit your philosophy, or
|
||||
add more than they cost over the lifetime of your project.
|
||||
* Dependencies: understand the size and complexity of each dependency
|
||||
you pull in. Use only built-in libraries if you can.
|
||||
|
||||
Small websites
|
||||
|
||||
I’m glad there’s a growing number of people interested in small
|
||||
websites.
|
||||
|
||||
A few months ago there was a sequence of posts to Hacker News about
|
||||
various “clubs” you could post your small website on: the [28]1MB Club
|
||||
([29]comments), [30]512KB Club ([31]comments), [32]250KB Club
|
||||
([33]comments), and even the [34]10KB Club ([35]comments). I think
|
||||
those are a fun indicator of renewed interested in minimalism, but I
|
||||
will say that raw size isn’t enough – a 2KB site with no real content
|
||||
isn’t much good, and a page with 512KB of very slow JavaScript is worse
|
||||
than a snappy site with 4MB of well-chosen images.
|
||||
|
||||
Some of my favourite small websites are:
|
||||
|
||||
[36]Hacker News: I personally like the minimalist, almost brutalist
|
||||
design, but I love its lightness even more. I just downloaded the home
|
||||
page, and loading all resources transfers only 21KB (61KB
|
||||
uncompressed). Even pages with huge comment threads only transfer about
|
||||
100KB of compressed data, and load quickly. Reddit has become such a
|
||||
bloated mess in comparison. Hacker News, never change!
|
||||
|
||||
[37]Lobsters: a similar news-and-voting site, with slightly more
|
||||
“modern” styling. It uses some JavaScript and profile icons, but it’s
|
||||
still clean and fast, and the total transfer size for the homepage is
|
||||
only 102KB. You just don’t need megabytes to make a good website.
|
||||
|
||||
[38]Sourcehut: I like the concept behind Drew DeVault’s business, but I
|
||||
love how small and anti-fluff the website is. He has set up a mini-site
|
||||
called the [39]Software Forge Performance Index that tracks size and
|
||||
browser performance of the prominent source code websites – Sourcehut
|
||||
is far and away the lightest and fastest. Even his homepage is only
|
||||
81KB, including several screenshot thumbnails.
|
||||
|
||||
[40]SQLite: not only is SQLite a small, powerful SQL database engine,
|
||||
the website is fantastically small and content-rich. Even their
|
||||
7000-word [41]page about testing is only 70KB. How do they do this?
|
||||
It’s not magic: focus on high-quality textual content, minimal CSS, no
|
||||
JavaScript, and very few images (a small logo and some SVGs).
|
||||
|
||||
[42]LWN: I’m a little biased, because I’ve written [43]articles for
|
||||
them, but they’re an excellent website for Linux and programming news.
|
||||
Extremely high-quality technical content (and a high bar for authors).
|
||||
They’re definitely niche, and have a “we focus on quality content, not
|
||||
updating our CSS every year” kind of look – they’ve been putting out
|
||||
great content for 23 years! Their homepage only downloads 44KB (90KB
|
||||
uncompressed).
|
||||
|
||||
[44]Dan Luu’s blog: this is one of the more hardcore examples. His
|
||||
inline CSS is only about 200 bytes (the pages are basically unstyled),
|
||||
and his HTML source code doesn’t use any linefeed characters. Kind of a
|
||||
fun point, although then he goes on to load 20KB of Google Analytics
|
||||
JavaScript…
|
||||
|
||||
As a friend pointed out, those websites have something of an
|
||||
“anti-aesthetic aesthetic”. I confess to not minding that at all, but
|
||||
on the other hand, small doesn’t have to mean ugly. More and more
|
||||
personal blogs and websites have adopted a small web approach but are
|
||||
more typographically appealing:
|
||||
* [45]Armin Ronacher’s Thoughts and Writings
|
||||
* [46]Chris Wellons’ “Null program” blog
|
||||
* [47]Eric Radman’s BSD and SQL blog
|
||||
* [48]Hugo Tunius’ programming blog
|
||||
* [49]James Hague’s “Programming in the Twenty-First Century”
|
||||
* [50]Julia Evans’ programming blog
|
||||
|
||||
There are many, many more. Programmer Sijmen Mulder created a nice list
|
||||
of [51]text-only websites – not quite the same thing as small, but it
|
||||
definitely overlaps!
|
||||
|
||||
However, it’s not just about raw size, but about an “ethos of small”.
|
||||
It’s caring about the users of your site: that your pages download
|
||||
fast, are easy to read, have interesting content, and don’t load scads
|
||||
of JavaScript for Google or Facebook’s trackers. Building a website
|
||||
from scratch is not everyone’s cup of tea, but for those of us who do
|
||||
it, maybe we can promote templates and tools that produce small sites
|
||||
that encourage quality over quantity.
|
||||
|
||||
For this website, I lovingly crafted each byte of HTML and CSS by hand,
|
||||
like a hipster creating a craft beer. Seriously though, if your focus
|
||||
is good content, it’s not hard to create a simple template from scratch
|
||||
with just a few lines of HTML and CSS. It will be small and fast, and
|
||||
it’ll be yours.
|
||||
|
||||
Loading this essay transfers about 23KB (56KB uncompressed), including
|
||||
the favicon and analytics script. It’s small, fast, and readable on
|
||||
desktop or mobile. I don’t think it’s too bad looking, but I’m
|
||||
primarily aiming for a minimalist design focussed on the content.
|
||||
|
||||
In addition to making sure your HTML and CSS are small, be sure to
|
||||
compress your images properly. Two basic things here: don’t upload
|
||||
ultra-high resolution images straight from your camera, and use a
|
||||
reasonable amount of JPEG compression for photos (and PNG for
|
||||
screenshots or vector art). Even for large images, you can usually use
|
||||
75% or 80% compression and still have an image without JPEG noise. For
|
||||
example, the large 1920x775 image on the top of my [52]side business’s
|
||||
homepage is only 300KB.
|
||||
|
||||
Speaking of hero images, you don’t need big irrelevant images at the
|
||||
top of your blog posts. They just add hundreds of kilobytes (even
|
||||
megabytes) to your page weight, and don’t provide value. And please
|
||||
don’t scatter your article with animated GIFs: if there’s something
|
||||
animated on the screen, I can hardly concentrate enough to read the
|
||||
text – and I’m [53]not the [54]only one. Include relevant, non-stock
|
||||
images that provide value equal to their weight in bytes. Bare text is
|
||||
okay, too, like a magazine article.
|
||||
|
||||
[55]IndieWeb.org is a great resource here, though they use the term
|
||||
“indie” rather than “small”. This movement looks more organic than the
|
||||
[56]Small Technology Foundation (which has even been [57]critiqued as
|
||||
“digital green-washing”), and their wiki has a lot more real content.
|
||||
IndieWeb also promotes local [58]Homebrew Website Clubs and
|
||||
[59]IndieWebCamp meetups.
|
||||
|
||||
Emphasize server-side, not JavaScript
|
||||
|
||||
JavaScript is a mixed blessing for the web, and more often than not a
|
||||
bane for small websites: it adds to the download size and time, it can
|
||||
be a performance killer, it’s bad for accessibility, and if you don’t
|
||||
hold it right, it’s [60]bad for search engines. Plus, if your website
|
||||
is content-heavy, it probably isn’t adding much.
|
||||
|
||||
Don’t get me wrong: JavaScript is sometimes unavoidable, and is great
|
||||
where it’s great. If you’re developing a browser-based application like
|
||||
Gmail or Google Maps, you should almost certainly be using JavaScript.
|
||||
But for your next blog, brochure website, or project documentation
|
||||
site, please consider plain HTML and CSS.
|
||||
|
||||
If your site – like a lot of sites – is somewhere in between and
|
||||
contains some light interaction, consider using JavaScript only for the
|
||||
parts of the page that need it. There’s no need to overhaul your whole
|
||||
site using React and Redux just to add a form. Letting your server
|
||||
generate HTML is still an effective way to create fast websites.
|
||||
|
||||
[61]Stack Overflow is a case in point. From day one, they’ve made
|
||||
[62]performance a feature by rendering their pages on the server, and
|
||||
by measuring and reducing render time. I’m sure the Stack Overflow code
|
||||
has changed quite a lot since the Jeff Atwood days – it now makes a ton
|
||||
of extra requests for advertising purposes – but the content still
|
||||
loads fast.
|
||||
|
||||
[63]Hacker News (there’s that site again) is a server-side classic.
|
||||
With only [64]one tiny JavaScript file for voting, the HTML generated
|
||||
on the server does the rest. And [65]apparently it still runs on a
|
||||
single machine.
|
||||
|
||||
Around fifteen years ago there was this great idea called
|
||||
[66]progressive enhancement. The idea was to serve usable HTML content
|
||||
to everyone, but users with JavaScript enabled or fast internet
|
||||
connections would get an enhanced version with a more streamlined user
|
||||
interface. In fact, Hacker News itself uses progressive enhancement:
|
||||
even in 2021, you can still turn off JavaScript and use the voting
|
||||
buttons. It’s a bit clunkier because voting now requires a page reload,
|
||||
but it works fine.
|
||||
|
||||
Is progressive enhancement still relevant in 2021? Arguably not, though
|
||||
some die-hards still turn JavaScript off, or at least enable it only
|
||||
for sites they trust. However, I think it’s the mentality that’s most
|
||||
important: it shows the developer cares about performance, size, and
|
||||
alternative users. If Hacker News voting didn’t work without
|
||||
JavaScript, I don’t think that would be a big problem – but it shows a
|
||||
certain kind of nerdish care that it does work. Plus, the JavaScript
|
||||
they do have is only 2KB (5KB uncompressed).
|
||||
|
||||
Compare that to the 8MB (14MB uncompressed) that the [67]Reddit
|
||||
homepage loads. And this across 201 requests – I kid you not! – most of
|
||||
which is JavaScript to power all the ads and tracking. Lovely…
|
||||
|
||||
You don’t need a “framework” to develop this way, of course, but there
|
||||
are some tools that make this style of server-side development easier.
|
||||
[68]Turbolinks from the Basecamp folks was an early one, and it’s now
|
||||
been superseded by [69]Turbo, which is apparently used to power their
|
||||
email service [70]Hey. I haven’t used these personally, but the ideas
|
||||
are clever (and surprisingly old-skool): use standard links and form
|
||||
submissions, [71]serve plain HTML, but speed it up with WebSockets and
|
||||
JavaScript if available. Just today, in fact, someone posted a new
|
||||
article on Hacker News which claims [72]“The Future of Web Software Is
|
||||
HTML-over-WebSockets”. If Hey is anything to go by, this technique is
|
||||
fast!
|
||||
|
||||
On the other hand, sometimes you can reduce overall complexity by using
|
||||
JavaScript for the whole page if you’re going to need it anyway. For
|
||||
example, the registry pages on my wedding registry website are rendered
|
||||
on the client (they actually [73]use Elm, which compiles to
|
||||
JavaScript). I do need the interactivity of JavaScript (it’s more
|
||||
“single page application” than mere content), but I don’t need
|
||||
server-side rendering or good SEO for these pages. The homepage is a
|
||||
simple server-rendered template, but the registry pages are fully
|
||||
client-rendered.
|
||||
|
||||
Static sites and site generators
|
||||
|
||||
Another thing there’s been renewed interest in recently is static
|
||||
websites (these used to be called just “websites”). You upload some
|
||||
static HTML (and CSS and JavaScript) to a static file server, and
|
||||
that’s it.
|
||||
|
||||
Improving on that, there are many “static site generators” available.
|
||||
These are tools that generate a static site from simple templates, so
|
||||
that you don’t have to copy your site’s header and footer into every
|
||||
HTML file by hand. When you add an article or make a change, run the
|
||||
script to re-generate. If you’re hosting a simple site or blog or even
|
||||
a news site, this is a great way to go. It’s content, after all, not an
|
||||
interactive application.
|
||||
|
||||
I use [74]GitHub Pages on this site just because it’s a free host that
|
||||
supports SSL, and automatically builds your site using the [75]Jekyll
|
||||
static site generator whenever you push a change. I have a standard
|
||||
header and include the same CSS across all pages easily, though you can
|
||||
have multiple templates or “layouts” if you want. Because most people
|
||||
only view one or two articles on my site, I include my CSS inline. With
|
||||
HTTP/2, this doesn’t make much difference, but Lighthouse showed around
|
||||
200ms with inline CSS, 300ms with external CSS.
|
||||
|
||||
Here’s an example of what a simple Jekyll page looks like (the start of
|
||||
this essay, in fact):
|
||||
---
|
||||
layout: default
|
||||
title: "The small web is beautiful"
|
||||
permalink: /writings/the-small-web-is-beautiful/
|
||||
description: A vision for the "small web", small software, and ...
|
||||
---
|
||||
Markdown text here.
|
||||
|
||||
I’ve also used [76]Hugo, which is a really fast static site generator
|
||||
written in Go – it generates even large sites with thousands of pages
|
||||
in a few seconds. And there are [77]many other options available.
|
||||
|
||||
Fewer dependencies
|
||||
|
||||
There’s nothing that blows up the size of your software (or JavaScript
|
||||
bundle) like third party dependencies. I always find a web project’s
|
||||
node_modules directory hard to look at – just the sheer volume of stuff
|
||||
in there makes me sad.
|
||||
|
||||
Different languages seem to have different “dependency cultures”.
|
||||
JavaScript, of course, is notorious for an “if it can be a library, it
|
||||
should be” attitude, resulting in the [78]left-pad disaster as well as
|
||||
other minuscule libraries like the 3-line [79]isarray. There are also
|
||||
big, heavy packages like [80]Moment.js, which takes [81]160KB even when
|
||||
minified. There are ways to shrink it down if you don’t need all
|
||||
locales, but it’s not the default, so most people don’t (you’re
|
||||
probably better off choosing a more modular approach like
|
||||
[82]date-fns).
|
||||
|
||||
Go now has good dependency management with the recent [83]modules
|
||||
tooling, but it also has a culture of “use the standard library if you
|
||||
can”. Russ Cox wrote an excellent essay about the downsides of not
|
||||
being careful with your dependencies: [84]Our Software Dependency
|
||||
Problem. Go co-creator Rob Pike even made this one of his [85]Go
|
||||
proverbs: “A little copying is better than a little dependency.” You
|
||||
can probably guess by now, but I like this minimalist approach: apart
|
||||
from reducing the number of points of failure, it makes programs
|
||||
smaller.
|
||||
|
||||
Python, Ruby, Java, and C# seem to be somewhere in between: people use
|
||||
a fair number of dependencies, but from what I’ve seen there’s more
|
||||
care taken and it doesn’t get as out of hand as node_modules.
|
||||
Admittedly it is a little unfair, as Python (and those other languages)
|
||||
have standard libraries that have more in them than JavaScript’s.
|
||||
|
||||
The website [86]YouMightNotNeedjQuery.com shows how many of the tasks
|
||||
you think you might need a library for are actually quite simple to do
|
||||
with plain JavaScript. For example, in one of my projects I use a
|
||||
function like the following to make an API request with plain old
|
||||
XMLHttpRequest:
|
||||
function postJson(url, data, callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === xhr.DONE) {
|
||||
callback(xhr.status, JSON.parse(xhr.responseText));
|
||||
}
|
||||
};
|
||||
xhr.open("POST", url, true);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
The moral of the story: think twice before adding dependencies. You’ll
|
||||
keep your websites and programs smaller and more reliable, and you’ll
|
||||
thank Russ Cox later.
|
||||
|
||||
Small analytics
|
||||
|
||||
Most website owners want some form of analytics to see how many
|
||||
visitors are coming to their site, and from where. The go-to tool is
|
||||
Google Analytics: it’s easy to set up and the UI is pretty
|
||||
comprehensive. But there’s a cost: it adds a significant amount of
|
||||
weight to your page (19KB of JavaScript, 46KB uncompressed), and it
|
||||
sends a lot of user data for Google to collect.
|
||||
|
||||
Once again, there’s been renewed interest in smaller, more
|
||||
privacy-friendly analytics systems in recent times. Just this morning I
|
||||
read a provocative article that was highly-voted on Hacker News called
|
||||
[87]“Google Analytics: Stop feeding the beast”.
|
||||
|
||||
Last year I wrote two articles for LWN on the subject, so I won’t say
|
||||
too much more here:
|
||||
* [88]Lightweight alternatives to Google Analytics: replacing it with
|
||||
lightweight open source and privacy-conscious alternatives,
|
||||
specifically [89]GoatCounter and [90]Plausible.
|
||||
* [91]More alternatives to Google Analytics: some heavier
|
||||
alternatives, and a brief look at log-based analytics tools.
|
||||
|
||||
For this website I use GoatCounter, which is available as a low-cost
|
||||
hosted service (free for non-commercial use) or as a self-hosted tool.
|
||||
I really like what Martin is doing here, and how small and simple the
|
||||
tool is: no bells and whistles, just the basic traffic numbers that
|
||||
most people want.
|
||||
|
||||
Small architectures (not microservices)
|
||||
|
||||
Small websites are great for users, but small architectures are great
|
||||
for developers. A small, simple codebase is easy to maintain, and will
|
||||
have fewer bugs than a large, sprawling system with lots of interaction
|
||||
points.
|
||||
|
||||
I contend that the “microservices everywhere” buzz is a big problem.
|
||||
Microservices may be used successfully at Google and Amazon, but most
|
||||
companies don’t need to build that way. They introduce complexity in
|
||||
the code, API definitions, networking, deployment, server
|
||||
infrastructure, monitoring, database transactions – just about every
|
||||
aspect of a system is made more complex. Why is that?
|
||||
* Code: you have lots of little repositories, possibly in different
|
||||
languages, and each has to have some way to talk to the other
|
||||
services (JSON over HTTP, gRPC, etc). With a monolithic system,
|
||||
it’s all in one language (much better for a small team), calling
|
||||
other modules is just a function call, and system-wide refactoring
|
||||
is comparatively easy (especially in a statically typed language
|
||||
like Go or Java).
|
||||
* API definitions: with many services talking to each other, suddenly
|
||||
you need standardized interfaces for how they communicate. You
|
||||
spend a lot of time setting up gRPC or JSON schema definitions. In
|
||||
a single codebase, a function signature is the API definition.
|
||||
* Networking: with microservices, a function call is a network call,
|
||||
and you spend time setting up your network infrastructure, thinking
|
||||
about timeouts and retries, and maybe even designing inter-service
|
||||
authentication. In monolithic systems, you only worry about
|
||||
networking when talking to your database, cloud provider, and
|
||||
users.
|
||||
* Deployment: at a previous company I worked at, once we started
|
||||
building with microservices, suddenly we needed fancy deployment
|
||||
tooling and a dedicated infrastructure team to manage it all. You
|
||||
can get by with a lot less if you’re only deploying a few services.
|
||||
* Server infrastructure: you’ll probably need to set up new
|
||||
infrastructure – lots of small virtual machines, or a
|
||||
Kubernetes-based system. Kubernetes in itself is a complex
|
||||
distributed application (even [92]Google admits it’s too complex),
|
||||
and it takes a lot of work – or a lot of money – to run properly.
|
||||
* Monitoring: to debug issues, you’ll need costly
|
||||
distributed-monitoring software like Datadog to see what’s going
|
||||
on. When an outage occurs, you’ll scramble to determine which
|
||||
service is responsible, which team to page, and so on. Compare that
|
||||
with a simple stack trace or single-service issue.
|
||||
* Database transactions: these are difficult to impossible in a
|
||||
microservices architecture. You may be able to design your way out
|
||||
of them, but that’s not easy either. With a monolith, just type
|
||||
BEGIN ... COMMIT, or however your database library spells it.
|
||||
|
||||
It’s been said before, but microservices solve a people problem, not a
|
||||
technical one. But beware of [93]Conway’s Law: your architecture will
|
||||
mimic your company structure. Or the reverse – you’ll have to hire and
|
||||
reorg so that your company structure matches the architecture that
|
||||
microservices require: lots of engineers on lots of small teams, with
|
||||
each team managing a couple of microservices.
|
||||
|
||||
That doesn’t mean microservices are always the wrong choice: they may
|
||||
be necessary in huge engineering organizations. However, if you’re
|
||||
working at such a company, you’ve probably already been using
|
||||
microservices for years. If you’re not “Google size”, you should think
|
||||
twice before copying their development practices.
|
||||
|
||||
What’s the alternative? The term “monolith” has a bad rap, but I agree
|
||||
with David at Basecamp that [94]monoliths can be majestic. Basecamp is
|
||||
a large, monolithic application, and they run it with just a dozen
|
||||
programmers. David is quick to point out that “the Majestic Monolith
|
||||
doesn’t pretend to provide a failsafe architectural road to glory”. You
|
||||
still have to think, design, and write good code.
|
||||
|
||||
Thankfully, people are bouncing back from the cargo culting. Just do a
|
||||
search for [95]“why not microservices” and you’ll find lots of good
|
||||
articles on the subject. One of the recent ones I’ve read is from
|
||||
Tailscale: [96]Modules, monoliths, and microservices.
|
||||
|
||||
So what’s my advice?
|
||||
* Unless your company name is Google or Amazon, start with a
|
||||
monolith.
|
||||
* Once it starts having problems, optimize or refactor the pain
|
||||
points.
|
||||
* If it’s still having issues, buy a bigger server.
|
||||
* If you have a specific technical reason to split it up, fix that
|
||||
problem.
|
||||
* If there are still problems, split off only the component that
|
||||
needs splitting off. You’ll have two services to deploy and
|
||||
monitor, but that’s far simpler than going all-in on microservices.
|
||||
|
||||
Okay, so this became more of an anti-microservices rant than I was
|
||||
planning, but so be it.
|
||||
|
||||
In terms of counter-examples, Stack Overflow once again comes to mind.
|
||||
They’re one of the web’s busiest sites, but they have a relatively
|
||||
simple, two-tier [97]architecture that they’ve scaled vertically – in
|
||||
other words, big servers with lots of RAM, rather than hundreds of
|
||||
small servers. They have 9 web servers and 4 very chunky SQL servers,
|
||||
with a few additional servers for their tag engine, Redis,
|
||||
Elasticsearch, and HAProxy. This architecture helps them get great
|
||||
performance and the ability to develop with a small team.
|
||||
|
||||
My own side business, [98]GiftyWeddings.com, only gets a small amount
|
||||
of traffic, so it’s nothing like Stack Overflow, but it uses a Go HTTP
|
||||
server with SQLite on one of the smallest EC2 instances available,
|
||||
[99]t2.micro. It costs about $8 per month, and I only have one tiny
|
||||
piece of infrastructure to maintain. I deploy using [100]Ansible – a
|
||||
tool that is another good example of simple architecture and boils down
|
||||
to “just use ssh”.
|
||||
|
||||
Speaking of SQLite, there’s a growing number of developers who advocate
|
||||
using SQLite to run their websites. SQLite’s [101]“when to use SQLite”
|
||||
page says “any site that gets fewer than 100K hits/day should work fine
|
||||
with SQLite. The 100K hits/day figure is a conservative estimate, not a
|
||||
hard upper bound. SQLite has been demonstrated to work with 10 times
|
||||
that amount of traffic.” Here are some other SQLite success stories:
|
||||
* [102]Litestream is an open source tool that provides streaming
|
||||
replication for SQLite. Read author Ben Johnson’s article, [103]Why
|
||||
I Built Litestream.
|
||||
* Go developer David Crawshaw has an article about what he calls
|
||||
[104]“one process programming” (with Go and SQLite), that can be
|
||||
summed up with his phrase “don’t use N computers when 1 will do”.
|
||||
He also created a [105]Go SQLite library that supports more
|
||||
SQLite-specific features than the other drivers.
|
||||
* Peewee ORM author Charles Leifer wrote an article [106]“Five
|
||||
reasons you should use SQLite in 2016” that’s still very relevant
|
||||
in 2021. It ends with “I hope you’ll give SQLite a try. Don’t
|
||||
believe the FUD about it not being production-worthy, or not being
|
||||
suitable for use in web-applications.”
|
||||
* Sam Eaton of [107]Crave Cookie runs a $200,000 per month side
|
||||
business (wow!) using a single server and SQLite. Read his
|
||||
[108]Indie Hackers interview.
|
||||
|
||||
Summing up
|
||||
|
||||
Companies will do what companies do, and continue to make
|
||||
flashy-looking, bloated websites that “convert” well. Maybe you can
|
||||
have an influence at work, and come home to your better half and say
|
||||
“honey, I shrunk the web”. Or maybe you’ll just focus on the small web
|
||||
for your personal projects. (Disclaimer: I mostly do the latter – as
|
||||
part of my day job, I work on [109]Juju, which is not a small system by
|
||||
most measures.)
|
||||
|
||||
Either way, I believe the “small web” is a compelling term and a
|
||||
compelling aesthetic. Not necessarily in the visual sense, but in the
|
||||
sense that you built it yourself, you understand all of it, and you run
|
||||
it on a single server or static file host.
|
||||
|
||||
There are thousands of excellent examples of small websites, and
|
||||
hundreds of ways to create simple architectures – this essay touches on
|
||||
only a few of the ones I’m passionate about. I’d love to hear your own
|
||||
ideas and stories! Comment over at [110]Lobsters or [111]Hacker News or
|
||||
[112]programming Reddit.
|
||||
|
||||
I’d love it if you [113]sponsored me on GitHub – it will motivate me to
|
||||
work on my open source projects and write more good content. Thanks!
|
||||
|
||||
References
|
||||
|
||||
1. file:///
|
||||
2. file:///
|
||||
3. file:///cv/
|
||||
4. file:///projects/
|
||||
5. file:///writings/
|
||||
6. file:///writings/non-tech/
|
||||
7. mailto:benhoyt@gmail.com
|
||||
8. https://benhoyt.com/
|
||||
9. mailto:benhoyt@gmail.com
|
||||
10. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#small-software
|
||||
11. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#small-websites
|
||||
12. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#emphasize-server-side-not-javascript
|
||||
13. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#static-sites-and-site-generators
|
||||
14. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#fewer-dependencies
|
||||
15. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#small-analytics
|
||||
16. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#small-architectures-not-microservices
|
||||
17. https://basecamp.com/books
|
||||
18. https://neustadt.fr/essays/the-small-web/
|
||||
19. https://ar.al/2020/08/07/what-is-the-small-web/
|
||||
20. https://en.wikipedia.org/wiki/Forth_(programming_language)
|
||||
21. https://github.com/benhoyt/third
|
||||
22. https://en.wikipedia.org/wiki/Demoscene
|
||||
23. https://www.youtube.com/watch?v=jB0vBmiTr6o
|
||||
24. https://www.youtube.com/watch?v=RCh3Q08HMfs
|
||||
25. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#fewer-dependencies
|
||||
26. https://cr.yp.to/bib/1995/wirth.pdf
|
||||
27. https://blog.brush.co.nz/2008/07/adobe-reader-9/
|
||||
28. https://1mb.club/
|
||||
29. https://news.ycombinator.com/item?id=25151773
|
||||
30. https://512kb.club/
|
||||
31. https://news.ycombinator.com/item?id=25450451
|
||||
32. https://250kb.club/
|
||||
33. https://news.ycombinator.com/item?id=25176663
|
||||
34. https://10kbclub.com/
|
||||
35. https://news.ycombinator.com/item?id=25556860
|
||||
36. https://news.ycombinator.com/news
|
||||
37. https://lobste.rs/
|
||||
38. https://sourcehut.org/
|
||||
39. https://forgeperf.org/
|
||||
40. https://sqlite.org/
|
||||
41. https://sqlite.org/testing.html
|
||||
42. https://lwn.net/
|
||||
43. https://lwn.net/Archives/GuestIndex/#Hoyt_Ben
|
||||
44. https://danluu.com/
|
||||
45. https://lucumr.pocoo.org/
|
||||
46. https://nullprogram.com/
|
||||
47. http://eradman.com/
|
||||
48. https://hugotunius.se/
|
||||
49. https://prog21.dadgum.com/
|
||||
50. https://jvns.ca/
|
||||
51. https://sjmulder.nl/en/textonly.html
|
||||
52. https://giftyweddings.com/
|
||||
53. https://news.ycombinator.com/item?id=26057078
|
||||
54. https://news.ycombinator.com/item?id=11210860
|
||||
55. https://indieweb.org/
|
||||
56. https://small-tech.org/
|
||||
57. https://news.ycombinator.com/item?id=24269071
|
||||
58. https://indieweb.org/Homebrew_Website_Club
|
||||
59. https://indieweb.org/IndieWebCamps
|
||||
60. https://benhoyt.com/writings/seo-for-software-engineers/
|
||||
61. https://stackoverflow.com/
|
||||
62. https://blog.codinghorror.com/performance-is-a-feature/
|
||||
63. https://news.ycombinator.com/
|
||||
64. https://news.ycombinator.com/hn.js
|
||||
65. https://news.ycombinator.com/item?id=23876281
|
||||
66. https://alistapart.com/article/understandingprogressiveenhancement/
|
||||
67. https://www.reddit.com/
|
||||
68. https://github.com/turbolinks/turbolinks
|
||||
69. https://turbo.hotwire.dev/
|
||||
70. https://hey.com/
|
||||
71. https://m.signalvnoise.com/html-over-the-wire/
|
||||
72. https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets/
|
||||
73. https://benhoyt.com/writings/learning-elm/
|
||||
74. https://pages.github.com/
|
||||
75. https://jekyllrb.com/
|
||||
76. https://gohugo.io/
|
||||
77. https://staticsitegenerators.net/
|
||||
78. https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how-to-program/
|
||||
79. https://github.com/juliangruber/isarray/blob/c9b0c5b4f44d366c9f51c7e85e70339bdeaa97b0/index.js#L3-L5
|
||||
80. https://momentjs.com/
|
||||
81. https://momentjs.com/docs/#/use-it/webpack/
|
||||
82. https://date-fns.org/
|
||||
83. https://golang.org/doc/modules/managing-dependencies
|
||||
84. https://research.swtch.com/deps
|
||||
85. https://go-proverbs.github.io/
|
||||
86. http://youmightnotneedjquery.com/
|
||||
87. https://casparwre.de/blog/stop-using-google-analytics/
|
||||
88. https://lwn.net/Articles/822568/
|
||||
89. https://www.goatcounter.com/
|
||||
90. https://plausible.io/
|
||||
91. https://lwn.net/Articles/824294/
|
||||
92. https://www.theregister.com/2021/02/25/google_kubernetes_autopilot/
|
||||
93. https://en.wikipedia.org/wiki/Conway's_law
|
||||
94. https://m.signalvnoise.com/the-majestic-monolith/
|
||||
95. https://duckduckgo.com/?t=canonical&q=why+not+microservices&ia=web
|
||||
96. https://tailscale.com/blog/modules-monoliths-and-microservices/
|
||||
97. https://stackexchange.com/performance
|
||||
98. https://giftyweddings.com/
|
||||
99. https://aws.amazon.com/ec2/instance-types/t2/
|
||||
100. https://www.ansible.com/
|
||||
101. https://sqlite.org/whentouse.html
|
||||
102. https://litestream.io/
|
||||
103. https://litestream.io/blog/why-i-built-litestream/
|
||||
104. https://crawshaw.io/blog/one-process-programming-notes
|
||||
105. https://github.com/crawshaw/sqlite
|
||||
106. https://charlesleifer.com/blog/five-reasons-you-should-use-sqlite-in-2016/
|
||||
107. https://cravecookie.com/
|
||||
108. https://www.indiehackers.com/podcast/166-sam-eaton-of-crave-cookie
|
||||
109. https://jaas.ai/
|
||||
110. https://lobste.rs/s/d6qwff/small_web_is_beautiful
|
||||
111. https://news.ycombinator.com/item?id=26305585
|
||||
112. https://www.reddit.com/r/programming/comments/lvfdq9/the_small_web_is_beautiful/
|
||||
113. https://github.com/sponsors/benhoyt/
|
||||
344
static/archive/macwright-com-o4dndf.txt
Normal file
344
static/archive/macwright-com-o4dndf.txt
Normal file
@@ -0,0 +1,344 @@
|
||||
#[1]macwright.com [2]macwright.com
|
||||
|
||||
Tom MacWright
|
||||
|
||||
tom@macwright.com
|
||||
|
||||
Tom MacWright
|
||||
|
||||
* [3]Writingâ‡
|
||||
* [4]Reading
|
||||
* [5]Photos
|
||||
* [6]Projects
|
||||
* [7]Drawings
|
||||
* [8]About
|
||||
|
||||
A year of Rails
|
||||
|
||||
Railroad
|
||||
|
||||
I spent most of 2020 working with [9]Ruby on Rails. I moved a project
|
||||
from [10]Next.js + [11]Rust to… Rails, baby! Back to the future. My
|
||||
earlier post on [12]Second-guessing the modern web was inspired by this
|
||||
experience, that for the product we were building, a ‘modern’ stack was
|
||||
not working as well as a traditional one.
|
||||
|
||||
We didn’t do competitive analysis against Laravel, Django, or Phoenix.
|
||||
They’re similar, not radically better or worse. There are multiple
|
||||
acceptable solutions to a problem, and this was more a matter of
|
||||
choosing the right kind of solution than pursuing some kind of perfect
|
||||
choice and burning hours and motivation doing the window-shopping.
|
||||
|
||||
What helped Rails win was that the team had a little more experience in
|
||||
Ruby (with the exception of myself), and we found plenty of resources
|
||||
for developing and deploying the stack. Rails fit perfectly into the
|
||||
ideology of [13]Choosing boring technology. Another part of the product
|
||||
would be the hard, innovative part, so it made no sense to grapple with
|
||||
bleeding-edge web frameworks.
|
||||
|
||||
This was a really fun experience. There’s a lot to love about Rails.
|
||||
Other communities could learn a bit from the Ruby & Rails culture and
|
||||
wisdom. I won’t implement everything in Rails, but it’ll be part of the
|
||||
toolbox.
|
||||
|
||||
Before this, I hadn’t touched the stuff. And I bet a lot of people are
|
||||
like that - they came of age in the world of React and Go, and haven’t
|
||||
tried anything even remotely similar to Rails. For their benefit, and
|
||||
to debrief from 2020, here are some notes on the experience. Plus,
|
||||
[14]Rails-like projects in JavaScript are ramping up quickly, and it’s
|
||||
fun to know the origins.
|
||||
|
||||
The good
|
||||
|
||||
Debugging Rails apps is amazing
|
||||
|
||||
A while ago, I [15]wrote on Twitter
|
||||
|
||||
the real reason why javascript developers don’t use breakpoints and
|
||||
use console.log is that breakpoints don’t work
|
||||
|
||||
After years of working in JavaScript, I’m used to bad debugging
|
||||
experiences. The Chrome debugger’s [16]automatic pause on caught
|
||||
exceptions is amazing, sometimes. But throwing a debugger statement in
|
||||
some React code is dodgy as hell. Sometimes it works, mostly it
|
||||
doesn’t. You have to deal with code that might not have the right
|
||||
[17]sourcemap to translate from bundled & minified code to original
|
||||
source. Subtle abstractions like React hooks and advanced transpiler
|
||||
stuff like [18]Regenerator mean that your code’s stacktrace probably
|
||||
looks nothing like what you expect, with lots of internal garbage.
|
||||
Sure, you can learn better techniques for diagnosing and debugging
|
||||
errors, but it’s not just you - the debugging story in JavaScript is
|
||||
pretty bad. This applies even to Node.js, where one of the debugging
|
||||
stories is to connect Chrome’s debugger to a Node.js instance: a
|
||||
finicky solution that doesn’t consistently work.
|
||||
|
||||
In Rails, there is [19]byebug. You write byebug in your source code,
|
||||
and you get an interactive REPL right there. It works in views,
|
||||
controllers, database migrations, everywhere. It almost always works.
|
||||
Variables are named what you expect. The whole system is paused at that
|
||||
moment, and you can actually interact with it, using all of the Rails
|
||||
utilities and your installed gems.
|
||||
|
||||
If a page crashes unexpectedly, you get a similar REPL experience, in
|
||||
your browser, automatically. With an automatically cleaned-up
|
||||
stacktrace that excludes Rails’s own frames. Like the byebug interface,
|
||||
this REPL actually works and is consistently helpful in finding root
|
||||
causes. Rarely will you need to use puts to print something to the
|
||||
console because this debugging system is so good.
|
||||
|
||||
The magic mostly works
|
||||
|
||||
Our Rails app didn’t have any require statements. You mention a
|
||||
module’s name, and it’s automatically included, using [20]Zeitwerk, a
|
||||
tool that comes standard with Rails.
|
||||
|
||||
This kind of system was terrifying to me before. What if you
|
||||
accidentally import something just by mentioning it? What if two things
|
||||
have the same name and you import the wrong one? How do you really know
|
||||
what’s happening? Sure, you’re happy now, with all of that annoying
|
||||
importing and exporting taken care of, but the sky might fall.
|
||||
|
||||
Or maybe it just… doesn’t. Maybe impure, vaguely risky techniques are
|
||||
just a net positive over time, and making everything fully explicit
|
||||
isn’t really necessary? Now when I’m using other systems, I wonder -
|
||||
what if I could just mention one of my React components and it would
|
||||
just… be there? Sure, the system would have to complain if there were
|
||||
two components with the same name, and it would have to make
|
||||
assumptions about directory structure, but overall, wouldn’t this be
|
||||
nice?
|
||||
|
||||
This applies to a lot of other parts of the system too. Rails is famous
|
||||
for doing pluralization - you name a model Post and you automatically
|
||||
get an interface called posts. But what, you ask, of words with uneven
|
||||
pluralization rules? Rails actually [21]does the right thing, almost
|
||||
always. And when it fails, you can override it. It actually just saves
|
||||
time, reliably.
|
||||
|
||||
Testing works
|
||||
|
||||
I’ve tried to test front-end applications. I’ve set up [22]nightwatch,
|
||||
[23]jest, [24]enzyme, [25]cypress, and probably 5-10 other frameworks.
|
||||
Front-end testing is universally terrible. Projects like Cypress are
|
||||
throwing untold hours into making it less terrible, taking on massive
|
||||
amounts of complexity to abstract away from fickle browser behavior and
|
||||
complex interactions.
|
||||
|
||||
But it still sucks. Frontend testing has no good attributes: it’s
|
||||
unreliable, hard to automate, hard to debug when it fails, and often
|
||||
doesn’t even assert for important behaviors, so it doesn’t actually
|
||||
identify regressions. Running frontend tests in CI is resource-heavy,
|
||||
requiring you to set up headless X windows environments on servers or
|
||||
use specialized CI services that produce screencasts of test runs.
|
||||
|
||||
Testing fully-server-rendered applications, on the other hand, is
|
||||
amazing. A vanilla testing setup with Rails & [26]RSpec can give you
|
||||
fast, stable, concise, and actually-useful test coverage. You can
|
||||
actually assert for behavior and navigate through an application like a
|
||||
user would. These tests are solving a simpler problem - making requests
|
||||
and parsing responses, without the need for a full browser or headless
|
||||
browser, without multiple kinds of state to track.
|
||||
|
||||
Not only do the tests work better, the testing culture is a completely
|
||||
different universe. There are entire books written about how to write
|
||||
RSpec tests that catch bugs, allow software evolution, and aren’t
|
||||
filled with boilerplate.
|
||||
|
||||
Gems are so powerful
|
||||
|
||||
Powerful and dangerous.
|
||||
|
||||
I’m used to modules as they work in other systems - Python, Node, Elm,
|
||||
and so on. They provide objects, functions, and variables that you can
|
||||
import and combine into your code explicitly. Usually they sit on some
|
||||
specific level of abstraction - it’s a utility for connecting to
|
||||
servers or a React component you can use.
|
||||
|
||||
Gems can do so much more. You install something like [27]Devise into
|
||||
your system and it adds views, routes, methods, utilities, you name it.
|
||||
It’s not like “loading some functionsâ€<C3A2>, it’s more like composing a
|
||||
whole different app into your app, implicitly.
|
||||
|
||||
This is obviously terrifying. It means that you can’t look at your
|
||||
directories of views and your file of routes.rb and know what exists at
|
||||
a glance. There are other layers, lurking in the ephemeral space of
|
||||
third-party code. They interact in serious but uncertain ways.
|
||||
|
||||
But it’s also pretty incredible - the idea that something like
|
||||
[28]passport, Node’s middleware, could instead be a full-fledged
|
||||
authentication system. It means that you have to write a lot less code,
|
||||
and it also means that the people who use that code have a lot more
|
||||
code in common. That gems can work on a higher level of abstraction,
|
||||
making it possible to cobble together software faster, to write less
|
||||
‘glue code.’
|
||||
|
||||
There’s so much good writing about Rails
|
||||
|
||||
Even if you don’t write Ruby, you should pay attention to [29]Sandi
|
||||
Metz. She’s incredibly wise and has so many incredible ideas to share.
|
||||
|
||||
And then there’s [30]arkency, [31]ThoughtBot, and so many other
|
||||
thoughtful writers with years of experience in Rails. Sometimes it’s a
|
||||
little shocking to google for some obscure problem and see a decade of
|
||||
discussion about it.
|
||||
|
||||
The best practices are also formalized into tools like [32]Code Climate
|
||||
and [33]reek. I’ve never seen so many actually-useful suggestions come
|
||||
out of automated systems as I did in the world of Ruby and Rails.
|
||||
|
||||
Ruby
|
||||
|
||||
Ruby is a pretty pleasant language to work in. Sure, it has a lot of
|
||||
syntax and a sprawling standard library, but you don’t have to use all
|
||||
of that if you don’t want to. It took me a while to adjust to the
|
||||
object-oriented way of doing things - in particular, the idea that you
|
||||
can’t just have a free-range function floating out there, unassociated
|
||||
with a class or module, like you can in JavaScript. And you can’t just
|
||||
create an arbitrary one-off object - you either need to define a class
|
||||
to create an object, or use a Hash to store data.
|
||||
|
||||
But Ruby’s standard library isn’t that huge. I’ve seen JavaScript’s
|
||||
‘standard library’ grow a lot too, and frankly it’s nice to have
|
||||
methods like [34]String.prototype.padStart instead of having every
|
||||
little thing in userspace. The only part that felt actively weird was
|
||||
[35]activesupport - a gem that extends Ruby’s core objects, but is part
|
||||
of Rails. It felt weird to have string methods that would only work if
|
||||
your environment was Rails.
|
||||
|
||||
The [36]Dash app for documentation rocketed from my pile of unused
|
||||
tools to an absolute must-have. In the world of Ruby and Rails, with
|
||||
most gems having pretty good, semi-standard documentation, you can
|
||||
search for, and get answers, super fast. The Ruby language
|
||||
documentation and the Rails documentation is absolutely great. The
|
||||
JavaScript equivalent - [37]MDN - pales in comparison.
|
||||
|
||||
The bad
|
||||
|
||||
The asset pipeline
|
||||
|
||||
Remember SASS and the YUI Compressor? These are, unfortunately,
|
||||
defaults in the [38]asset pipeline. There’s [39]Webpacker too, which
|
||||
has a parallel approach to CSS and images as the asset pipeline. It has
|
||||
[40]opinionated integrations with stuff like React. Ah, and I should
|
||||
mention that Rails’s [41]JavaScript utilities are written in…
|
||||
CoffeeScript.
|
||||
|
||||
I get it - it’s hard to keep up with the latest trends in frontend. But
|
||||
this is one area where Rails’s strong backwards compatibility feels
|
||||
iffy. I wish that Rails was more opinionated about the frontend, and
|
||||
that it had better opinions.
|
||||
|
||||
Best practice churn
|
||||
|
||||
In Smalltalk, everything happens somewhere else. - [42]Adele
|
||||
Goldberg
|
||||
|
||||
Ruby, as today’s Smalltalk, has the same issue. The community venerates
|
||||
small - that methods should be short, files should be small, complexity
|
||||
should be controlled. This begs the question of where it all goes -
|
||||
certainly not in controllers, which should be skinny, and not in views,
|
||||
which should have very little logic at all, and maybe [43]not in models
|
||||
either. Maybe in [44]Service Objects, or policies, or decorators?
|
||||
|
||||
I found myself falling victim to this. I’d try to win CodeClimate’s
|
||||
approval by moving code around, perfecting the art of making everything
|
||||
small or at most medium-sized, extracting concerns until most files
|
||||
looked okay. This was time well-spent on learning, but I have to admit
|
||||
that it doesn’t actually matter for an early-stage startup’s product.
|
||||
|
||||
In stark contrast to the folks who say that Rails is for prototypes,
|
||||
there’s a lot of attention paid to long-lived engineering efforts -
|
||||
adopting patterns that let many team work on the same ‘monolith’,
|
||||
identifying [45]shotgun surgery - a term I first heard from Sandi Metz.
|
||||
|
||||
ActiveRecord is great, except when it isn’t
|
||||
|
||||
One of the hardest bugs we encountered happened with ActiveRecord. We
|
||||
were creating a set of changes to apply to a model, using their
|
||||
in-memory instances to do some stuff, and then finally applying them.
|
||||
This broke because one of the ActiveRecord methods automatically
|
||||
‘committed’ those changes, quietly.
|
||||
|
||||
ActiveRecord is kind of like this - a lot of the times it’s pleasantly
|
||||
implicit, letting you just assign a value and automatically saving that
|
||||
to the database. But then it’ll do something implicitly that you don’t
|
||||
want to happen, and figuring out why this happened and how to stop it
|
||||
from happening is a real challenge.
|
||||
|
||||
Most of the time, to be clear - it’s a really great system. It provides
|
||||
lots of ways to generate efficient-enough queries, knowing full well
|
||||
that SQL performance is often the bottleneck of web applications. Most
|
||||
of the time it’s really nice that it automatically casts and
|
||||
deserializes query results. But when it goes bad, the diagnosis and the
|
||||
cure can be pretty ugly.
|
||||
|
||||
The other issue with ActiveRecord is that it has efficient methods and
|
||||
inefficient methods right next to each other, because it automatically
|
||||
turns your ‘query builder’ into an array when you call array-like
|
||||
methods. So, for example:
|
||||
Dogs.all.max_by(&:height)
|
||||
|
||||
Is wildly inefficient. It might fetch and deserialized a million
|
||||
records just to sort them and give you the first. On the other hand,
|
||||
Dogs.order(height: :desc).first
|
||||
|
||||
Is fast - it sorts in the database and fetches a single record. Rails
|
||||
is both offering smart and easy ways to write optimized code, but also
|
||||
making it really easy to write inefficient code.
|
||||
__________________________________________________________________
|
||||
|
||||
A Rails-like framework is a really good thing to have in your toolbox,
|
||||
and there’s a lot to learn from the Ruby community. My hope is that we
|
||||
see these sorts of abstractions in new languages and frameworks, and
|
||||
see more of the Ruby community’s culture filter into the programming
|
||||
world.
|
||||
|
||||
February 18, 2021 [46]@tmcw
|
||||
|
||||
References
|
||||
|
||||
1. https://macwright.com/rss.xml
|
||||
2. https://macwright.com/atom.xml
|
||||
3. file:///
|
||||
4. file:///reading/
|
||||
5. file:///photos/
|
||||
6. file:///projects/
|
||||
7. file:///drawings/
|
||||
8. file:///about/
|
||||
9. https://rubyonrails.org/
|
||||
10. https://nextjs.org/
|
||||
11. https://www.rust-lang.org/
|
||||
12. https://macwright.com/2020/05/10/spa-fatigue.html
|
||||
13. http://boringtechnology.club/
|
||||
14. https://macwright.com/2020/10/28/if-not-spas.html
|
||||
15. https://twitter.com/tmcw/status/1321133460501585922
|
||||
16. https://developers.google.com/web/updates/2015/05/automatically-pause-on-any-exception
|
||||
17. https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/
|
||||
18. https://github.com/facebook/regenerator
|
||||
19. https://github.com/deivid-rodriguez/byebug
|
||||
20. https://github.com/fxn/zeitwerk
|
||||
21. https://weblog.rubyonrails.org/2005/8/25/10-reasons-rails-does-pluralization/
|
||||
22. https://nightwatchjs.org/
|
||||
23. https://jestjs.io/
|
||||
24. https://enzymejs.github.io/enzyme/
|
||||
25. https://www.cypress.io/
|
||||
26. https://rspec.info/
|
||||
27. https://github.com/heartcombo/devise
|
||||
28. http://www.passportjs.org/
|
||||
29. https://sandimetz.com/
|
||||
30. https://blog.arkency.com/
|
||||
31. https://thoughtbot.com/blog/
|
||||
32. https://codeclimate.com/
|
||||
33. https://github.com/troessner/reek
|
||||
34. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
|
||||
35. https://rubygems.org/gems/activesupport/versions/6.1.1
|
||||
36. https://kapeli.com/dash
|
||||
37. https://developer.mozilla.org/en-US/
|
||||
38. https://guides.rubyonrails.org/asset_pipeline.html
|
||||
39. https://edgeguides.rubyonrails.org/webpacker.html
|
||||
40. https://github.com/rails/webpacker#integrations
|
||||
41. https://github.com/rails/rails/tree/main/actionview/app/assets/javascripts
|
||||
42. https://en.wikipedia.org/wiki/Adele_Goldberg_(computer_scientist)
|
||||
43. https://thoughtbot.com/blog/skinny-controllers-skinny-models
|
||||
44. https://codeclimate.com/blog/7-ways-to-decompose-fat-activerecord-models/
|
||||
45. https://en.wikipedia.org/wiki/Shotgun_surgery
|
||||
46. https://twitter.com/intent/follow?screen_name=tmcw&user_id=1458271
|
||||
150
static/archive/maggieappleton-com-7am49k.txt
Normal file
150
static/archive/maggieappleton-com-7am49k.txt
Normal file
@@ -0,0 +1,150 @@
|
||||
#[1]Main RSS Feed
|
||||
|
||||
[2]Home
|
||||
The Garden (BUTTON)
|
||||
[3]Now
|
||||
[4]About
|
||||
(BUTTON)
|
||||
|
||||
notes
|
||||
|
||||
evergreen
|
||||
|
||||
What App is That?
|
||||
|
||||
A guide to the apps and tools I use to create illustrations
|
||||
* [5]How to Illustrate
|
||||
|
||||
Planted about 3 years agoLast tended about 2 years ago
|
||||
|
||||
(BUTTON) Back To Top
|
||||
|
||||
"What app is that?"
|
||||
|
||||
[6]
|
||||
|
||||
I'm a Promiscuous Polytooler
|
||||
|
||||
I use wide variety of different tools and apps for different kinds of
|
||||
visual creations. I'm not wedded to any one tool in particular – they
|
||||
all have their strengths and weaknesses. I'll use whatever fits the
|
||||
task at hand and move work between them liberally.
|
||||
|
||||
Here's all the apps and hardware that might be involved in a particular
|
||||
creation...
|
||||
|
||||
None of these are affiliate links - I'm just pointing you to official
|
||||
sites for more context
|
||||
[7]
|
||||
|
||||
Workflows
|
||||
|
||||
And here's a couple of my common workflows for different styles of
|
||||
illustrations and visuals...
|
||||
|
||||
1. Illustrated notes
|
||||
|
||||
Anything I make that has a painterly and loose hand-drawn feel was made
|
||||
in Procreate on the iPad or Photoshop on the Wacom Cintiq. Or probably
|
||||
a combination – it's easy to move files back and forth between the two
|
||||
and the tools they offer are very similar.
|
||||
|
||||
Illustrations like these...
|
||||
|
||||
Both of these applications allow you to draw in “raster” graphics,
|
||||
meaning you paint pixels onto a canvas. They require a decent level of
|
||||
hand-skills to make sure your lines aren't wobbly, although both
|
||||
applications have smoothing features to help with that.
|
||||
|
||||
When I'm in Procreate I use a small selection of brushes I've gathered
|
||||
over the years. It's hard for me to remember where they're all from,
|
||||
and I've customised the majority of them to suit my personal prefs.
|
||||
Most of them were originally from Max Ulichney's brushes. I have the
|
||||
essentials set ($2), the painters set ($8), and the comics set ($15),
|
||||
and can vouch they're all great.
|
||||
|
||||
I move these pieces to Photoshop if I want to work on a larger screen,
|
||||
or have accidentally enlarged the canvas to a 14000px wide sprawling
|
||||
set of sketches that Procreate can't open without crashing.
|
||||
|
||||
2. Polished vector illustrations
|
||||
|
||||
Illustrations that look more “polished” are made primarily in Adobe
|
||||
Illustrator, with a touch of Photoshop at the end for lighting effects
|
||||
and texture.
|
||||
|
||||
Pieces like these...
|
||||
|
||||
These illustrations are all vector-based, meaning we use mathematical
|
||||
curves to define their shapes, rather than painted pixels. Vectors are
|
||||
great for create hard, crisp edges and working with perfect geometric
|
||||
forms.
|
||||
|
||||
While I love vectors for laying down the foundation shapes of these,
|
||||
I'll move them over the Photoshop once they're 90% done to adjust the
|
||||
colors, add more subtlety to the lighting and shadows, and chuck a bit
|
||||
of texture on the top so they feel more tangible.
|
||||
|
||||
Want to share? (BUTTON) Tell Twitter About It
|
||||
|
||||
3 Backlinks
|
||||
|
||||
Why You Own an iPad and Still Can't Draw
|
||||
|
||||
The failure of drawing materials without mediums and meat
|
||||
|
||||
Frequently Asked Questions
|
||||
|
||||
Questions I am often asked to answer
|
||||
|
||||
The Best Illustration Books and Courses
|
||||
|
||||
My favourite resources for learning to draw and developing your visual
|
||||
thinking skills
|
||||
|
||||
Mentions around the web
|
||||
|
||||
Tomiwa 😃
|
||||
Maggie Appleton - indieweb.social/@maggie
|
||||
2 Likes and Retweets
|
||||
|
||||
Want to stay up to date?
|
||||
|
||||
(BUTTON) Subscribe via RSS Feed
|
||||
© 2023 Maggie Appleton
|
||||
* [8]The Garden
|
||||
* [9]Essays
|
||||
* [10]About
|
||||
* [11]Notes
|
||||
* [12]Now
|
||||
* [13]Patterns
|
||||
* [14]Library
|
||||
* [15]Projects
|
||||
* [16]Colophon
|
||||
|
||||
References
|
||||
|
||||
Visible links:
|
||||
1. file:///rss.xml
|
||||
2. file:///
|
||||
3. file:///now
|
||||
4. file:///about
|
||||
5. file:///topics/how-to-illustrate
|
||||
6. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71674-9587TMP.html#im-a-promiscuous-polytooler
|
||||
7. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71674-9587TMP.html#workflows
|
||||
8. file:///garden
|
||||
9. file:///essays
|
||||
10. file:///about
|
||||
11. file:///notes
|
||||
12. file:///now
|
||||
13. file:///patterns
|
||||
14. file:///library
|
||||
15. file:///projects
|
||||
16. file:///colophon
|
||||
|
||||
Hidden links:
|
||||
18. https://github.com/MaggieAppleton
|
||||
19. https://uk.linkedin.com/in/maggieappleton
|
||||
20. https://dribbble.com/mappleton
|
||||
21. https://twitter.com/Mappletons
|
||||
22. https://indieweb.social/@maggie
|
||||
135
static/archive/maggieappleton-com-fube9k.txt
Normal file
135
static/archive/maggieappleton-com-fube9k.txt
Normal file
@@ -0,0 +1,135 @@
|
||||
#[1]Main RSS Feed
|
||||
|
||||
[2]Home
|
||||
The Garden (BUTTON)
|
||||
[3]Now
|
||||
[4]About
|
||||
(BUTTON)
|
||||
|
||||
Essays
|
||||
|
||||
budding
|
||||
|
||||
Why You Own an iPad and Still Can't Draw
|
||||
|
||||
The failure of drawing materials without mediums and meat
|
||||
* [5]How to Illustrate
|
||||
|
||||
Planted almost 3 years agoLast tended almost 3 years ago
|
||||
|
||||
(BUTTON) Back To Top
|
||||
|
||||
Assumed Audience
|
||||
|
||||
Anyone who thinks they can't draw, but would like to learn
|
||||
|
||||
They message me a lot.
|
||||
|
||||
Which iPad should I buy? What app do you use? What brush is that?
|
||||
What size should my canvas be?
|
||||
|
||||
These questions aren't wrong. In fact they're perfectly reasonable.
|
||||
|
||||
I'm vocal about the fact many of my illustrations are made on in an app
|
||||
called . I have a full post about my drawing equipment and workflows
|
||||
over at
|
||||
[6]What App is That?
|
||||
|
||||
How are you supposed to draw if you don't also have these fancy tools?
|
||||
|
||||
This is the tricky bit.
|
||||
|
||||
If you go out and buy yourself these same things, you'll have all the
|
||||
right materials to draw. But that's only the dressing on the drawing
|
||||
dish.
|
||||
[7]
|
||||
|
||||
What you have is Material without the Medium or the Meat
|
||||
|
||||
What on earth do I mean by material, medium, and meat?
|
||||
__________________________________________________________________
|
||||
|
||||
[8]
|
||||
|
||||
Moving past materials
|
||||
|
||||
Worrying about the materials should take up - at most - 10% of your
|
||||
attention and concern. Focus 70% of your attention on learning the
|
||||
medium while you're just starting out.
|
||||
|
||||
You can keep 20% of your focus on the Meat. But I wouldn't worry too
|
||||
much about communicating original, profound ideas at first. Doing so in
|
||||
addition to learning a whole new language is going to be overwhelming.
|
||||
|
||||
In the same way it's a bad idea to learn Spanish while simultaneously
|
||||
trying to write a philosophy dissertation in it.
|
||||
|
||||
Once you get more comfortable “speaking" in visual language, you'll be
|
||||
able to shift a much higher percentage of your attention onto the Meat.
|
||||
You'll get to focus on The Thing You Want to Say, and know enough
|
||||
visual language to say it well.
|
||||
|
||||
That's the ideal I'm currently striving for. To reach a point where the
|
||||
Material is irrelevant, the Medium is a baked into my subconscious, and
|
||||
I'm all about the Meat.
|
||||
|
||||
That's the goal. Don't let the shiny iPad reflection blind you.
|
||||
|
||||
Get past picking the Material. Focus on the Medium. Aim for the Meat.
|
||||
|
||||
Want to share? (BUTTON) Tell Twitter About It
|
||||
|
||||
1 Backlinks
|
||||
|
||||
The Best Illustration Books and Courses
|
||||
|
||||
My favourite resources for learning to draw and developing your visual
|
||||
thinking skills
|
||||
|
||||
Mentions around the web
|
||||
|
||||
Tomiwa 😃
|
||||
Maggie Appleton - indieweb.social/@maggie
|
||||
2 Likes and Retweets
|
||||
|
||||
Want to stay up to date?
|
||||
|
||||
(BUTTON) Subscribe via RSS Feed
|
||||
© 2023 Maggie Appleton
|
||||
* [9]The Garden
|
||||
* [10]Essays
|
||||
* [11]About
|
||||
* [12]Notes
|
||||
* [13]Now
|
||||
* [14]Patterns
|
||||
* [15]Library
|
||||
* [16]Projects
|
||||
* [17]Colophon
|
||||
|
||||
References
|
||||
|
||||
Visible links:
|
||||
1. file:///rss.xml
|
||||
2. file:///
|
||||
3. file:///now
|
||||
4. file:///about
|
||||
5. file:///topics/how-to-illustrate
|
||||
6. file:///apps
|
||||
7. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L84552-9249TMP.html#what-you-have-is-material-without-the-medium-or-the-meat
|
||||
8. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L84552-9249TMP.html#moving-past-materials
|
||||
9. file:///garden
|
||||
10. file:///essays
|
||||
11. file:///about
|
||||
12. file:///notes
|
||||
13. file:///now
|
||||
14. file:///patterns
|
||||
15. file:///library
|
||||
16. file:///projects
|
||||
17. file:///colophon
|
||||
|
||||
Hidden links:
|
||||
19. https://github.com/MaggieAppleton
|
||||
20. https://uk.linkedin.com/in/maggieappleton
|
||||
21. https://dribbble.com/mappleton
|
||||
22. https://twitter.com/Mappletons
|
||||
23. https://indieweb.social/@maggie
|
||||
1069
static/archive/softwarecrisis-dev-7c7z9g.txt
Normal file
1069
static/archive/softwarecrisis-dev-7c7z9g.txt
Normal file
File diff suppressed because it is too large
Load Diff
191
static/archive/taylor-town-5siv9a.txt
Normal file
191
static/archive/taylor-town-5siv9a.txt
Normal file
@@ -0,0 +1,191 @@
|
||||
[1]taylor.town
|
||||
|
||||
[2]about [3]now [4]hire [5]rss [6]spam
|
||||
|
||||
cloaca maxima
|
||||
|
||||
When to Build Millennia Sewers
|
||||
|
||||
In the mid-1800s, [7]every building in central Chicago was raised 10ft
|
||||
(30m). Yes, they literally used [8]jackscrews to lift entire city
|
||||
blocks up one-by-one.
|
||||
|
||||
Chicago had to [9]hotfix production because they built the city on the
|
||||
shoreline of Lake Michigan, where filth accumulated without natural
|
||||
drainage. They lifted the entire city after it was built so they could
|
||||
add sewers and prevent flooding.
|
||||
|
||||
For comparison, Rome’s [10]Cloaca Maxima (“Greatest Sewer”) is still
|
||||
in-use after 2,400 years.
|
||||
|
||||
So why didn’t Chicago just build it right the first time?
|
||||
* [11]Irreversible Decisions
|
||||
* [12]Unintended vs. Unforeseen
|
||||
* [13]Always Scale Down
|
||||
* [14]Labor & Materials
|
||||
* [15]Awful Architecture
|
||||
|
||||
Irreversible Decisions
|
||||
|
||||
Some decisions are consequential and irreversible or nearly
|
||||
irreversible – one-way doors – and these decisions must be made
|
||||
methodically, carefully, slowly, with great deliberation and
|
||||
consultation. If you walk through and don’t like what you see on the
|
||||
other side, you can’t get back to where you were before. We can call
|
||||
these Type 1 decisions. But most decisions aren’t like that – they
|
||||
are changeable, reversible – they’re two-way doors. If you’ve made a
|
||||
suboptimal Type 2 decision, you don’t have to live with the
|
||||
consequences for that long. You can reopen the door and go back
|
||||
through. Type 2 decisions can and should be made quickly by high
|
||||
judgment individuals or small groups.
|
||||
|
||||
As organizations get larger, there seems to be a tendency to use the
|
||||
heavy-weight Type 1 decision-making process on most decisions,
|
||||
including many Type 2 decisions. The end result of this is slowness,
|
||||
unthoughtful risk aversion, failure to experiment sufficiently, and
|
||||
consequently diminished invention. We’ll have to figure out how to
|
||||
fight that tendency.
|
||||
|
||||
– [16]Jeff Bezos
|
||||
|
||||
The Cloaca Maxima didn’t magically start out as the Greatest Sewer. It
|
||||
began as an open-air canal, then was modified and renovated and
|
||||
connected to the aqueducts.
|
||||
|
||||
The Romans probably made mistakes, but they didn’t make any wrong
|
||||
irreversible decisions. To build something that lasts, make sure the
|
||||
architecture is correct where it counts.
|
||||
|
||||
The Chicago sewage disaster was technically reversible, but extremely
|
||||
expensive and painful.
|
||||
|
||||
Put “wiggle-room” in your architecture. Plan for repairs. Add
|
||||
backdoors, engine-hoods, seams, and spaces. Emergency plans are
|
||||
generally cheap to include in early phases of design.
|
||||
|
||||
Unintented vs. Unforeseen
|
||||
|
||||
[17]Exxon executives knew that CO₂ emissions would harm Earth.
|
||||
|
||||
Exxon willfully ignored its own research. Climate change was unintended
|
||||
but not unforeseen.
|
||||
|
||||
Prophets are silenced when apocalypses seem bad for business.
|
||||
|
||||
But remember – all apocalypses are opportunities for entrepeneurship.
|
||||
Exxon could’ve made billions by diversifying themselves with renewable
|
||||
energy. They acted against their own self-interest by ignoring their
|
||||
facts.
|
||||
|
||||
To prevent long-term disaster, solve the hard problem of aligning
|
||||
incentives. Build systems so that all constituents predict and prevent
|
||||
impending doom.
|
||||
|
||||
Transparency thwarts [18]own goals. It’s difficult to do stupid things
|
||||
when you do stupid things publicly.
|
||||
|
||||
Always Scale Down
|
||||
|
||||
There’s really two ways to design things. You can either sort of
|
||||
start with small things and scale them up or you could start with
|
||||
big things and scale them down…
|
||||
|
||||
So suppose you want to build a system for like 10,000 people to use
|
||||
simultaneously. One way of doing it would be to start with the
|
||||
system, design it for 10 people and test it like that and scale it
|
||||
up 10,000. The other way would be to design it for like 100,000,000
|
||||
people – I mean do the design for that – and then scale it down to
|
||||
tens of thousands. You might not get the same architecture. You
|
||||
might get a completely different architecture. In fact, you would
|
||||
get a different architecture.
|
||||
|
||||
And I think it’s a really bad idea to start at a design for 10 or
|
||||
100 things and scale it up. It’s better to start with an
|
||||
architecture that you know will work for a few trillion things and
|
||||
scale it down. It will actually be less efficient when you’ve got
|
||||
your 10,000 things than when you scaled up, but you’ll know that
|
||||
you’ll be able to scale it up later. So it’s good.
|
||||
|
||||
So rather than ask, “how do we get to five nines?”, let’s make it
|
||||
more interesting! Let’s start at 9,999 nines reliability and scale
|
||||
it down.
|
||||
|
||||
– Joe Armstrong from [19]Systems that run forever and self-heal and
|
||||
scale
|
||||
|
||||
If you can afford it, throw a few extra zeroes on your designs.
|
||||
|
||||
Labor & Materials
|
||||
|
||||
Carefully compare lifetime, labor, and materials.
|
||||
|
||||
lifetime repair labor materials
|
||||
asphalt 20 years moderate $ $
|
||||
concrete 30 years difficult $ $$
|
||||
stone 100+ years easy $$$$ $$$
|
||||
|
||||
Pay particular attention to labor – 9 women can’t make a baby in 1
|
||||
month.
|
||||
|
||||
Exercise for the reader: Which is cheaper, a Nespresso machine or a
|
||||
[20]percolator?
|
||||
|
||||
Awful Architecture
|
||||
|
||||
Sometimes there are no tradeoffs.
|
||||
|
||||
Some decisions are awful in every dimension.
|
||||
|
||||
[21]Dvorak keyboards reduce finger fatigue using the same materials as
|
||||
QWERTY keyboards.
|
||||
|
||||
[22]Juicero famously launched a high-tech product that was inferior to
|
||||
traditional juicers [23]in every comparable way:
|
||||
|
||||
After taking apart the device, venture capitalist Ben Einstein
|
||||
considered the press to be “an incredibly complicated piece of
|
||||
engineering”, but that the complexity was unnecessary and likely
|
||||
arose from a lack of cost constraints during the design process. A
|
||||
simpler and cheaper implementation, suggested Einstein, would likely
|
||||
have produced much the same quality of juice at a price several
|
||||
hundred dollars cheaper.
|
||||
|
||||
If you want to create lasting sewers, study sewer architecture and its
|
||||
impacts. What do good sewers have in common? What do bad sewers look
|
||||
like? What tradeoffs exist with sewage systems? Are there any
|
||||
promising-yet-untested sewer designs? Why do sewers go into disrepair?
|
||||
What societal factors prevent sewers from being made in the first
|
||||
place? Who truly controls the sewers?
|
||||
|
||||
Great architects think ahead, but don’t let ambitions run amok. They
|
||||
anticipate irreversible changes and second-order effects. They consider
|
||||
all the costs – labor and materials and maintenance and environmental
|
||||
impact. They always stay ahead-of-schedule and within their budget. And
|
||||
despite the overwhelming constraints, great architects build millennia
|
||||
sewers whenever and wherever they can.
|
||||
|
||||
References
|
||||
|
||||
1. file:///
|
||||
2. file:///about
|
||||
3. file:///now
|
||||
4. file:///hire-me
|
||||
5. file:///feed.xml
|
||||
6. https://newsletter.taylor.town/
|
||||
7. https://en.wikipedia.org/wiki/Raising_of_Chicago
|
||||
8. https://en.wikipedia.org/wiki/Jack_(device)#House_jack
|
||||
9. https://www.reddit.com/r/ProgrammerHumor/comments/blhec6/fixing_bugs_in_production/
|
||||
10. https://en.wikipedia.org/wiki/Cloaca_Maxima
|
||||
11. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#irreversible
|
||||
12. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#unintended
|
||||
13. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#scale-down
|
||||
14. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#labor-materials
|
||||
15. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#awful
|
||||
16. https://www.sec.gov/Archives/edgar/data/1018724/000119312516530910/d168744dex991.htm
|
||||
17. https://en.wikipedia.org/wiki/ExxonMobil_climate_change_denial
|
||||
18. https://en.wikipedia.org/wiki/Own_goal
|
||||
19. https://www.youtube-nocookie.com/embed/cNICGEwmXLU?start=433
|
||||
20. https://en.wikipedia.org/wiki/Coffee_percolator
|
||||
21. https://en.wikipedia.org/wiki/Dvorak_keyboard_layout
|
||||
22. https://en.wikipedia.org/wiki/Juicero
|
||||
23. https://en.wikipedia.org/wiki/Juicero#Criticism
|
||||
142
static/archive/timharek-no-ah7ilz.txt
Normal file
142
static/archive/timharek-no-ah7ilz.txt
Normal file
@@ -0,0 +1,142 @@
|
||||
[1]Skip to content
|
||||
* [2]Blog
|
||||
* [3]Connect
|
||||
* [4]About
|
||||
|
||||
* [5]Index
|
||||
* [6]Blog
|
||||
* My thoughts on Helix after 6 months
|
||||
|
||||
My thoughts on Helix after 6 months
|
||||
|
||||
Published June 19, 2023 — 3 minute read
|
||||
Photo of Tim Hårek Andreassen Tim Hårek Andreassen
|
||||
|
||||
Back in [7]January I decided to try out Helix as my primary editor and
|
||||
today I have almost been using it for 6 months and these are my
|
||||
thoughts.
|
||||
|
||||
[8]# What I like
|
||||
|
||||
[9]# Keystrokes
|
||||
|
||||
Helix lives in the opposite land when it comes to keystrokes in
|
||||
comparison to Vim, and it was only difficult for the first couple of
|
||||
days. I’ve become fond of the way to navigate around.
|
||||
|
||||
[10]# Minor modes
|
||||
|
||||
I really like that there are more modes, called [11]“Minor modes”, and
|
||||
the reason why I like them are that whenever I initate a mode there is
|
||||
a subtle pop-up in the lower-right corner with the available actions
|
||||
with the activated mode. This is super helpful when you are first
|
||||
learning Helix and when you are doing something you don’t do on a
|
||||
regular basis. It lowers the chance of having to switch context in
|
||||
order to do something. For instance, I know that m activates “Match
|
||||
mode”, but sometimes I may forget how to select around specific
|
||||
selector like (), but with Helix I will have a little helper that tells
|
||||
me that the next key is a and then the next helper will help me select
|
||||
just ().
|
||||
|
||||
[12]# Moving around
|
||||
|
||||
I’ve become really fond of the idea that every move-action is also a
|
||||
selection/highlight, I find that I miss that feature whenever I edit
|
||||
server-configs via SSH or somewhere else when I’m not in Helix. It
|
||||
feels natural after a while because you get used to moving around
|
||||
text/code with w and e.
|
||||
|
||||
[13]# Configuration
|
||||
|
||||
No more Vimscript and Lua, just plaintext TOML! The documentation for
|
||||
how to configure the editor is great and most of the defaults are also
|
||||
great! My editor-config is just 23 lines in contrast to my
|
||||
Neovim-config which is 209 lines long.
|
||||
|
||||
[14]# Language server protocol (LSP) support
|
||||
|
||||
I had some experience with this from Neovim, but it felt cumbersome
|
||||
having to configure everything. With Helix I can simply run hx --health
|
||||
markdown and see what LSP is required for Markdown.
|
||||
$ hx --health markdown
|
||||
Configured language server: marksman
|
||||
Binary for language server: /opt/homebrew/bin/marksman
|
||||
Configured debug adapter: None
|
||||
Highlight queries: ✓
|
||||
Textobject queries: ✘
|
||||
Indent queries: ✘
|
||||
|
||||
I even managed to get it working with Deno thanks to its documentation
|
||||
on how to use custom LSPs for specific languages.
|
||||
|
||||
[15]# What I don’t like
|
||||
|
||||
There really isn’t anything in particualr that I don’t like about
|
||||
Helix. I really miss having it installed on servers by default, but I
|
||||
completely understand that that is a big ask 😅 It’s not too difficult
|
||||
to swap between Vim-bindings and Helix-bindings for short sessions.
|
||||
|
||||
[16]# Conclusion
|
||||
|
||||
Helix is fun and easy! I highly recommend Helix if you:
|
||||
* want to try a new editor,
|
||||
* tired of configuring {Neo}vim with Vimscript/Lua,
|
||||
* or been thinking about trying out Vim, but been hesitant because of
|
||||
the modes.
|
||||
|
||||
I will continue to use Helix for the forseeable future, I’m looking
|
||||
forward to what future updates will bring!
|
||||
|
||||
Remember to check out Helix’s tutor, hx --tutor for quick introduction
|
||||
to its keystrokes and interactions.
|
||||
|
||||
Tagged with [17]100 days to
|
||||
offload[18]helix[19]software[20]thoughts[21]tools
|
||||
540 words
|
||||
[22]Reply via e-mail
|
||||
|
||||
Also mentioned in
|
||||
|
||||
* [23]June 2023
|
||||
|
||||
Last deploy: 2023-07-02 11:14 UTC
|
||||
|
||||
* [24]Stats
|
||||
* [25]Privacy
|
||||
* [26]Sitemap
|
||||
* [27]RSS
|
||||
|
||||
References
|
||||
|
||||
Visible links:
|
||||
1. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#main
|
||||
2. https://timharek.no/blog/
|
||||
3. https://timharek.no/connect/
|
||||
4. https://timharek.no/about/
|
||||
5. https://timharek.no/
|
||||
6. https://timharek.no/blog/
|
||||
7. https://timharek.no/blog/trying-helix/
|
||||
8. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#what-i-like
|
||||
9. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#keystrokes
|
||||
10. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#minor-modes
|
||||
11. https://docs.helix-editor.com/keymap.html#normal-mode
|
||||
12. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#moving-around
|
||||
13. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#configuration
|
||||
14. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#language-server-protocol-lsp-support
|
||||
15. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#what-i-don-t-like
|
||||
16. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#conclusion
|
||||
17. https://timharek.no/tags/100-days-to-offload/
|
||||
18. https://timharek.no/tags/helix/
|
||||
19. https://timharek.no/tags/software/
|
||||
20. https://timharek.no/tags/thoughts/
|
||||
21. https://timharek.no/tags/tools/
|
||||
22. mailto:tim@harek.no?subject=RE: My thoughts on Helix after 6 months
|
||||
23. https://timharek.no/blog/2023-june-recently/
|
||||
24. https://timharek.no/stats/
|
||||
25. https://timharek.no/privacy/
|
||||
26. https://timharek.no/sitemap/
|
||||
27. https://timharek.no/rss.xml
|
||||
|
||||
Hidden links:
|
||||
29. https://timharek.no/
|
||||
30. https://timharek.no/blog/my-thoughts-on-helix-after-6-months/
|
||||
@@ -49,6 +49,12 @@ ul {
|
||||
}
|
||||
}
|
||||
|
||||
ol {
|
||||
margin-left: 3ch;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
blockquote {
|
||||
border-left: 1ch solid #ddd;
|
||||
font-style: italic;
|
||||
@@ -70,6 +76,7 @@ footer {
|
||||
|
||||
sup {
|
||||
line-height: 0;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
figure {
|
||||
@@ -90,7 +97,7 @@ figure {
|
||||
}
|
||||
}
|
||||
|
||||
.references {
|
||||
.references, .footnotes {
|
||||
font-size: 0.8em;
|
||||
|
||||
h3 {
|
||||
|
||||
Reference in New Issue
Block a user