Archive for the ‘Uncategorized’ Category

Lil’ Thought Blasters About Mastodon

Monday, November 14th, 2022

Screenshot of Arc browser with Pinafore open on the right, and a CSS editor on the left styling it.

It’s Official 💨

Sunday, November 13th, 2022

Pleased that FART (Flash of inAccurate coloR Theme, lol) has become:

… officially a term of art in computer science.

Because it’s a part of Chrome Platform Status as a feature of Client Hints. Indeed, prefers-color-scheme is a perfect thing for Client Hints.

… it is a best practice to not load CSS for the particular non-matching color scheme in the critical rendering path, and instead to initially only load the currently relevant CSS.

No FART if the server only returns CSS matching your preferred theme (right away, anyway). Client Hints is the mechanism that tells the server that preference so it can respond accordingly.

Speaking of folk interfaces

Saturday, November 12th, 2022

I was at a charity dinner with an auction tonight.

Clearly they couldn’t figure out how to put instructions into the system anywhere anybody could find. So they made “items” in the CMS and made them $1.

I’m pleased to have won the “how to register” item for $3.

The Nightmare Before Christmas Before The Nightmare Before Christmas

Saturday, November 12th, 2022

The movie goes:

  1. Some man who has had some success running other things has a twinkle in his eye to run another thing.
  2. He takes it over on a whim with some seriously questionable tactics.
  3. Smart people that he should really listen to tell him it’s a bad idea but he completely ignores it and alienates them.
  4. He does a terrible job running the new thing and hurts people in the process.
  5. In the end he’s like “oh wait that was a dumb idea”, credits nobody else for being right, and is welcomed warmly back because he’s a powerful man.

Sounds familiar I dunno.

Jack Skellington from The Nightmare Before Christmas handing a young boy a present. Elon Musk's face is overlaid onto Jack's face.

Personal Coding Challenge: Data Validation, Correction, and Default Handling

Saturday, November 12th, 2022

Say you have some JSON data like this (I’ll be using Go on purpose here):

jsonString := `{ "number": "1600", "street_name": "Pennsylvania", "street_type": "Avenue" }`
Code language: JSON / JSON with Comments (json)

The challenge here is to build a machine that does four things:

  1. Validate that the JSON is valid syntax.
  2. Validate that the JSON is valid against a schema.
  3. If there is a problem with one part of the data, first attempt to fix it (see how the value for "number" is "1600", that’s a basic mistake, try to coerce it into an int of 1600).
  4. If that part of the bad data cannot be coerced, or if it’s invalid even after it is, fall back to a default value.

1) Validation is fairly easy.

Go standard lib can do it.

jsonString := `{ "number": "1600", "street_name": "Pennsylvania", "street_type": "Avenue" }` isValid := json.Valid([]byte(jsonString)) if isValid { fmt.Println("JSON data is valid in most basic sense.") } else { fmt.Println("ERROR! String is not valid JSON.") }
Code language: Go (go)

2) Validation against schema can be done with a lib.

I don’t know if this is the only option, but gojsonschema works.

jsonString := `{ "number": "1600", "street_name": "Pennsylvania", "street_type": "Avenue" }` schema := gojsonschema.NewStringLoader(`{ "type": "object", "properties": { "number": { "type": "number" }, "street_name": { "type": "string" }, "street_type": { "enum": ["Street", "Avenue", "Boulevard"] } } }`) json := gojsonschema.NewStringLoader(jsonString) result, err := gojsonschema.Validate(schema, json) if err != nil { panic(err.Error()) } if result.Valid() { fmt.Printf("The document is valid\n") } else { fmt.Printf("The document is not valid. see errors :\n") for _, desc := range result.Errors() { fmt.Printf("- %s\n", desc) } }
Code language: Go (go)

3) Fixing theoretically easy to fix data

Here’s that original JSON again:

jsonString := `{ "number": "1600", "street_name": "Pennsylvania", "street_type": "Avenue" }`
Code language: Go (go)

And note in the schema, we’re expecting a number: "number": { "type": "number" }. If we ran the validation in Step 2 above, we’d get:

> make run
go build -o main .
./main
The document is not valid. see errors :
- number: Invalid type. Expected: number, given: string

So that’s true for schema validation, but it would also be true if we tried to json.Unmarshal the data into a struct with strict types (which we definitely do). So in addition the schema, we have a type which is also kind of a schema.

type address struct { Number int `json:"number"` StreetName string `json:"street_name"` StreetType string `json:"street_type"` }
Code language: Go (go)

