<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="rss.xsl" type="text/xsl"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Angus Software Blog</title>
    <link>https://angussoftware.com/blog</link>
    <description>Updates and articles from &lt;FEED_TITLE&gt;</description>
    <atom:link href="https://angussoftware.com/blog/rss.xml" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Fri, 05 Dec 2025 17:30:00 GMT</lastBuildDate>
    <item><title>From XML to Everywhere: My First Kotlin Multiplatform Run</title><link>https://angussoftware.com/blog/from-xml-to-everywhere/</link><guid isPermaLink="false">from-xml-to-everywhere</guid><pubDate>Fri, 05 Dec 2025 17:30:00 GMT</pubDate><description><![CDATA[After 11 years of Android development and XML layouts, I built a portfolio app that runs on Android and the web using Kotlin Multiplatform and Compose.]]></description><category>android</category><category>kotlin</category><category>kmp</category><category>compose</category><category>multiplatform</category><category>ci-cd</category><content:encoded><![CDATA[<h1>From XML to Everywhere: My First Kotlin Multiplatform Run</h1>
<p>For about 11 years I’ve been doing Android—9 of those professionally—and for almost that entire time my UI life was XML and old-school views.</p>
<p>Meanwhile, my “portfolio site” was this ancient Kotlin/JS thing I hacked together in 2019 that really should’ve been deleted years ago.</p>
<p>At some point I decided:</p>
<ul>
<li>I need to learn Compose anyway</li>
<li>Kotlin Multiplatform (KMP) is clearly not going away</li>
<li>I should ship something real, not another toy app rotting in a repo</li>
</ul>
<p>So I built a <a href="https://angussoftware.com">portfolio app</a> that runs on Android and the web.</p>
<p>It took about three and a half months of nights and weekends. It’s not some dribbble-perfect masterpiece, but it’s done, it works, and I’m proud of it.</p>
<h2>Why I Picked Kotlin Multiplatform</h2>
<p>Short version: I already live in Kotlin all day, so using KMP was the obvious move.</p>
<p>The pitch is: write your core logic once, run it on multiple platforms.</p>
<p>In practice, that mostly worked. I reused a good chunk of code across Android and web, especially around data, networking, and RSS parsing. There were still platform-specific bits and some “why is this only broken on web?” moments, but nothing deal-breaking.</p>
<p>For a Kotlin-heavy Android dev, it felt like the least painful way to get something running in a browser without switching languages or brain models.</p>
<h2>Unlearning XML: Getting Used to Compose</h2>
<p>The hardest part of this project was not “learning Compose.” It was getting my brain to stop thinking in layouts and XML attributes.</p>
<p>I’ve spent years staring at things like:</p>
<ul>
<li>LinearLayout, ConstraintLayout</li>
<li>android:layout_* soup</li>
<li>Inflaters, adapters, recycling, view holders, all that</li>
</ul>
<p>Compose does not care about any of that. It’s all:</p>
<ul>
<li>Functions</li>
<li>State in, UI out</li>
<li>Recomposition instead of “findViewById and mutate”</li>
</ul>
<p>Once I stopped trying to force the old mental model on top of Compose, everything got a lot smoother. Simple screens came together quickly. Stateful parts felt cleaner than the equivalent view code I’ve written in the past.</p>
<p>There’s still some “Compose brain” I’m building, but I get why the industry is moving this way.</p>
<h2>Designing for Android and Web: Twice the UX Work</h2>
<p>One thing I absolutely underestimated: designing for both phone and browser at the same time.</p>
<p>Stuff that feels good on a phone can look weird stretched across a big monitor. A layout that’s perfect for thumbs and scrolling suddenly feels clunky with a mouse.</p>
<p>Things I kept running into:</p>
<ul>
<li>Buttons that were fine on mobile but looked oversized on desktop</li>
<li>Navigation patterns that made sense on Android but felt off in a browser tab</li>
<li>Spacing and typography that needed tweaks between narrow and wide layouts</li>
</ul>
<p>This isn’t really a KMP problem. It’s a “you chose to target more than one platform” problem. The shared code is great, but the UX still needs platform-aware decisions.</p>
<p>If you go down this route, just assume your design workload is basically multiplied.</p>
<h2>Rolling My Own RSS Feed Parser</h2>
<p>The part I’m weirdly most happy with is the blog section. It reads from an RSS feed that I control, and I ended up writing my own RSS parser.</p>
<p>Could I have used a library? Probably. But:</p>
<ul>
<li>I wanted something that worked the same on Android and in the browser</li>
<li>I didn’t want to pull in a big dependency that was JVM-only</li>
<li>It was a good excuse to get my hands dirty</li>
</ul>
<p>So the flow is:</p>
<ul>
<li>Fetch the RSS XML as plain text</li>
<li>Parse out what I care about (title, link, description, pub date, images, etc.)</li>
<li>Deal with the usual nonsense: CDATA, HTML entities, weird formatting</li>
<li>Return clean data objects for Compose to render</li>
</ul>
<p>On top of that, I created a separate repo whose only job is to generate the RSS XML and host it via GitHub Pages. That repo builds the feed, pushes it, and the app consumes it.</p>
<p>Yes, my blog is effectively powered by a stack of GitHub repos and XML. I’m fine with that.</p>
<h2>CI/CD: From Commit to Play Store and Web</h2>
<p>Once the basic app was working, I set up a pipeline so I wouldn’t have to manually build and upload things like an amateur every time.</p>
<p>Here’s what happens when I push to a release branch:</p>
<ul>
<li>GitHub Actions runs the unit tests</li>
<li>Builds and signs the Android release</li>
<li>Uploads the build to Google Play (Internal Testing track)</li>
<li>Builds the WebAssembly version</li>
<li>Deploys the web bundle to GitHub Pages</li>
</ul>
<p>The Android part was the most annoying to wire up:</p>
<ul>
<li>Keystore management</li>
<li>Google Play Console service account</li>
<li>Getting the right permissions and JSON config lined up</li>
</ul>
<p>The web part was comparatively easy: just configure GitHub Pages and give the workflow permission to deploy.</p>
<p>All the sensitive stuff (keys, tokens, passwords) lives in GitHub secrets, not in the repo. It took some trial and error to get that right, but now releases are basically “push and let the robots handle it.”</p>
<h2>DNS, Cloudflare, and Accidentally Learning How the Internet Works</h2>
<p>Previously, I just used Squarespace or similar tools that hide all the DNS details. Click some buttons, type a domain, magically it works.</p>
<p>This time I wanted more control:</p>
<ul>
<li>Primary site on <a href="https://angussoftware.com">angussoftware.com</a></li>
<li>angussoftware.dev pointing to the same thing</li>
<li>Proper HTTPS, redirects, etc.</li>
<li>Bonus: verify my Bluesky handle using my own domain</li>
</ul>
<p>That meant actually learning:</p>
<ul>
<li>A records vs CNAME</li>
<li>How Cloudflare handles DNS and proxying</li>
<li>Page rules and redirects</li>
</ul>
<p>It’s not rocket science, but there’s a difference between “I clicked around until it worked” and “I actually know which record does what.” I’m now closer to the second one.</p>
<h2>How Much AI Helped (Honestly, a Lot)</h2>
<p>I used AI constantly during this project: JetBrains’ Junie (with Claude) and ChatGPT.</p>
<p>Things it helped with:</p>
<ul>
<li>Boring boilerplate and wiring</li>
<li>“How do people usually do X in KMP?”</li>
<li>Sketching out navigation and state patterns for multiplatform</li>
<li>GitHub Actions YAML and signing/release config</li>
<li>JavaScript/HTML bits where I was rusty</li>
</ul>
<p>The important part is: it didn’t magically build the app. It just made it faster to move from “stuck” to “trying something concrete.”</p>
<p>I still had to:</p>
<ul>
<li>Understand what the code was doing</li>
<li>Fix the parts that didn’t work</li>
<li>Make tradeoffs that made sense for my app</li>
</ul>
<p>But compared to my old way of working (hours of docs + StackOverflow rabbit holes), this felt much more like pairing with a very fast, occasionally wrong coworker.</p>
<h2>What’s Next?</h2>
<p>A few things on my mind now that the first version is shipped:</p>
<p><strong>iOS</strong>
I’d love to add an iOS target. Realistically, the main thing stopping me is hardware. I don’t own a Mac, and Apple has decided that’s mandatory. KMP itself is ready for it; my wallet is not.</p>
<p><strong>More content</strong>
The app is a portfolio and blog, so it’s only as good as what I put into it. I want to add more writeups of past projects, especially some of the more interesting Android work and side projects I’ve done.</p>
<p><strong>Games in the browser</strong>
I’ve got some Android games I’d like to drag into the modern world and make playable on the web. That’s a bigger effort than a blog reader, but now that the multiplatform foundation exists, it’s at least not a totally wild idea.</p>
<h2>Would I Use KMP Again?</h2>
<p>Yes.</p>
<p>As someone who already writes Kotlin every day, KMP is the most straightforward way for me to build something that runs on more than one platform without feeling like a beginner again.</p>
<p>Is it perfect? No:</p>
<ul>
<li>You’ll still hit platform-specific bugs</li>
<li>The tooling isn’t flawless</li>
<li>You still have to think separately about UX for each platform</li>
</ul>
<p>But given my background, it’s a very solid fit. I’d absolutely use it again for future projects where Android + web (and maybe iOS someday) make sense.</p>
<h2>Wrapping Up</h2>
<p>This project ate 3.5 months of my free time and pulled me into all kinds of side quests:</p>
<ul>
<li>Learning Compose</li>
<li>Thinking in multiplatform instead of just “Android”</li>
<li>Wiring up CI/CD so releases don’t suck</li>
<li>Figuring out DNS and domain setup</li>
<li>Building an RSS system end-to-end</li>
</ul>
<p>The app itself is simple: it shows who I am, what I’ve built, and pulls in my blog posts. But the real win was proving to myself that I could take a brand-new stack, stick with it long enough, and actually ship something real instead of abandoning it halfway like so many other side projects.</p>
<p>That alone made it worth it.</p>
]]></content:encoded></item>
    <item><title>How I found and lost a love for music</title><link>https://angussoftware.com/blog/lost-music/</link><guid isPermaLink="false">lost-music</guid><pubDate>Sun, 10 Aug 2025 18:46:00 GMT</pubDate><description><![CDATA[I played the drums and guitar when I was younger. For me, it's been years since I played both.]]></description><category>intro</category><category>music</category><category>depression</category><content:encoded><![CDATA[<h1>How I found and lost a love for music</h1>
