How to Use //go:embed

Update: Want to listen to a podcast about go:embed instead of reading a blog post? Check out Go Time episode 171.

简体中文版 by 涛叔 Tao Shu

I have previously written about how to use //go:generate. It exists to “to automate the running of tools to generate source code before compilation.” Now there is a new feature in Go that eliminates many uses of source code generation. In addition to the remarkable new flag.Func feature, Go 1.16 also introduced a new //go:embed directive that allows you to include the contents of arbitrary files and directories in your Go application. To demonstrate some of the capabilities of //go:embed, I have made an example repo which I will explain in this post.

The basic idea of embedding is that by adding a special comment to your code, Go will know to include a file or files. The comment should look like //go:embed FILENAME(S) and be followed by a variable of the type you want to embed: string or []byte for an individual file or embed.FS for a group of files. The go:embed directive understands Go file globs, so patterns like files/*.html will also work (but not **/*.html recursive globbing).

You can read the official docs for a complete technical explanation, so here let’s take a look at some examples to see what’s possible.

Read more…

Adding Some Func to Go’s Flag Package

Go 1.16 is shaping up to be one of the most exciting releases of Go in recent memory. Among its new features is the //go:embed directive and the reorganization/deprecation of io/ioutil. It’s not due out until February 2021 (Edit: it came out Feb. 16, 2021), but now I would like to write about a minor change to the standard library flag package that might otherwise be missed in the sea of changes:

The new Func function allows registering a flag implemented by calling a function, as a lighter-weight alternative to implementing the Value interface.

I proposed and implemented flag.Func. I have made minor contributions to the Go project before, but this is the first time I’ve added a whole top level function to the standard library, so I’d like to explain a little about what it does and the process of getting it accepted into the Go standard library.

Read more…

Dropping Support For IE11 Is Progressive Enhancement

TL;DR if you have to choose, you should prioritize users with no JavaScript over users with old JavaScript.

If you’re a web developer working today, it’s probably long passed time for you to stop transpiling your modern JavaScript into ES5 for Internet Explorer. Any time or effort spent getting your JavaScript working in IE11 is wasted time that could be better spent making a better experience for users without JavaScript. Moving your resources from Internet Explorer to users without JavaScript will let you improve the SEO and accessibility of your site while providing a better experience for everyone.

First, some notes about who this advice is for: I am assuming you’re working for a small team with no Quality Assurance testing department making a content focused site. If you have a large team that actually QA tests IE11, this advice may not apply to your situation. If you’re just doing personal projects for fun, you should have already dropped ES5 years ago. If you’re making more of an app than a content site, you probably should have cut off IE11 years ago, but the calculations are more complex and site specific.

Read more…

Link: Lea Verou · The failed promise of Web Components

The promise of Web Components was that we’d get this convenience, but for a much wider range of HTML elements, developed much faster, as nobody needs to wait for the full spec + implementation process. We’d just include a script, and boom, we have more elements at our disposal!

Or, that was the idea. Somewhere along the way, the space got flooded by JS frameworks aficionados, who revel in complex APIs, overengineered build processes and dependency graphs that look like the roots of a banyan tree.

I think the issue is deeper than Verou’s complaints, although those are valid. Web Components don’t actually to solve the problem they purport to solve. The pitch is “get semantic elements from across the web!” But those are wrong problems to try to solve.

Read more…

Creating Domain Specific Error Helpers in Go With errors.As

The other day, I was reading a website about some historical documents, when I saw that it had an error message on top:

Screenshot of a WordPress site with an error message

Screenshot from the site

Some quick searching online for the error message revealed that it was caused by a mismatch between the site’s versions of PHP and WordPress. Older versions of WordPress had a bug in the switch statement of a certain localization component, and later versions of PHP dump a warning about this bug out to the end user HTML. When I came back to the site a few days later, it had been fixed.

The ultimate reason for my seeing for the error message as a random reader is that PHP has too many ways to deal with errors:

Builtin PHP functions, and therefore any PHP project, have a whole range of error handling mechanisms — errors, warnings, returning error values, and exceptions. At every point, calling code needs to know which system will be used to handle errors.

PHP often chooses to send warnings like this right out to the end user because it doesn’t trust operators to actually read their Apache logs. Such a practice would be very out of place in the Go programming language.

Read more…

Link: Rachel by the Bay · Tripping over the potholes in too many libraries

In short, I think it’s become entirely too easy for people using certain programming languages to use libraries from the wide world of clowns that is the Internet. Their ecosystems make it very very easy to become reliant on this stuff. Trouble is, those libraries are frequently 💩. If something about it is broken, you might not be able to code around it, and may have to actually deal with them to get it fixed.

Repeat 100 times, and now you have a real problem brewing.

I have a simple rule: never use a dependency that you could replace with an afternoon of programming.

Read more…

Heidegger, Cookies, and NoSQL

Life with a toddler is always a strange combination of charming, frustrating, philosophical, exhausting, and funny. The other night, my wife tried to give my daughter a cookie. “Cut, cut!” my daughter said. So, my wife took the cookie and cut it in half. “No, no, no!” cried the toddler. “Okay, which one?” said wife, holding out a whole cookie in one hand and the half cookie in the other. “Two!” said the toddler, grabbing a cookie with each hand. She was finally happy.

But I couldn’t help but notice. “You don’t have two,” I said. “You have one and a half.” Naturally, she ignored me.

Read more…

Writing Go CLIs With Just Enough Architecture

As someone who has written quite a few command line applications in Go, I was interested the other day when I saw Diving into Go by building a CLI application by Eryb on social media. In the post, the author describes writing a simple application to fetch comics from the XKCD API and display the results. It looks like this:

$ go-grab-xkcd --help

Usage of go-grab-xkcd:
  -n int
        Comic number to fetch (default latest)
  -o string
        Print output in format: text/json (default "text")
  -s    Save image to current directory
  -t int
        Client timeout in seconds (default 30)

I came away a little disappointed though because I felt like the final result was both a little undercooked and a little overcooked: undercooked in that it didn’t handle errors robustly enough and overcooked in that it created some abstractions speculatively in a way that I felt were unlikely to pay off in the long run.

Naturally, one thing lead to another, and I forked and rewrote the demo app myself to demonstrate what I consider to be just enough architecture for a Go command line app.

Read more…

Link: Reddit · Why does all() return True if the iterable is empty?

The other day on Reddit someone asked this:

Why does all() return True if the iterable is empty? Shouldn’t it return False just like if my_list: would evaluate to False if the list is empty? What’s the thinking behind it returning True?

They have since removed their question, but it sparked a long discussion thread, and my comment was heavily upvoted, so I thought I would record it here:

This is literally a 2,500 year old debate in philosophy. The ancients thought “all unicorns are blue” should be false because there are no unicorns, but modern logic says it is true because there are no unicorns that aren’t blue. Python is just siding with modern predicate logic, but your intuition is also quite common and was the orthodox position until the last few hundred years.

Read more…