If we tried to parse the JSON now, we’d get a similar error to the schema checking:

var add address err := json.Unmarshal([]byte(jsonString), &add) if err != nil { fmt.Println(err) }
Code language: Go (go)
> make run
go build -o main .
./main
json: cannot unmarshal string into Go struct field address.number of type int

The hope is that there is a way to run some kind of callback function to try to coerce the problematic bit of data into something that is valid. So "1600" is so obviously just incorrectly a string, the callback would force it into an int and all would be well.

This is where I’m kinda stuck, and will update this post when it’s figured out.

Update: You can provide Unmarshaling instructions for custom types

This article was very helpful.

Rather than an int like you want it, call it something else:

type FlexInt int type FlexAddress struct { Number FlexInt `json:"number"` StreetName string `json:"street_name"` StreetType string `json:"street_type"` }
Code language: Go (go)

Now as Marko Mikulicic says:

All you have to do is implement the json.Unmarshaler interface.

So:

func (fi *FlexInt) UnmarshalJSON(b []byte) error { if b[0] != '"' { return json.Unmarshal(b, (*int)(fi)) } var s string if err := json.Unmarshal(b, &s); err != nil { return err } i, err := strconv.Atoi(s) if err != nil { return err } *fi = FlexInt(i) return nil }
Code language: Go (go)

This is awfully clever I think.

  1. It checks the first character of the value of the FlexInt and if it’s not a double-quote mark (like is required for a JSON string), then assume its an int and Unmarshal it that way.
  2. Then try to Unmarshal it as a string and return that if it works
  3. Then try to coerce it into an int and if that works, great
  4. Errors returned if nothing seems to work (could always try accounting for more situations)

So this handles trying to fix decently-easy-to-fix JSON type errors, and also gives an opportunity to just return some kind of default value if every attempt at fixing it fails.

4) Default / Fallback Values

One issue here is where to put the fallback values. If we know we’re exclusively dealing with JSON data, it seems like the JSON schema would be the place. That can look like:

{ "type": "object", "properties": { "number": { "type": "number", "default": 1000 }, "street_name": { "type": "string" }, "street_type": { "enum": ["Street", "Avenue", "Boulevard"] } } }
Code language: JSON / JSON with Comments (json)

But the trouble here is that by the time we’re parsing/unmarshaling the data, that’s in Go, so we’d have to somehow come back to the schema and parse that and pluck the data out to use. Just seems weird.

Maybe we’ll have to do Step 3, then if we find the data to be unfixable, remove it, then run it back through a JSON schema situation where it puts default values back into the parsed data. Again something I don’t really know how to do, but seems plausible. Plus it does double duty. I would think this machine would optionally be able to put in default values. Not always, sometimes missing fields are better, but it could put in defaults on command.

Bonus: Not just JSON

I think JSON is the primary use case here, but not all data is passed around as JSON. Perhaps this machine could do the same kind of thing for data that is already in Go. Step 1 becomes irrelevant (Go code will just choke on invalid syntax), but the rest still matter. Can a struct have a schema with allowed values? So not just int but an int with min and max? Not just a string but a string with a valid set of ENUM values. Seems like that should be no huge problem. Can a struct with a value outside what the schema allows be fixed or reverted to a default value? Hopefully?

In this case, wouldn’t it make more sense to put the default values in the type definition rather than a JSON schema, so like this NOT REAL code:

type address struct { Number int `json:"number",default:1000` StreetName string `json:"street_name"` StreetType string `json:"street_type"` }
Code language: JavaScript (javascript)

Then if you need JSON schema also, you could generate it from this type? I’m already out of my depth here and this is doubly so, but also seems possible.

The Difference Between Integration Testing and End-to-End Testing

Friday, November 11th, 2022

I don’t think there is any doubt that this is a unit test:

function sum(a, b) { return a + b; } test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
Code language: JavaScript (javascript)

You have a function, and you’re testing that the function returns what you think it should return. A code base probably has lots of this as they are easy to write, useful, and not flakey.

I also don’t think there is any doubt about what an end-to-end test is. The quintessential end-to-end test is like “go to this URL, fill out this form, click the submit button, and see if the right thing happens. Cypress is king here.