<p>I played the drums and guitar when I was younger. For me, it’s been years since I played both. In elementary school I
played trombone and I sang, but eventually those lost their appeal. It wasn’t until the games Guitar Hero &amp; Rock Band
did I really get into the hype of playing. Rock music had a much richer history than the grunge and alternative I was
raised on, and was suddenly obsessed with playing real guitar and drum whenever I could.</p>
<p>Rock Band was the real launching off for me. In 2007, I didn’t have a Facebook, MySpace, or a cell phone, but I did have
a PS3. How do kids these days get into hobbies? Do they see something on their TikTok and decide, “that’s cool; that’s
for me” or do they just keep scrolling? Rock Band and Guitar Hero were there for me, a kid who considered himself
artistically talentless, as an inlet for creative exploration.</p>
<p>On real rock instruments, I got my start on drums playing on my buddy Rob from middle schools’ set. There was a heatwave
one summer, and I spent 3 nights at his house as we beat all of Guitar Hero 3 co-op. It was the days. Over the following
month, I transferred my skills from Rock Band drums to real drums, practicing when we could. Rob and I recruited some
other dudes from school to play with us, and our ninth graders’ first rock band was born. I was the singer, we
covered Green Day, Weezer; and I’ll admit I was hooked to the amount of attention I was getting.</p>
<p>I joined more bands, recorded albums and EPs, studied Music Theory in college, was the lead of the chorale and the
school musical (granted, my school was tiny), and made lots of friends and connections. Then, one day, a tipping
point happened: and from then on it was all about how I will make an income, go to college, have a career, save for
retirement, stay current in my field, not get fired, and get promoted; Music in my life died a brief and unironically
quiet death. I tried to hang onto guitar skills through college, but beyond drunken singalongs and convincing a girl
I was not a total stick in the mud, it was pointless. I tried again during the pandemic but never got the hook to
stick to it. As always, my speed of improvement was dishearteningly slow, and other priorities got in the way. As for
drums, I haven’t given any an honest play in 15 years.</p>
<p>Now, the guitar sitting in the corner stays dusty, unplayed, and perhaps even sadder than I am about its state. “I gave
Music up for my survival, my future,” I tell myself, half believing it, a tear in my eye, and coping in my words. The
silence and absence are still real, but not every passion can survive adulthood. Maybe the reality is that I never
really
had anything worth pursuing and was doomed to be let down from the start. Perhaps what I thought was improvement and
impression was all just stage lights and amp feedback pushing adrenaline and dopamine.</p>
<p>…but ultimately, I am grateful that I could be inspired. This gratitude did not come easy, but because I had to look
for it. I’m grateful that some campy video games with crude facsimiles of music instruments could make me fall in love
with so many sounds, histories, and cultures. I’ll probably never be satisfied with this part of my personal history,
but I can’t deny that love I’ve had since I first started learning. That is the romantic part of my personal musical
tragedy: that it existed, at all, in the context of everything else.</p>
]]></content:encoded></item>
  </channel>
</rss>