FeoBlog
Client Older Posts

Deno Embedder

@Cody Casterline
2023-02-13 19:35:13 -0800

I've really been enjoying writing code in Deno. It does a great job of removing barriers to just writing some code. You can open up a text file, import some dependencies from URLs, and deno run it to get stuff done really quickly.

One nice thing is that Deno will walk all the transitive dependencies of any of your code, download them, and cache them. So even if your single file actually stands on the shoulders of giant( dependency tree)s, you still get to just treat it as a single script file that you want to run.

You can deno run foo.ts or deno install https://url.to/foo.ts and everything is pretty painless. My favorite is that you can even deno compile foo.ts to bundle up all of those transitive dependencies into a self-contained executable for folks who don't have/want Deno.

Well... almost.

This doesn't work if you're writing something that needs access to static data files, though. The problem is that Deno's cache resolution mechanism only works for code files (.ts, .js, .tsx, .jsx and more recently, .json). So if you want to include an index.html or style.css or image.jpg, you're stuck with either reading it from disk or fetching it from the network.

If you fetch from disk, deno run <remoteUrl> doesn't work, and if you fetch from the network, your application can't work in disconnected environments. (Not to mention the overhead of constantly re-fetching network resources every time your application needs them.)

In FeoBlog, I've been using the rust-embed crate, which works well. I was a bit surprised that I didn't find anything that was quite as easy to use in Deno. So I wrote it myself!

Deno Embedder follows a pattern I first saw in Fresh: You run a development server that automatically (re)generates code for you during development. Once you're finished changing things, you commit both your changes AND the generated code, and deploy that.

In Fresh's case, the generated code is (I think?) just the fresh.gen.ts file which contains metadata about all of the web site's routes, and their corresponding .tsx files.

Deno Embedder instead will create a directory of .ts files containing base64-encoded, (possibly) compressed copies of files from some other source directory. These .ts files are perfectly cacheable by Deno, so will automatically get picked up by deno run, deno install, deno compile, etc.

I'm enjoying using it for another personal project I'm working on. I really like the model of creating a single executable that contains all of its dependencies, and this makes it a lot easier. Let me know if you end up using it!

My New ASUS Router Wants To Spy On Me

@Cody Casterline
2023-01-26 19:15:12 -0800

After a recommendation from coworkers, and reading/watching some reviews online, I decided to get a new router. I purchased the "ASUS Rapture GT-AXE11000 WiFi6E" router in particular for its nice network analytics and QoS features.

On unpacking and setting up said router, I'm disappointed to find that the features I purchased the router for require that I give network analytics data over to a third-party.

image.png

The last line of that popup says:

If you would like to disable sharing your information with Trend Micro through the above functions, please go to: Router web GUI > Advanced settings > Administration > Privacy

For a brief few seconds I was naive enough to think that the issue was just that this behavior was opt-out instead of opt-in. So I headed over to the Privacy settings to opt out.

image.2.png

However, please note that such features/functions may not work if you stop sharing your information with Trend Micro.

"May not work" my ass! If you withdraw consent it just disables the features entirely, and then tells you:

image.3.png

Please note that users are required to agree to share their information before using [the features that I bought this router for].

At least now (after a couple router restarts to apply settings) they're telling the truth. This is not an "option", it's a requirement.

If I go back to the "Statistic" or "Bandwidth Monitor" tabs, they're now disabled:

image.4.png

image.5.png

I'm considering returning this router for one that won't try to spy on me. There is NO reason for this kind of thing in my home router, a device which should be prioritizing my own security and privacy. And certainly not for features like QoS or bandwidth usage monitoring.

Does anyone have recommendations? I want something that:

  • Has good network analytics so that when network issues occur, I can determine if it's due to one of my devices, or my ISP.
  • Good QoS (preferably one that can adjust to varying bandwidth availability throughout the day without me having to constantly toggle bandwidth caps)
  • Doesn't require consenting to third-party data collection.