it('adds todos', () => { cy.visit('https://todo.app.com') cy.get('[data-testid="new-todo"]') .type('write code{enter}') .type('write tests{enter}') // confirm the application is showing two items cy.get('[data-testid="todos"]').should('have.length', 2) })
Code language: JavaScript (javascript)

Unit and end-to-end tests are the extremes on two sides of a spectrum. On the left, unit tests, little itty bitty sanity testers. On the right, end-to-end tests, big beefy (cough; sometimes flakey) tests that prove that lots and lots of systems are working together as intended and what a user experiences is in good shape. Even though the amount of code in the test isn’t super different, what is being tested is wildly different.

I think integration tests are a dot somewhere in the middle of that spectrum.

Integration tests combine multiple systems in your app. API tests seem like a quintessential example to me. You could certainly unit test parts of an API, but tests that use the API as you would actually interact with it in your web app are the juicy onces. Meaning combining multiple systems. Integrating systems, as it were.

Say your API is in GraphQL and your front end uses Apollo Client to interact with it. An integration test could be…

  1. In JavaScript…
  2. Spin up Apollo and have it connect to the same GraphQL server the current environment uses (dev, staging, prod, etc)
  3. Write a query and/or mutation that hits the API and does something
  4. Test what you get back
  5. … in Jest or whatever.

Now you’re testing a limited set of multiple systems and that’s an integration test.


Highly related:

Nobody Gets Hurt Doing Their One-Rep Maxes*

Thursday, November 10th, 2022

Says my physical therapist.

I hurt my back most recently doing back squats. 135lbs on the bar. That’s nothing for my big elephant legs. It was my third rep of what was going to be 60 reps over 15 minutes as part of an EMOM (Every Minute on the Minute) workout involving box step-ups as well.

I was hurrying to start the reps as the gym was waiting for me to start. I treated the weight too casually. I didn’t brace up. Tighten my core and glutes. Bend that bar.

That’s what you do when you’re going for a one-rep max, you are psychologically and physically braced to do it. You go into it with the right prep. That’s safe. Loosey goosey = not safe.


* I’m sure plenty of people have hurt themselves doing one-rep maxes. I just like the thinking here.

Two Quick Things I learned about JSON in Go

Thursday, November 10th, 2022

One.

You don’t have to json.Unmarshal into an empty struct. I learned with examples like this:

type Post struct { FavoriteCount int `json:"favorite_count"` ID string `json:"id"` FullText string `json:"full_text"` } exampleJSON := []byte(`{ "id": "098a9df8a90d8fad", "full_text": "Blah blah blah." }`) var post Post err := json.Unmarshal(exampleJSON, &post) if err != nil { fmt.Println(err) }
Code language: Go (go)

There, post is totally defaults, meaning because favorite_count was missing in the JSON data, post.FavoriteCount defaults to 0, the Go default value for an int. But it doesn’t have to start that way! You can Unmarshal it into a variable of that type that isn’t all default values.

post := Post{ FavoriteCount: 5, } err = json.Unmarshal(exampleJSON, &post) if err != nil { fmt.Println(err) }

Now even though the JSON data is still missing favorite_count, the post.FavoriteCount value will be 5. Useful!

And surprising to me, as a language that doesn’t have much in the way of convience methods. Like there certainly is no ...spread like JavaScript, and this feels a smidge like spreading.

Here’s a thing on Replit.

Another thing I need to learn is how to deal better with Unmarshaling data into a struct where the JSON data could be wrong. With the default json.Unmarshal it just totally fails, and so far I’ve worked around it with really permissive temporary types that use a bunch of interface{} shit and coercing it later. But I’d rather use a strict type and deal with it on the spot. I hear userland libs like mapstructure and fastjson can maybe help here.

Two.

Sometimes JSON is all like…

{ "things": {[ "thing: { } ]} }
Code language: JSON / JSON with Comments (json)

And sometimes JSON is all like:

[{ "thing": { } }]
Code language: JSON / JSON with Comments (json)

I was somehow under the wrong impression that the first example was somehow better. It might be in some cases, like where you might use like things_v2 as an opportunity to “version” the JSON, but generally, I actually think the second example is cleaner.

The second is also easier to deal with in Go, as you don’t need an additional “parent” type to deal with “things”. You can just make the main type a []slice and it knows what it’s looking for will be an array in the JSON then.

type testURL struct { Title string `json:"title"` Value string `json:"value"` } exampleJSON := []byte(`[ {"title": "Homepage", "value": "https://nextjs.org/"}, {"title": "GitHub", "value": "https://github.com/vercel/next.js/"}, {"title": "Docs", "value": "https://nextjs.org/docs"} ]`) var allURLs []testURL err := json.Unmarshal(exampleJSON, &allURLs) if err != nil { fmt.Println(err) }
Code language: Go (go)

Here’s a Replit thing.

Dan’s Book: Twenty Bits I Learned About Making Websites

Wednesday, November 9th, 2022

I got a copy of Dan’s latest book!

So many endearing, funny, and relatable bits. From Chapter 4:

As soon as I typed the HTML for my first hyperlink, the power of it hit me. This is the DNA of the web, the fabric that connects all of the bits and pieces all over the globe. It sounds so primitive now, but when this was ll new to me and I was disocvering how it all worked and how simple it was to create links, it was magic.

It’s still magic! URLs are one of mankind’s greatest achievements. It took a lot for them to exist, and now that they do, they have literally advanced civilization. They are the ultimate unbeatable feature.


Couldn’t agree more with Chapter 5. Couldn’t agree more with Chapter 19. Love love Chapter 9. He’ll get ya with Chapter 8 though, them’s a doozy — real Secret of Life stuff there.

Icon Set Nostolgia

Wednesday, November 9th, 2022

I think Daniel Bruce’s Entypo was the first icon set designed for the web that I fawned over.

Screenshot of Entypo+ homepage which is mostly just big grid of small white vector icons on dark gray.

Maybe it was how it had a cool name, almost like it was a startup product. And the website design around it was awesome. The 2012 design was pretty fresh, especially for that time:

Screenshot of 2012 Entypo.com homepage. Large dark banner showcasing the shopping bag, trash, search (flashlight), and archive (file drawer) icons. The Entypo logo is slightly 3D looking casting a shadow over the header.

Then a 2014 update:

The 2014 Entypo.com website this time with a large green header and showcasing a similar set of large icons. Two large blue buttons for Download Package and Character map. The rest of the page is small black icons on a white background.

Alas, they are no more. The link to download them leads to a broken Dropbox link.

Screenshot of an Error (403) page on Dropbox.com, signaling the file doesn't exist.

Maybe even a smidge earlier than Entypo, Drew Wilson’s Pictos was also massively cool. This was circa 2012:

Screenshot of homepage for Pictos.css. Mostly a large grid of black icons on a grungy white background. Each row of icons has grungy dashed lines through it showing off how aligned the icon features are.

Pictos modernized into a fancy set that included line, solid, and color, which to this day is pretty cool and unique for an icon set to offer:

Screenshot of revamped Pictos website howing off the line, shape, and color variations of 8 of the icons from the set.

But alas:

Default Chrome "This site can't be reached" page.

You cannot get it as Plasso, the payments startup that was also done by Drew, is no more.


Bit rot, kids. Happens to the best of them.

A Brief and Probably Only Partially Correct History of CSS Nesting

Wednesday, November 9th, 2022

I’m really not sure where it is now! I imagine one of them will win here (soon?), then the spec gets finalized, then the browser implementations get fixed up, then we really start thinking and talking about it. Q1 2023?? Let’s go!

Local By Flywheel has Fancy Headless WordPress Scaffolding

Tuesday, November 8th, 2022

Local By Flywheel makes running a local WordPress site trivially easy. I just got a marketing email from them saying that there is a plugin for Atlas now, which is their parent company WP Engine’s product for running “Headless” WordPress. Headless, meaning the front-end of the site isn’t HTML produced from PHP directly, it’s some other kind of front-end that digests content from WordPress via API.

I didn’t really know what supporting Atlas really means, so I just gave it a shot. First, you gotta add and activate it as a plugin:

Now you’ll have some Atlas-powered “Blueprints” available when you spin up a site:

Spinning it up the first time will install some extra stuff, as to be expected. Once it is spun up, you’ll see in Local it’s not just running the PHP, MySQL, and Nginx stuff, but there is a whole section just for the Node.js front end too.

And you got a site!

This website is VERY different from how you’d “normally” build a WordPress website. It’s literally Next.js, so it’s React-powered, and it looks like it grabs the data with GQty, a GraphQL client. That weirded me out because I was like… WordPress’ API isn’t GraphQL by default. But that’s part of the Blueprint! It installs and activates WP GraphQL by default.

This is some fancy shit I tell you what!!!

Part of me is like… ugh, but this is a lot of technology to maintain. I wouldn’t do it for anything that doesn’t really need it. The homepage has like 4 MB of JavaScript by default 😭. That’s a development build but still, cripes.

But another part of me is like… I would probably enjoy working on a serious product with this stack. Because two things:

I just don’t like how this isn’t quite a first-class citizen situation from either side.

« Older Entries