More Map Utilities

 — 

A few weeks back I wrote about Maps and how MapUtils.isEmpty from Apache Commons Collections made the null-checks go away with isEmpty. Since then, I've been poking around the rest of MapUtils and it turns out the isEmpty method is not the only goodie hidden in there. MapUtils also has getter methods that are arguably even more useful, especially in a codebase where pretty much everything is a Map<String,Object>, for better or for worse (ok, probably for worse).

Here's the pattern I've been untangling lately:

// this is messy, since we always use Map<String,Object>
String myString = (String) myMap.get("someKey");

That cast is doing a lot of quiet work: it assumes the key exists, that the value is non-null, and that it's actually a String. Any one of those assumptions failing gives you a NullPointerException or a ClassCastException at runtime.

The first improvement I reached for is in the standard Map interface: getOrDefault:

// this is what I have been doing, to fix the NPEs
String myString = (String) myMap.getOrDefault("someKey", "");

This is somewhat better, I mean at least now missing keys don't blow up. But the cast is still there, and if some upstream code stuck an Integer in that slot, I still get a ClassCastException.

Enter MapUtils.getString:

// but this is better
String myString = MapUtils.getString(myMap, "someKey");

No casting at all! It handles the type coercion for me, and if the key is missing or the map is null, it returns null instead of throwing an exception. And of course, you can supply a default:

// but this is even better, because it saves the null
String myString = MapUtils.getString(myMap, "someKey", "");

Now I've got a one-liner that handles a null map, a missing key, a null value, and a value of the wrong type, without a cast and without a chain of if statements.

And it's not just getString. There's a whole family: getInteger, getLong, getBoolean, getDouble, getMap, and so on, and each has a default-value overload. If you live in Map<String,Object> land, these will save you a lot of defensive code.

What strikes me about all of this is that Commons Collections has been sitting in our classpath for years. It's not a new dependency, it's not exotic, it's just there. I've been writing casts and null checks by hand when the library I was already using had a cleaner answer the whole time. A reminder that it's worth occasionally re-reading the Javadocs or poking through the methods in autocomplete to see what you are missing (that is exactly what I did here).

Category: tech Tags:

Modern Java Maps

 — 

I'm back doing Java stuff for a while, and a lot of our codebase uses Maps a lot. Though it's a new project, the codebase leans heavily on the style of Java 7/8 and not with the new patterns that came with Java 9 and above. Here are some things that I have learned lately.

Creation

I've seen this pattern many times over my career and never loved it:

  Map<String,String> myMap = new HashMap<>();
  myMap.put("A","B");
  myMap.put("C","D");
  myMap.put("E","F");
//  ....

Java 9 introduced better ways to initialize a map. The simplest:

Map<String,String> myMap = Map.of("A","B","C","D","E","F");

Keys and values go in alternating order. One catch: Map.of only supports up to 10 entries. For larger maps, there's Map.ofEntries:

Map<String,String> myMap = Map.ofEntries(Map.Entry("A","B"),
                                         Map.Entry("C","D"),
                                         Map.Entry("E","F"));

More verbose, but still much cleaner than the old approach and there's no entry limit.

Testing for Empty

Empty-checking in Java is trickier than it should be. If the object might be null, the naive check becomes:

if (myMap==null || myMap.isEmpty()) { ///

That gets old fast. Apache Common Collections has a cleaner option and chances are it's already in your project even if you didn't add it explicitly:

if (MapUtils.isEmpty(myMap)) {////

MapUtils handles the null check for you. Worth noting: you can't use CollectionUtils here — it won't compile, because Map doesn't implement Collection in the Java type hierarchy. You can also get an immutable empty map from standard Java:

Map<String,String> myMap = Collections.emptyMap();

So Collections considers Map a collection but not CollectionUtils. Java consistency at its finest.

Coming back to a Java codebase after time away is a strange experience. The language has genuinely improved, but the old patterns are still used everywhere, written by people who had no reason to change them. I suspect I'll be finding these kinds of small upgrades for a while.

Category: tech Tags:

My Emacs Misconceptions

 — 

This is my Emacs Carnival post this month on Mistakes and Misconceptions.

Just in the past year, I realized something surprising: I no longer have vi muscle memory. I was a dedicated vi user for fifteen years before I switched to Emacs, and at some point it just… left. I can still do the basics with some effort, but the more advanced things I used to reach for in vi are simply gone. I now do everything much more easily in Emacs — without thinking about it.

So fixing what little vi usage I have left was easy: on the remote systems I log into, like my NAS, I alias vi and vim to mg, which is a lightweight Emacs clone. It gives me quick "edit and out" capability on the command line. It's a small thing, but it says a lot about where I've landed.

But to understand how I got here, I need to tell you how I first started using vi.

The Misconception I Inherited

My first job in college left me no choice but to use vi. Using anything else on our Solaris workstations was unheard of. We had an Emacs user who started that installed it in his home directory. The next day, when he logged in, it was gone. The sysadmin had a cron job that scanned for Emacs installs and deleted them overnight. The message was clear: Emacs was big, unwieldy, and not worth our time.

That misconception stuck with me longer than it should have.

Those early impressions didn't help. Vi has a steep learning curve, sure, but the basics were approachable — you could at least move around without thinking too hard. Emacs required two-key combinations just to navigate. That seemed like madness.

What Actually Changed My Mind

Years into my next job, I was supporting an application that required juggling a lot of files at once. Vim, at the time, made that genuinely painful. I knew some of the developers I admired online used Emacs heavily, so I decided to give it a real try.

I went cold turkey. No Viper, no Evil mode, no vi emulation layer — just stock Emacs keybindings from day one. Partly for the workflow improvement, partly out of curiosity. I haven't really looked back. That was 25 years ago.

The Misconception I Held About Myself

Here's the thing I didn't expect: I thought keeping some vi fluency was important. That it would always be there as a fallback. Fifteen years of muscle memory doesn't just disappear overnight. It decays slowly from lack of use – and I don't miss it. Not because vi isn't good, but because Emacs has replaced the underlying need. The things that made Emacs look unwieldy at first — the key chords, the weight, the learning curve — turned out to be features, not bugs. The same depth that frustrated me early on is exactly what made vi fade away naturally.

My config looks very different than it did a few years ago, and almost nothing like it did when I started. But that's the point. It grew with me, rather than the other way around.

Category: tech Tags:

Readeck: More Than a Read-It-Later App

 — 

In my last post I mentioned I switched to Readeck as my read-it-later app. It's starting to become essential to my workflow. The first thing that struck me was how fast it feels. My old Wallabag instance was sluggish when saving an article. Readeck saves asynchronously: you tell it to save a link, it goes into a queue, and Readeck processes it in the background. You can see the status in the web app interface. The same thing happens when you delete an article – it doesn't get deleted right away but the article is marked on the interface and it will go away soon. This sounds like a quirk (especially for the delete) but it keeps the interface responsive – the heavy lifting happens behind the scenes.

Readeck's Collections are a feature that I didn't expect to like and now they have become essential. A collection is basically a saved search – articles matching a tag, a keyword, a URL pattern, or a date range are collected automatically. I have one for articles saved in the last seven days and a few organized by topic. The Collections are like "smart folders" – they update without me doing anything.

Recently I started using the epub export. You can export a single article or an entire collection to an epub file and load it onto a Kobo or any other reader. Long articles and shortish stories read a lot better for me on eInk. I do wish there was a direct save to Dropbox or Google Drive so it lands on the Kobo without the manual transfer step.

You can also share your articles within Readeck. It generates a URL to the nicely formatted article that you can share with people. That URL expires after a certain amount of time. That expiration seems a little weird but it is the difference between sharing with a few people and re-publishing the original.

Readeck also has annotations for highlighting sections in articles and those highlights show up when you share an article publicly. I would like a mass export to a file that has a link to the article in my Readeck server, but that is minor. Annotations within the webapp work really well. Annotations are the main reason I use the mobile browser rather than the app – in the browser I can highlight things but I can't in the mobile app and the mobile site works really well.

The feature I've gotten the most personal use out of isn't in Readeck itself – it's a workflow I built around it. I used to save articles and then never look at them, so my reading list turned into a graveyard. I solved this with an iOS Shortcut that calls the Readeck API to save the page and simultaneously assigns a unique tag. The tag, Readeck URL and my API key are stored in DataJar (a free app for storing state, secrets and values in Shortcuts). When I save an article, the title and tag flash on screen, and I write them in my bullet journal as a reminder to at least open it later. The Shortcut is here if you want to adapt it.

If you want to try Readeck before committing, there's a Docker image you can run locally. That's exactly how I started – I saved a few articles, poked around, and only then moved it to Pikapod. It was certainly worth the experiment. If you're already happy with Instapaper, you probably won't find much to convince you to change. But if you've ever wanted a self-hosted option that doesn't feel like a compromise, Readeck is a great choice.

Category: tech Tags:

Pikapod Apps

 — 

I realized that my article from last fall on self-hosting on the NAS is now outdated. Not only am I not hosting apps on my NAS anymore, but I'm not even using those apps anymore. I started using Pikapod to host my RSS and read-it-later apps. Pikapod hosts a lot of open source apps of all types and needs.

I stopped hosting on my NAS simply because things got really slow, especially Wallabag. It even affected my normal NAS operations of copying and hosting files, which is really its main job for me. I stumbled upon Pikapod from the Installer newsletter and I decided to give it a shot. Ironically, they didn't have Selfoss as an option, so I did some research and picked FreshRSS. Also, I decided that there were things about Wallabag I didn't really like, and after some searching, I decided to choose Readeck, and I've been very happy with both.

Both of my apps are very fast, and I pay under $5/month to host both of them. Pikapod basically takes a Docker container and starts it up – though they don't give you any real details on how the apps run.

Not everything has been golden. I wanted to install some plugins in FreshRSS, so I had to temporarily turn on an SFTP connection to that pod and move the files up there. The only way to make your own personal backup of your apps (which you should do) is to use S3 on AWS. You have to dedicate a whole bucket to the backups, which isn't that bad though it gives you more to manage in your AWS environment. But the cost of the S3 usage is negligible.

As far as URL goes… you can use their randomly-generated URL or add your own cname to the pod. I like to start the pod up with the random name and then put in my cname when it's ready – yes you can change the URL after it's running.

There's no CLI or anything like that on your host apps, which is both good and bad considering I tend to make trouble if I'm given shell access. So, for me, the limitations are the feature: just enough control, not enough rope to hang myself.

The pods themselves work really well. Overall I'm really happy. In the future I'll cover FreshRSS and Readeck in more depth but I felt Pikapod needed a post in and of itself. If you need CLI access or absolute complete control, this isn't for you. If you want open-source tools that stay running, Pikapod is hard to beat.

Category: tech Tags:

Emacs Carnival: Completion

 — 

This is part of the February 2026 Emacs Blog Carnival on Completion

For me, completion is a odd thing to have as a carnival theme mostly because I just "do completion" and don't think about it. I really had to do a lot of thinking just to figure out what I would write. And then I realized that I use completion all the time - I just don't think about it.

In Buffers

To be frank, normal buffers I use the built-in hippie-expand which uses the contents of the buffer and maybe other buffers to offer smartest thing. So the ironic thing is I don't set up a lot of fancy completions - I just type M-/ and get what I want. For example, in a Python file I type def then M-/ and hippie-expand suggests defaultdict from my imports at the top of the file

I do use some lsp-modes and they give me completions, but it's a long list and that I don't generally use . But if it happens to be a long line that is exactly what I want, I have no problems using that. For me, it's generally not work setting up lsp mode for all the modes I'm into – just the big ones: Python or Java.

I also have yasnippet installed, but I don't use it all that often. I have even built my own templates, but to be frank, I kind of forget about them and just write my own code. Most of my problem is that I don't always know what the shortcuts are – so I just don't do it. Thinking about part of my completion journey caused me some time with robot friend Claude and we came up with a way to dump the yasnippet shortcuts and templates to a Denote file – could be easily changes to a normal Org file. See it here: https://gist.github.com/squarepegsys/2fe7caa75b862f6604a0afca660a8d58

This has made it more clear what each mode has. And my cheatsheet for orgmode has become handy while writing this post!

Utility Completion

I'm defining this as "not in the main buffer" – so the minibuffer, commands, switching buffers, looking for files, etc.

For this, I still use what I have using for many years: Helm. I've read about newer frameworks like Vertico, but I've never installed them to try. They don't seem to offer anything Helm doesn't already do, while Helm integrates with so many more packages. Helm integrates natively with projectile, ag/rg, org-mode, and dozens of other tools - workflows that require additional packages and configuration with newer stacks. If I was starting Emacs now, I would start with something else, but I have never had a reason to move from Helm.

For example, long ago I assigned the standard C-x C-f to helm-find-files. I type part of a filename, fuzzy match through directories, and soon I have exactly what I want – with the option to copy, rename, grep, or open as root without ever leaving the interface. It's essentially muscle memory now. Switching to Vertico would mean relearning what C-x C-f does, and losing actions I don't even consciously remember I use.

And, to expand on this some more… helm-find-files can do a lot more than just loading up the next file, Hitting Tab brings up a slew of options, like running grep, search and replace, etc.

More Helm magic I can't do without is helm-swoop. Think of it as a live, interactive grep of your current buffer—as you type, matching lines appear instantly. You can jump to any match, or – and this is the magic – press C-c C-e to enter edit mode, make changes across all matches, and C-c C-c to commit them back to the buffer.

It's hard to explain how that works, so below is a Gif of it in action, in a file of junk text finding and replacing Id with Ego:

In Conclusion

At the end of the day, I don't think about using commands like hippie-expand or helm-find-files – I just use them. They are muscle memory for me, a step in a longer workflow and I just expect that step to be there. That is probably the best part of completion in Emacs – it just works. Or, to put this back on theme: completion should be the sideshow to your Emacs Carnival.

Category: tech Tags:

Getting Down with Git Town

 — 

I like Git a lot and I know how to use it fairly well.. I wouldn't consider myself an ultimate expert – more like an intermediate user that has found themselves in weird situations with Git and, most of the time, figuring out how to get out of them

My main issues with Git, especially in our standard world of pushing changes and then going to a website to make a merge requests, it's a little low level. Don't get me wrong – I think merge requests are great not only for someone to look at your code but also for teaching moments! But making a branch in the right format, constantly pulling in the parent branch, pushing and making a MR… that is a lot of manual steps!

When I stumbled on Git Town, I was a little bit suspicious but I tried it out anyway.. and I found it incredibly good. It basically wraps a lot of what I specified above into a couple of steps that generally do the right thing.

You can look at the install and usage on your own – no sense in me listing that here. But here is how I use it:

I first say "Oh I need to work on ticket X" so I type:

> git hack TICK-123-some-witty-name

That will:

  • get the latest from main or whatever my configured parent branch is
  • create a branch named TICK-123-some-witty-name and have it in that folder.

Note it doesn't matter what branch originally was on when I created that branch. When I want to hack, it always starts it from main (or whatever parent).

So I'm working along and note there are some changes in main that have been push. I then will type:

> git sync

Now only will that grab the changes from main and put it in my current –hack– feature, but will put the changes in main to all the other features I have checked out. Neat huh?

If I need to switch back to another feature that I was working on, I would do :

> git switch <name>

and then it will switch the branches. Note that with the early sync command, I have an updated branch!

Finally, my favorite one – when I'm ready to make a MR. I simply do:

> git propose

And it will make sure it's sync'ed with the parent, push up the changes and use the API of the server (which you configured earlier) to make a MR, give you the link and even open the browser for you!

There are many other git-town commands but that is really want I do. I also use it with git-worktrees a lot. Basically I put each hack into it's own folder and that minimizes when I use the switch command.

I really like this… it's less manual steps that you would do anyway. Give Git Town a try!

Category: tech Tags:

Emacs Maintenance

 — 

This is to join in on October 2025's Emacs Blog Carnval: Maintenance

This is an ironic subject for me, because my Emacs config is full of stuff – and some of it I use. I do a lot of experimentation and trying out new packages. Some of them are "oh this cool – I should use it." And, alas, some of it is cool but I find out that I don't really use it. What I have found that I will use things when I put them into my personal Transient menu. Then I guess I will see it and use it more and more often. Overall, I have configured a lot of things and rarely use some of them. One example is notmuch – I archive email from it every day via a cronjob but I rarely search it. I don't consider this a waste of time… I like having a little playground to experiment in. Not everything has to be a main change to my workflow … small tweaks over time can make a big difference.

I should also confess that I'm a horrible Lisp programmer. I can do some basic things but past that I consult my AI programming buddy. It's usually Kagi Assistant with a custom model I came up with via their Custom Assistant interface. I use a custom lens to look at Emacs results and have put in the following prompt:

"You are a seasoned Emacs user. You have been using it for around 30 years and know what the latest packages are and the newest trends. You weigh the opinions on Reddit highly. But you also use Helm over other completion frameworks. You are an expert on Elisp and are willing to help whoever asks you questions."

Sometimes the answer starts with "As a 30 year veteran of Emacs…" and I just chuckle. But the answers get me 85-98% there. I've found this especially handy to integrate packages together. I think it works so well because of how many packages have their source code available and that Elisp has been documented for a long time. But like any AI coding assistant, when it goes wrong, it goes very, very wrong and you start spinning in circles if you aren't careful.

Category: tech Tags:

Emacs Obscure Package: transient

 — 

This is my entry to the Emacs Carnvial - Obscure Packages.

It's funny to say that Transient is an obscure package not just because it's now bundled in Emacs, but also because one of the killer apps in Emacs – Magit – uses it. But how many people make their own Transient menus? It's easy and it's powerful.

In my configuration, I have a hard time finding keystrokes that I can remember that aren't already taken. And how do I remember them? How do I remember them? Well I have solved that problem with making Transient menus. They aren't hard – you really don't even have to know Elisp to make them.

I'm no expert but here is an actual Transient example from my own config. C-c c started out as my shortcut to Denote but now it's morphed into "Mike's customized packages"

(transient-define-prefix mh/denote-transient ()
  "Denote"
    [["Common Denote Commands"
    ("n" "new note" denote)
    ("j" "journal" denote-journal-new-or-existing-entry)
    ("l"  "link, create" denote-link-or-create)
    ("m" "mark" org-remark-mark-yellow)
    ("E" "email search" helm-notmuch)
    ("f" "find note" mh/helm-denote-find-files)
    ("r"  "rename-note" denote-rename-file)
    ("F"    "copy file path"  copy-full-path-to-kill-ring)
    ("w"  "Explore Random Note" denote-explore-random-note)
    ("p"   "lsp" eglot-transient-menu)

    ]

    ["less common\n "
     ("J"  "Janitor"  mh/denote-janitor-transient)
     ("e"   "Explore"  mh/denote-explore-transient)
    ("b"  "show backlinks"  denote-backlinks)
   ("d"  "dired filter"  denote-sort-dired)
    ("g"  "ag notes" mh/helm-ag-org-wiki)
    ("k" "search old vaults"  my-xeft-transient)]])


(global-set-key (kbd "C-c c" ) 'mh/denote-transient)

Note that the format is "key" "Label" "function". Any function will do. even other Transients! One of my favorite things is to make another Transient menu in another config file and just call reference it in my main one. I like this a lot because I only have to remember one shortcut C-c c and then all my other customizations are listed. If I remember what I need, I just quickly hit it otherwise I look at the label.

It's funny how this is probably something Emacs people use most everyday via Magit but do not implement their own Transient menus themselves. They are easy to put together, and powerful.

Category: tech Tags:

Using Dataclass as a constructor

 — 

This article from Glyph talks about not using the __init__ dunder function to initialize a class and instead use the dataclass in the standard library. I read his post and experimented with this new way to make a constructor and decided that I totally agreed – this was a much cleaner way to initialize a class. I will let you read his arguments about why this is so much better.

But I hit a gotcha as I was implementing a new class, and it was more to do with my understanding of how Dataclasses work than actually using it in an constructor. Here is an example:

from dataclasses import dataclass
from initializers import some_expensive_client

@dataclass
class MyService:
    client = some_expensive_client()

    ## more methods

some_expensive_client is just a wrapper around an outside API. In my case, it was an AWS/boto3 client. I'm not sure what type it was to make Python's typing system happy and, to be frank, I don't really care that much (yes, I'm a bit old-fashioned in my Python ways). But that was a mistake.

When I was writing a test, I wanted to client via MyService(client=mock_client). But then I got an AWS error that client wasn't valid. I scratched my head … my mock_client didn't have anything to do with AWS. Then noticed that I didn't specify a type, which a dataclass expects. So I just added Any.

from dataclasses import dataclass
from typing import Any
from initializers import some_expensive_client

@dataclass
class MyService:
    client : Any = some_expensive_client()

    ## more methods

And then I could do MyService(client=mock_client) with no problem. So what seems to happen is if you don't specify a type, the @dataclass gets confused and doesn't actually initialize it (or treat it like a normal property). Once you add the type (even a generic Any) the magic happens.

Category: tech Tags:

© Mike Hostetler 2016

Powered by Pelican