@Cody Casterline
2023-01-20 09:38:04 -0800

I do not trust myself to write software without some form of type checking. And I prefer more typing (ex: nullability, generics) when it is available.

This comes from a long history of realizing just how many errors end up coming down to type errors -- some piece of data was in a state I didn't account for or expect, because no type system was present to document and enforce its proper states.

Relatedly, I trust other programmers less when they say they do not need these tools to write good code. My immediate impression when someone says this is that they have more ego than self-awareness. In my opinion, it's obvious which of those makes for a better coworker, teammate, or co-contributor.

@Cody Casterline
2023-01-13 18:31:38 -0800

Fixing your code before the weekend is like cleaning your house before you go on vacation. So much nicer to come back to. 😊

@Cody Casterline
2023-01-04 10:44:57 -0800

Me: I dislike that the usual software engineer career path is to move into management. I just want to write cooode!

Also me: (leading standup today, being taskmaster, making sure we capture details into tickets, unblock people, shuffle priorities from Product Mgmt, volunteering to help other devs w/ something they're stuck on) I am actually quite good at this.

😑

YAGNI

@Cody Casterline
2022-12-21 15:55:34 -0800

YAGNI. AIYAGNI,YWKWYNUYNI.

Not (Yet) Banned: FeoBlog

@Cody Casterline
2022-12-18 14:56:16 -0800

So Twitter came out with a great new feature today: You're not allowed to link to other social media web sites.

What is a violation of this policy?

At both the Tweet level and the account level, we will remove any free promotion of prohibited 3rd-party social media platforms, such as linking out (i.e. using URLs) to any of the below platforms on Twitter, or providing your handle without a URL:

  • Prohibited platforms:
    • Facebook, Instagram, Mastodon, Truth Social, Tribel, Post and Nostr
    • 3rd-party social media link aggregators such as linktr.ee, lnk.bio

It's a laughable attempt to stop the bleeding of people fleeing to other social networks, and it's going to Streisand Effect itself into the (figurative) Internet Hall of Fame. Most of the point of Twitter for many is finding and posting links to interesting stuff online.

What's next, a ban on "free promotion of prohibited 3rd-party news sources" that point out what a ridiculous policy this is? (Though, I suppose that's not far from what they're already doing -- banning reporters who unfavorably cover Musk.)

FeoBlog is not yet banned, of course, because it's not on anyone's radar. What can I do to get some more users and get it noticed?

If you want to give it a try, it's open source software, so you can download it and run your own server. Or, if you don't want to bother with all that, ping me and I'll get you set up with a free "account" on my server. :)

AWS Lambdas: WTF

@Cody Casterline
2022-12-15 18:14:27 -0800

I've used AWS's SQS at several companies now. In general, it's a pretty reliable and performant message queue.

Previously, I'd used SQS queues in application code. A typical application asks for 1-10 messages from the SQS API, receives the messages, processes them, and marks them as completed, which removes them from the queue. If the application fails to do so within some timeout, it's assumed that the application has crashed/rebooted/etc, and the messages go back onto the queue, to be later fetched by some other instance of the application.

To avoid infinite loops (say, if you've got a message that is actually causing your app to crash, or otherwise can't be properly processed), each message has a "receive count" property associated with it. Each time the message is fetched from the queue, its receive count is incremented. If a message is not processed by the time the "maximum receive count" is reached, instead of going back onto the queue, it gets moved into a separate "dead-letter queue" (DLQ) which holds all such messages so they can be inspected and resolved (usually manually, by a human who got alerted about the problem).

That generally works so well that today we were quite surprised to find that some messages were ending up in our DLQs despite the fact that the code we had written to handle said messages was not showing any errors or log messages about them. After finally pulling in multiple other developers to investigate, one of them finally gave us the answer, and it came down to the fact that we're using Lambdas as our message processor.

So here's the issue, which you'll run into if:

  • you use a lambda function to process SQS messages
  • you set a reserved concurrency to limit that lambda's concurrency

Whatever Amazon process feeds SQS messages into that lambda will fetch too many messages. (I'm not sure if there's a way to tell if it was in a large batch, or lots of individual fetches in parallel, but either way the result is the same.)

Every time it does this, it increments the messages' receive counts. And of course when they reach their max receive count, they go to the DLQ, without your code ever having seen them.

This happens outside of your control and unbeknownst to you. So when you get around to investigating your DLQ you'll be scratching your head trying to figure out why messages are in there. And there's no configuration you can change that fixes it. Even if you set the SQS batch size for the lambda to 1.

If you think you might be running into this problem, check two key stats in the AWS console: the "throttle" for the lambda, and the DLQ queue size. If you see a lambda that suddenly gets very throttled which correlates with lots of messages ending up in your DLQ, but see no errors in your logs, this is likely your culprit.

It seems crazy that it works this way, and seemingly has for years. AWS's internal code is doing the wrong thing, and wasting developer hours across the globe. Ethically, there's also the question of whether you're getting billed for all of those erroneous message receives. But I'm mostly worried about having a bad system that is a pain in the ass to detect to work around.

Time Travel

@Cody Casterline
2022-12-15 14:59:57 -0800

Me, minutes before a meeting: Just one more line. One more line of code.

(15 minutes later, seeing a clock): Dangit, I'm late for my meeting.

Habits

@Cody Casterline
2022-12-14 13:05:27 -0800

Me: "Why do I put the cap back on my water bottle after every sip? This is annoying even to myself."

Also me: Knocks over the full bottle I just minutes before had placed between me and my keyboard and yet had somehow forgotten existed.

(Thankfully, the cap was on! 😆)

FeoBlog & Deno

@Cody Casterline
2022-12-13 23:48:53 -0800

For a while I'd been maintaining 2 versions of the FeoBlog TypeScript client:

  • The "main" one, in Node.js, used by the web UI.
  • A port of that code to Deno.

But maintaining two codebases is not a great use of time. So now the Deno codebase is the canonical one, and I use DNT to translate that into a node module, which I then import into the FeoBlog UI, which you are probably using right now to read this post. :)

A Phone Number is a Liability

@Cody Casterline
2022-12-12 13:10:04 -0800

Is it weird that I'm starting to feel like having a phone number is not worth it?

First, I use actual phone conversations VERY rarely. If I'm home and want to have a voice conversation with someone, I usually use VoIP (usually: FaceTime Audio) because it has higher quality than cell phone calls. If I'm out and about and want to communicate meeting time/place with someone, I'm going to send (or expect) a text message. So there's the question about whether it's worthwhile continuing to pay for a service that I don't use.

But the real problem is that modern apps and online services use your phone number as if it's a unique ID. If you give some organization your phone number, they'll definitely use it to uniquely identify you. Possibly to third parties.

And, even if you don't give them your phone number directly, since apps can slurp your contact info from any of your friends' contact lists, they've still got it.

And if companies can store this data about you, that data can get hacked and leaked. "HaveIBeenPwned" recently added phone numbers to their search because it's become such a concern.

If you worry about giving out your Social Security number, you should probably worry just as much about giving out your phone number. To companies or your friends.

This doesn't even touch on the problem of spam/phishing/fraudulent calls, which is another real problem w/ the phone system.

So, despite having the same phone number since 1998, I'd love to get rid of mine. Unfortunately, I can't yet because so many systems (ex: banks, messaging apps) do use it to identify you.

Plus, imagine you give up (or just change) your phone number. Now your old number is available for re-use. If someone were to claim it, they could then use it to impersonate you on any systems that haven't been updated with your new (lack of) phone number.

Happy Thanksgiving

@Cody Casterline
2022-11-24 02:30:44 -0800

I’m thankful for when the cat comes and gets me to come to bed, as if to say: “uh? Hey. I’m sleepy and I need some warm legs to curl up on. Can you get in bed already?” ❤️

Twitter

@Cody Casterline
2022-11-14 16:43:03 -0800

So recently Elon has:

  • Removed twitter identify verification (blue checkmarks are now meaningless?)
  • Shut down 2FA
  • Removed the information about what app someone tweeted from.

It sure is starting to seem like he paid a lot of money to delegitimize it as a communication platform.

Guess you can't get "cancelled" if people and bots are indistinguishable.

@Cody Casterline
2022-11-05 03:39:54 -0700

The weather finally got decently cold and we turned on the heat in the new house. Woke up at 3:15am broiling in my own bed. It turns out the previous owner had programmed the thermostat to go up to 75°F at some point in the night.

75!? I barely let the house get that warm during the summer! So I’m currently in the living room with the sliding door to the back patio cracked so I can cool off. 🥵

IDE Inlay Hints

@Cody Casterline
2022-10-27 21:09:37 -0700

Am I weird in disliking inlay hints?

They're those little notes that your IDE can add to your code to show you what types things are, but they're not actually part of your source code. For an example, see TypeScript v4.4's documentation for inlay hints.

My opinion is that:

  • for well-written code, they fill my screen with redundant noise that makes it more difficult to see the simple code in front of me.
  • for poorly-written code, they're a crutch that you can rely on instead of refactoring the code to be more readable and less fragile.

As an example, take this code:

function main() {
    console.log(foo("Hello", "world"))
}

// Imagine this function is in some other file, so it's not on the same screen.
function foo(target: string, greeting: string) {
    return `${greeting}, ${target}!`
}

If you're looking at just the call site, there's a non-obvious bug here because the foo() function takes two arguments of the same type, and the author of main() passed them to foo() in the wrong order.

Inlay hints propose to help with the issue by showing you function parameter names inline at your call site, like this:

function main() {
    console.log(foo(target: "Hello", greeting: "world"))
}

(target: and greeting: are added, and somehow highlighted to indicate that they're not code.)

Now it's more clear that you've got the arguments in the wrong order. But only if you're looking at the code in an IDE that's providing those inlay hints. If you're looking at just the raw source code (say, while doing code review, or spelunking through Git history), you don't see those hints. The developer is relying on extra features to make only their own workflow easier.

Without inlay hints, it's a bit more obvious that, hey, the ordering here can be ambiguous, I should make that more clear. Maybe we should make foo() more user-friendly?

Lots of languages support named parameters for this reason. TypeScript/JavaScript don't have named parameters directly, but often end up approximating them with object passing:

function foo({target, greeting}: FooArgs) {
    return `${greeting}, ${target}!`
}

interface FooArgs {
    target: string
    greeting: string
}

Now the call site is unambiguous without inlay hints:

foo({greeting: "Hello", target: "world"})

And, even better, our arguments can be in whatever order we want. (This syntax is even nicer in languages like Python or Kotlin that have built-in support for named parameters.)


The prime use of these kinds of hints is when you're forced to use some library that you didn't write that has a poor API. But IMO you're probably still better off writing your own shim that uses better types and/or named parameters to operate with that library, to save yourself the continued headache of dealing with it. Inline hints just let you pretend it's not a problem for just long enough to pass the buck to the next developers that have to read/modify the code.

Is Windows 11 Just This Slow?

@Cody Casterline
2022-10-01 11:44:08 -0700

I have a desktop gaming machine that runs Windows 11. It's not bad at games but it's so slow at things like, opening apps, opening settings, etc.

Is Windows 11 just this slow, or is something wrong?

It's so bad that I ran winsat formal to see if my nvme "hard drive" was somehow misconfigured:

image.png

Results:

> Run Time 00:00:00.00
> Run Time 00:00:00.00
> CPU LZW Compression                          1139.80 MB/s
> CPU AES256 Encryption                        15057.26 MB/s
> CPU Vista Compression                        2834.34 MB/s
> CPU SHA1 Hash                                10656.56 MB/s
> Uniproc CPU LZW Compression                  100.19 MB/s
> Uniproc CPU AES256 Encryption                986.78 MB/s
> Uniproc CPU Vista Compression                250.19 MB/s
> Uniproc CPU SHA1 Hash                        774.01 MB/s
> Memory Performance                           29614.11 MB/s
> Direct3D Batch Performance                   42.00 F/s
> Direct3D Alpha Blend Performance             42.00 F/s
> Direct3D ALU Performance                     42.00 F/s
> Direct3D Texture Load Performance            42.00 F/s
> Direct3D Batch Performance                   42.00 F/s
> Direct3D Alpha Blend Performance             42.00 F/s
> Direct3D ALU Performance                     42.00 F/s
> Direct3D Texture Load Performance            42.00 F/s
> Direct3D Geometry Performance                42.00 F/s
> Direct3D Geometry Performance                42.00 F/s
> Direct3D Constant Buffer Performance         42.00 F/s
> Video Memory Throughput                      279385.00 MB/s
> Dshow Video Encode Time                      0.00000 s
> Dshow Video Decode Time                      0.00000 s
> Media Foundation Decode Time                 0.00000 s
> Disk  Sequential 64.0 Read                   4159.90 MB/s          9.5
> Disk  Random 16.0 Read                       1007.15 MB/s          8.8
> Total Run Time 00:00:11.67

When it can read a Gagabyte per second when doing random access, I don't think the disk is the problem. The CPU is an "AMD Ryzen 7 3700X 8-Core Processor" at 3.59 GHz, which also shouldn't be a problem.

Anybody have tips beyond "LOL don't run Windows"?

FeoBlog Upgrades

@Cody Casterline
2022-09-25 22:23:45 -0700

Well, I started this morning fixing a minor bug in FeoBlog. But then the GitHub Action build failed which sent me down a day-long rabbit hole that ended up with me upgrading from ActixWeb v3 to v4.

It's a bit disappointing because Rust is in theory not supposed to break backward compatibility. But I guess some bits of their API leaked and then got used by libraries I was using.

Not really what I had planned for my Sunday but glad to be on newer versions of things, I guess? 😅

@Cody Casterline
2022-08-25 15:40:08 -0700

Me: You should remain professional and avoid burning bridges.

Facebook recruiter: Hi! Want to use ML to moderate virtual social spaces?

Me: On second thought, …

Fresh Looks Cool!

@Cody Casterline
2022-05-17 23:58:45 -0700

When Node became popular, I never understood the hype around server-side JavaScript, other than that it took what had before then been mostly client-side and making it usable on the server.

But the pitfalls of writing large systems on the server without type checking seemed too great. And I wasn't that fond of JavaScript at the time.

By the time I got around to playing with Node more seriously, TypeScript was a thing. In FeoBlog I wanted to write a browser-based client that would both be a nice UI and a great demo of the client/server capabilities of the system. I chose Svelte as my UI toolkit, and I very much enjoy the features it offers. However, bundling JavaScript for the browser is still a pain to get working. And if you ship everything as a Single-Page Application, you lose out on indexing, and old/underpowered browsers.

FeoBlog actually has remnants of an early server-side template system which it falls back on for that purpose, but you lose out on a lot of features, and it's lost parity with the new Svelte UI. It would be nice if I could write code once and have it render on the server OR the client.

So now I'm starting to see the appeal of server-side JS. But... I don't really want to run Node. Thankfully there's Deno, which I've already enjoyed writing some scripts for.

AND, there's a cool new web framework called Fresh. It's got the same super-fast dev cycle that I've enjoyed with Deno, and the result is code that can render things on the server OR client.

If you want to see a(n incidental) demo of Fresh, take a look at Deno Deploy: Crazy Fast Cloud Functions - Architecture Speedun, which is where I first discovered it.

Looking forward to see where this goes!