<?xml version="1.0"?>
<rss version="2.0">
  <channel>
    <title><![CDATA[LinLog]]></title>
    <link>https://linlog.skepticats.com/</link>
    <description><![CDATA[Linux, Programming, and Computing in General]]></description>
    <lastBuildDate>2023-05-14T22:31:36+00:00</lastBuildDate>
    <managingEditor>pageer@skepticats.com (Peter Geer)</managingEditor>
    <language>en-US</language>
    <generator>https://lnblog.skepticats.com/?v=2.3.1</generator>
    <item>
      <title><![CDATA[Installing PHPStorm under WSL2]]></title>
      <link>https://linlog.skepticats.com/entries/2023/05/installing-phpstorm-under-wsl2.php</link>
      <description><![CDATA[<p>The other week I tried to install PHPStorm under WSL2.&nbsp; Because that's a thing you can do now (especially since Linux GUI apps now work in recent Windows 10 updates).&nbsp; The installation process itself was pretty simple.</p>
<ul>
<li>Download PHPStorm for Linux from JetBrains website.</li>
<li>Now extract the tarball and run the&nbsp;<code>bin/phpstorm.sh</code> script.</li>
<li>PHPStorm should start up.</li>
</ul>
<p>The next step is to configure your license.&nbsp; In my case, I was using a corporate license server.&nbsp; The issue with this is that you need to log into JetBrains' website using a special link to activate the license.&nbsp; Unfortunately:</p>
<ul>
<li>By default, WSL doesn't have a browser installed.</li>
<li>Firefox can't be installed because the default build uses a snap image, and WSL apparently doesn't support snap.</li>
<li>PHPStorm doesn't appear to be able to properly deal with activating via a Windows browser (I tried pointing it to the Windows Chrome executable and got an error page that points to a port on localhost).</li>
</ul>
<p>So how do we get around this?&nbsp; Well, we need to install a browser in WSL and configure PHPStorm to use it.&nbsp; So here's what we do:</p>
<ul>
<li>Skip the registration for now by starting a trial license.</li>
<li>Download the Vivaldi for Linux DEB package from Vivaldi's website.&nbsp; You could use a different browser, but I like Vivaldi and it offers a convenient DEB package, so I used that.</li>
<li>Install the Vivaldi DEB.&nbsp; WSL will be missing some packages, so you have to run&nbsp;<code>apt install --fix-broken</code> after installing it.</li>
<li>Go into the PHPStorm settings and configure your web browsers to include Vivaldi and set it as the default browser.</li>
<li>Go back to the registration dialog and try again.&nbsp; This time, PHPStorm should start up Vivaldi and direct you to the appropriate link.</li>
<li>Log into your JetBrains account and follow the instructions.&nbsp; The web-based portion should succeed and registration should complete when you click "activate" in PHPStorm again.</li>
</ul>
<p>There we go - PHPStorm is registered and works.&nbsp; Mildly annoying setup, but not actually that bad.</p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 06 May 2023 22:20:57 +0000</pubDate>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Ubuntu]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[Programming]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[WSL]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2023/05/installing-phpstorm-under-wsl2.php</guid>
      <comments>https://linlog.skepticats.com/entries/2023/05/06_1820/comments/</comments>
    </item>
    <item>
      <title><![CDATA[Vim macro recording is really nice]]></title>
      <link>https://linlog.skepticats.com/entries/2023/01/vim-macro-recording-is-really-nice.php</link>
      <description><![CDATA[<p>This is probably a big "duh" for anyone who's used it before, but Vim's macro recording is pretty handy.&nbsp; It's one of those things I've been vaguely aware of for a long time, but never actually used before.&nbsp; Until now, I really only ever recorded a macro by accident.</p>
<p>But the other night I was playing around with my <a href="https://github.com/pageer/myfinemu">attempt to learn Go by writing a NES emulator</a>.&nbsp; I'm working from a demo of <a href="https://bugzmanov.github.io/nes_ebook/">writing one in Rust</a>, which recommends having highly comprehensive unit tests, so that's what I'm trying to do.&nbsp; The problem I'm running into is that this results in lots of repetitive test cases.&nbsp; The individual test cases are short, usually six to ten lines, and take the form of a struct defining the processor state and expectations.&nbsp; The thing is, there are a <em>lot</em> of them.&nbsp; By that, I mean that so far I've implemented 20 of around 150 opcodes and my unit test file is already pushing 1000 lines, compared to about 250 lines of production code.</p>
<p>Now, a 4:1 test to prod ratio isn't necessarily a&nbsp;<em>bad</em> thing, but it does seem a little high.&nbsp; And the tests are all <em>very</em> similar, so they're kind of hard to read and navigate - unless you know the exact term to search for, they all just blend together.&nbsp; So I really wanted to condense them down, preferably to one line per test case.&nbsp; So I finally decided to make a few functions to extract the common stuff into a template so that I can condense all those structs down into one-liners.&nbsp; Great!&nbsp; But I already have 1000 lines of code to update.&nbsp; Not so great.</p>
<p>Enter the Vim macro reorder.&nbsp; For each opcode, a wrote a function to create the test template.&nbsp; Now I had to take the existing structs and convert those into function calls.&nbsp; Unfortunately, this was too complex for a simple substitution and it was just too tedious to do that many by hand.&nbsp; However, the exact same series of steps could be repeated for each test case, so I decided to look up that macro recorder that I've been accidentally turning on for years.</p>
<p>Turns out it's super simple.&nbsp; You just start recording by using "q" with a register name (e.g. "qa") in command mode, do a bunch of stuff, and then run "q" again to stop.&nbsp; Then you can execute the macro with "@" and the name, e.g. "@a" and repeat that with "@@".&nbsp; By itself, this is not terribly remarkable.&nbsp; But with Vim movements and actions, it's really easy to make a macro that performs a complex manipulation on structurally identical blocks of text.&nbsp; So I was literally able to start recording, just do the manipulation like I normally would, and then stop recording, leaving me with a macro that works perfectly with basically zero extra work.</p>
<p>Like I said, nothing really new or ground-breaking here.&nbsp; Just discovering one of those handy features that I've never really used before.&nbsp; But now I know how to take advantage of that for future use.</p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 07 Jan 2023 23:21:16 +0000</pubDate>
      <category><![CDATA[Vim]]></category>
      <category><![CDATA[Programming]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2023/01/vim-macro-recording-is-really-nice.php</guid>
      <comments>https://linlog.skepticats.com/entries/2023/01/07_1821/comments/</comments>
    </item>
    <item>
      <title><![CDATA[Non-standard project setup with CoC and Pyright]]></title>
      <link>https://linlog.skepticats.com/entries/2021/12/non-standard-project-setup-with-coc-and-pyright.php</link>
      <description><![CDATA[<p>Here's a quick little thing that I'll probably need to remember and might be useful to other.</p>
<p>At work, we have a PHP project that has automated integration tests written in Python.&nbsp; The top-level directory of the Git repo is the normal PHP stuff, but the&nbsp;<code>tests/integration/</code> directory is a Python sub-project that uses Poetry and Pytest.</p>
<p>Now, I use Vim as my editor and CoC with Intelliphense and Pyright for my PHp and Pythong language servers.&nbsp; Since the main repo is PHP, Intelliphense works just fine.&nbsp; Hwoever, Pyright needs a little help.&nbsp; In particular, it didn't find the third-party dependencies&nbsp;<em>or</em> the integration test framework packages because it didn't know where to look.</p>
<p>Fortunately, this is easily fixed by creating a&nbsp;<code>pyrightconfig.json</code> file.&nbsp; I was able to create one of those in the top-level directory of the project and add an "execution environment" to tell Pyright where to find the root of the Python project.&nbsp; I set it to the "tests" directory because, while the main dir is <code>tests/integration/</code>,&nbsp; that directory is also a Python module, so using "tests" lets Pyright find the "integration" module.</p>
<p>My particular file looks like this:</p>
<p><code>{<br />&nbsp; &nbsp; "venvPath": "tests/integration",<br />&nbsp; &nbsp; "venv": ".venv",<br />&nbsp; &nbsp; "executionEnvironments": [<br />&nbsp; &nbsp; &nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "root": "tests<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; ]<br />}</code><code></code><code></code></p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 11 Dec 2021 23:20:15 +0000</pubDate>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Vim]]></category>
      <category><![CDATA[Programming]]></category>
      <category><![CDATA[Note to Self]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2021/12/non-standard-project-setup-with-coc-and-pyright.php</guid>
      <comments>https://linlog.skepticats.com/entries/2021/12/11_1820/comments/</comments>
    </item>
    <item>
      <title><![CDATA[Broken development environment]]></title>
      <link>https://linlog.skepticats.com/entries/2021/08/broken-development-environment.php</link>
      <description><![CDATA[<p><em><strong>Author's note:</strong> This episode of From The Archives is the stub of an article I wrote on December 10, 2007.&nbsp; At the time, I was working for eBaum's World (this was back around the time ebaum sold it, but before he was forced out).&nbsp; It was kind of a weird time because it was my first experience working for an actual tech company.&nbsp; (It was also a weird place to work, for other reasons, but that's a different story.)&nbsp; Previously, I'd been stuck in the world of public-sector internal IT which is...not great, by comparison.</em></p>
<p><em>This particular post was expressing my annoyance over how our development environment was broken.&nbsp; Our dev environment, at the time, was literally just a shared server that we all pushed code to. And yes, that means we had plenty of opportunity to step all over each other and things could easily break for non-obvious reasons.</em></p>
<p><em>This was obviously terrible, but it's what we had to work with.&nbsp; We had a four-man development and system administration team with not a huge budget or set of internal resources.&nbsp; And, of course, there was&nbsp;<span style="text-decoration: underline;">always</span> something more important to do than improving our dev environment setup.</em></p>
<p><em>These days, I still have dev environment issues, but for completely different reasons.&nbsp; My company has an entire infrastructure for spinning up development VMs, including dedicated host clusters, custom tooling to setup environments, and teams responsible for managing that stuff.&nbsp; So now I have my own virtual instance of every server I need (which, for reference, is currently about eight VMs).&nbsp; However, there are still some holes in that infrastructure.</em></p>
<p><em>Part of the issue is that we have a&nbsp;<span style="text-decoration: underline;">lot</span> of teams that share or depend on the same infrastructure and/or services.&nbsp; For instance, one of the services that my team maintains is also worked on by at least three other teams.&nbsp; And we all share the same database schema, which doesn't automatically get updated in dev environments when changes are made in production, so when you pull in the develop branch, you frequently get breaking changes that you may not have ever heard of, usually in the form of config or database changes that aren't set in&nbsp; your environment.&nbsp; Sure, everything "just works" if you start fresh, but nobody ever starts fresh because it takes too long to spin up all the required pieces and set up the test data.&nbsp; (However, we are moving toward a Docker/Kubernetes setup for the pieces that don't need test data, so things are moving in the right direction.)</em></p>
<p><em>Not that I can complain too much.&nbsp; Even for my personal projects, which are&nbsp;<span style="text-decoration: underline;">much</span> simpler, my dev environment is frequently in disarray.&nbsp; Things get out of date, permissions or services don't get correctly configured after an update, or my setup is out of sync with the production environment.&nbsp; &nbsp; In fact, I had that problem just the other day - I pushed some code for this blog that worked fine locally, but broke on the live server because it was running a different version of PHP.&nbsp; Granted, the code in my dev environment was&nbsp;<span style="text-decoration: underline;">wrong</span> (and I really should have caught it there), but that's not the point.</em></p>
<p><em>The point is that environment maintenance is hard and dev environment maintenance doubly so because it changes frequently and is of much lower priority than production.&nbsp; That's something I hadn't really had to worry about in my internal IT job, because I was writing desktop apps and everybody was running identical Windows desktops.&nbsp; It was a a simpler time....</em></p>
<hr />
<p>This week's installment of "Pete's list of things that suck" features broken development environments. &nbsp;I spent the last couple of days at work wrestling with one and it really, really sucks.</p>
<p>The thing is, our development environment is...really screwed. &nbsp;Things went really bad during the production server upgrade a couple of months ago and we had to hack the hell out of the code just to keep the site running. &nbsp;As a result, we had all kinds of ugly, server-specific hackery in production which just plain broke when we moved it back into devel. &nbsp;And since, of course, we have a huge backlog of projects that management wants implemented, we've had no time to go back and reconfigure the development servers.</p>
<p>This week, I've been trying to test some changes to our user upload process. &nbsp;However, due to some NFS misconfiguration and some code problems, uploads just plain don't work in our main development environment. &nbsp;We do have a new, additional set of development servers (well, one box with a half-dozen virtual machines, but you get the idea), but I couldn't get those to work either. &nbsp;Part of it was that the configuration on those servers was incomplete, and part of it was that Firefox sucks.&nbsp; <em>(Note from the present: I no longer remember why that was.)</em></p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 21 Aug 2021 22:20:06 +0000</pubDate>
      <category><![CDATA[Programming]]></category>
      <category><![CDATA[Software Engineering]]></category>
      <category><![CDATA[From the Archives]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2021/08/broken-development-environment.php</guid>
      <comments>https://linlog.skepticats.com/entries/2021/08/21_1820/comments/</comments>
    </item>
    <item>
      <title><![CDATA[CoC for Vim]]></title>
      <link>https://linlog.skepticats.com/entries/2021/08/coc-for-vim.php</link>
      <description><![CDATA[<p>A few weeks ago, I was looking into Typescript a bit.&nbsp; I've heard lots of good things about it, but never had a chance to play with it.&nbsp; However, I got tasked with some updates to my company's portal site.&nbsp; (While not technically my team's responsibility, the portal team was swamped, so I agreed to make the required updates to support a&nbsp; back-end feature my team added.)&nbsp; And, of course, the portal team uses Typescript.</p>
<p>Naturally, most of the editing recommendations for Typescript are focused on Visual Studio Code.&nbsp; But I like Vim, so I did a quick search and found <a href="https://pragmaticpineapple.com/ultimate-vim-typescript-setup/">this article</a>, which led me to CoC (which I choose to pronounce "coke", like the soda), which stands for the slightly ungrammatical "Conquer of Completion".&nbsp; It's a plugin for NeoVim and Vim that essentially does Intellisense (code completion, context popups, etc.) using language servers.</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="https://linlog.skepticats.com/entries/2021/08/14_1821/html-completion.png" alt="" width="800" /></p>
<p>If you're not familiar, the <a href="https://langserver.org">Language Server Protocol</a> (abbreviated LSP, though that always makes me think of the <a href="https://reflectoring.io/lsp-explained/">Liskov Substitution Principle</a>) was developed by Microsoft for VS Code.&nbsp; It's essentially a way to make Intellisense work without the editor having to implement support for each language.&nbsp; It does this by defining a protocol that "clients" like an editor can use to communicate with a "language server".&nbsp; The language server is a stand-alone program that can provide code intelligence for a particular language, but is not directly tied to any particular editor.&nbsp; The server can then be called by any client that implements the protocol, which means that the editor itself doesn't actually have to know anything about the language to implement advanced editing features - which is <em>huge</em>.</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="https://linlog.skepticats.com/entries/2021/08/14_1821/php-completion.png" alt="" width="800" /></p>
<p>Anyway, CoC is an LSP client for Vim.&nbsp; And I have to say,&nbsp;<em>it's awesome</em>!&nbsp; I've messed with a few code completion and LSP plugins in the past, but I never really got them to work right.&nbsp; They were either difficult to configure, or required Vim to be built with particular non-standard options.&nbsp; But CoC was dead-simple to set up.&nbsp; The only catch is that you have to install the language servers separately, but it turns out that's super-simple as well.&nbsp; (The ones I've used so far can all be installed through NPM.)</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="https://linlog.skepticats.com/entries/2021/08/14_1821/strpos-info.png" alt="" width="800" /></p>
<p>I'm still getting used to it, but having CoC is a game changer for Vim.&nbsp; I'd given up on having this level of intelligence in my editor.&nbsp; I mean, for something that supports as many languages as Vim, building it the old-fashioned way just isn't feasible.&nbsp; But when you can use the same language servers as more modern editors to do the heavy lifting, suddenly it's no longer crazy.</p>
<p>The next step is to look into the available commands and customizations for CoC and see what I can come up with to optimize my experience.&nbsp; So far it's a pretty cool tool and it definitely makes the development experience nicer.&nbsp; I want to see what else I can do with it.</p>
<p>&nbsp;</p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 14 Aug 2021 22:21:37 +0000</pubDate>
      <category><![CDATA[Vim]]></category>
      <category><![CDATA[Software]]></category>
      <category><![CDATA[Programming]]></category>
      <category><![CDATA[Tools]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2021/08/coc-for-vim.php</guid>
      <comments>https://linlog.skepticats.com/entries/2021/08/14_1821/comments/</comments>
    </item>
    <item>
      <title><![CDATA[Docblocks in Vim]]></title>
      <link>https://linlog.skepticats.com/entries/2021/07/docblocks-in-vim.php</link>
      <description><![CDATA[<p>As you may or may not know, I've become an avid Vim user.&nbsp; I use it for work and home, having given up on PHPStorm a couple of years ago.</p>
<p>But one of the things that PHPStorm did automatically, which was quite handy, was to add PHPDoc comments to functions automatically.&nbsp; This is kinda nice because, let's face it, unless you're writing a long description, most of a docblock is just typing.&nbsp; You duplicate the parameters and return signature and, if the names and types are pretty obvious (which they should be), then there's not really much to say.&nbsp; But having them is part of the coding standard, so you can't just skip them, even though they don't add much.</p>
<p>Fortunately, Vim has a plugin for that, known as PDV.&nbsp; It will read the declaration of a function (or class, or a few other things) and auto-generate a docblock for you.&nbsp; This is nice, but the extension was a little out of date - it hadn't been updated to support return type annotations.&nbsp; There was a pending pull request to add that, but it hadn't been merged.&nbsp; I'm not sure why - apparently that repo is dead.</p>
<p>So I decided to just <a href="https://github.com/pageer/pdv">create my own fork</a> and merge the outstanding pull requests.&nbsp; Now I have a version that supports modern type annotations, which is nice.&nbsp; While I was at it, I also added an alternative set of templates for <a href="https://www.naturaldocs.org">NaturalDocs</a> doc comments.&nbsp; I use NaturalDocs for <a href="https://lnblog.skepticats.com/">LnBlog</a>, so I figured it would be nice to be able to auto-generate my docblocks there too.&nbsp; All I needed to do as add a line to my <a href="https://github.com/joonty/vim-sauce">Sauce</a> config to change the PDV template path.</p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Mon, 12 Jul 2021 01:38:40 +0000</pubDate>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[Programming]]></category>
      <category><![CDATA[Vim]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2021/07/docblocks-in-vim.php</guid>
      <comments>https://linlog.skepticats.com/entries/2021/07/11_2138/comments/</comments>
    </item>
    <item>
      <title><![CDATA[Stupid Git tricks: Undoing a stash pop]]></title>
      <link>https://linlog.skepticats.com/entries/2021/04/stupid-git-tricks-undoing-a-stash-pop.php</link>
      <description><![CDATA[<p>Here's a handy little Git nugget I learned the other day: if you get conflicts trying to apply a popped stash, <a href="https://stackoverflow.com/questions/48619276/actually-undo-git-stash-pop">it doesn't get removed from the stack</a>.&nbsp; I didn't actually know this, but it's a very handy piece of information.</p>
<p>In this case, I was trying to stash my changes so I could switch to a different branch.&nbsp; Normally this is as easy as <code>git stash ; git co develop ; git stash pop</code>, but I failed to account for conflicts.&nbsp; And this time it wasn't the "nice" kind of conflict, where you just fix it and move on with your life.&nbsp; Noooooo.&nbsp; This time, I realized that I actually needed to base my changes on the branch I was originally on.&nbsp; (That branch was due to be merged into develop, but it just hadn't happened yet.)&nbsp; So fixing the conflicts would have been a waste of time because I'd just have the same conflicts in reverse when I switched back.</p>
<p>But it turns out you can just do a <code>git reset --hard whatever</code> and because of the conflicts, the stashed changes will still be on the top of the stack.&nbsp; Very handy!&nbsp; This little nugget saved me a bunch of time.</p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 17 Apr 2021 14:20:54 +0000</pubDate>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Programming]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2021/04/stupid-git-tricks-undoing-a-stash-pop.php</guid>
      <comments>https://linlog.skepticats.com/entries/2021/04/17_1020/comments/</comments>
    </item>
    <item>
      <title><![CDATA[Blogging APIs]]></title>
      <link>https://linlog.skepticats.com/entries/2020/12/blogging-apis.php</link>
      <description><![CDATA[<p><em><strong>Author's note:</strong> It's officially the holiday season and I'm feeling lazy.  So guess what - it's another episode of &quot;From the Archives&quot;!  That's right, it's time for more of the series where I trot out something that's been sitting in my drafts folder for ten years because I can't muster the energy to write something new.</em></p><p><em>This article is from way back on March 18, 2007.  It actually appears to be finished, so I'm not sure why I never published it.  Perhaps I was filled with crippling self doubt that my analysis was actually stupid and people would make fun of me, so I never hit the publish button.  That was actually a thing I did for many years.  These days, I'm more casual about it.  One of the benefits of getting older is that you're more experienced and able to have a more objective view of the quality of your work.  Another is that you have a wider perspective on what really matters in life.  Another way to put that is &quot;you don't care as much what other people think.&quot;</em></p><p><em>Anyway, this article is about my attempts at implementing the various blogging APIs in LnBlog.  This included the Blogger, MetaWeblog, and MoveableType APIs.  I guess that seemed like a good idea at the time.  In retrospect, it was a nice educational exercise, but not especially useful.  I mean, the <span style="text-decoration: underline;">idea</span> of a generic API that third-party clients can use to post to your blog is great.  But in practice, it doesn't seem like that's a thing that many people actually need.  I certainly never found a good use-case for it.  Maybe that's why the APIs never really got fleshed out.</em></p><p><em>But that's enough out of present-day me.  Let's hear from 2007 me.  Enjoy!</em></p><p>Last month, I finally got around to doing some actual testing on the MetaWeblog and Blogger API implementations for <a href="http://lnblog.skepticats.com/">LnBlog</a>.  By that, I mean that rather than testing it with my own code, I actually installed a few free blogging clients.  I learned a few interesting lessons from this.</p><h3>The Clients</h3><p>I tested four blogging clients.  The first is <a href="http://deepestsender.mozdev.org/">Deepest Sender 0.7.9</a>, a Firefox extension that supports LiveJournal, Blogger, Wordpress, MSN Spaces, and generic MetaWeblog blogs.  The second is <a href="http://kblogger.pwsp.net/">KBlogger 0.6.2</a>, a simple KDE panel applet that supports the MetaWeblog and Blogger APIs.  Third is <a href="http://qtm.blogistan.co.uk/">QTM 0.4.0</a>, a C++/Qt4 application that support the Blogger, MetaWeblog, and MovableType APIs.  Last is <a href="http://blogtk.sourceforge.net/">BloGTK 1.1</a>, a Python/GTK+ application that also supports Blogger, <abbr title="MetaWeblog">MW</abbr>, and <abbr title="MovableType">MT</abbr>.</p><p>My results were mixed.  KBlogger worked basically as advertised.  In fact, it's the only one of the clients that seemed to understand the APIs in the same way that I do.  The only problem is that it's a bit short on features.</p><p>BloGTK seemed to work pretty well.  However, it worked best when set to use the MoveableType API.  When using the MetaWeblog API, I had problems editing posts.  It also has a few weird little bugs, such as things getting messed up when switching accounts.</p><p>While it has a nice interface, QTM simply would not work with LnBlog.  For the record, this is <em>not my fault</em> but rather due to the fact that this version of QTM did not correctly implement the APIs.  When sending calls to the server, it sent blog IDs, post IDs, category IDs, etc. as integers, whereas the specification calls for them to be strings.  While the difference may be academic for some servers, LnBlog really does use strings as IDs, so the requests raise errors in the XML-RPC library.  (Note: this seems to have been corrected in CVS.)</p><p>And as for Deepest Sender, I just can't get it to work as advertised.  I don't know why.  It can post entries, but editing them results in a hung edit window, the &quot;active blog&quot; box is shrunk down to an unrecongizable control, and I have yet to even see a category selection box.</p><h3>Server Problems</h3><p>The first problem I encountered with LnBlog's implementation of the Blogger 1.0 and MetaWeblog APIs was my silly assumption that, just because they are two separate API specifications, I could implement them separately.  And so, that's exactly what I did: I wrote one PHP script to implement the Blogger 1.0 API and a different one to implement the MetaWeblog API.</p><p>Oh, what a fool I was!</p><p>While that attitude made perfect sense when looking just at the specs, it just doesn't work that way in practice.  Of the four clients I tested, KBlogger was the <em>only one</em> that worked when the MetaWeblog server didn't implement the Blogger 1.0 API at the same URI.  The others all blithely assumed that the same URI would implement the Blogger, MetaWeblog, and MovableType APIs.  I guess few people even stopped to consider that a server might have independent implementations of the different APIs.  Or perhaps it's just that KBlogger is designed to support clients that only understand Blogger 1.0 while the others assume MetWeblog support.  It's hard to tell.</p><h3>Placing the blame</h3><p>After going back to look at the specs, I believe much of the blame for this situation rests with the <a href="http://www.xmlrpc.com/metaWeblogApi">MetaWeblog API specification</a> itself.  The problem is that it's just a bad specification.  In fact, it's really more a sketch of a specification than an actual spec.  It's too vauge, too confusing, and leaves too much open to interpretation.</p><p>For instance, take the metaWeblog.getCategories method.  According to the specification, this method returns a struct, with each member being a struct with the description, HTML URL, and RSS URL for each category.  </p><p>For non-programmers, &quot;struct&quot; is short for &quot;structure,&quot; and is simply set of key/value pairs.  In this case, having member structs with keys for description and URLs makes perfect sense.  </p><p>However, putting all of these in a struct doesn't make sense.  The spec says that the  category structs are to be returned in a struct, but says nothing about the key names of this container struct.  But the entire point of <em>having</em> a struct is to associate key names with values.  A struct with no particular key names is meaningless.  It's like writing a book where the index lists words, but not page numbers - if you can't pick the word (key) you want and go straight to the corresponding page (value), then the entire exercise is pointless.</p><p>Another shortcoming of the API is that it does not clearly specify a way to identify blog posts.  For example, the API includes the metaWeblog.editPost and metaWeblog.getPost methods, both of which take a post ID.  It also includes a metaWeblog.getRecentPosts method to get an array of the most recent posts for a blog.  You would think that you could call getRecentPosts, let the user pick a post, edit it, and then call editPost to commit the changes to the server.  But you can't.  </p><p>That's because the API does not specify how to get the post ID.  The metaWeblog.getPost and metaWeblog.getRecentPosts methods return a struct and an array of structs respectively, and the spec states that the members of these post structs are the members of RSS items.  But there is no mention of where the post ID comes in.  RSS certainly has no concept of a post ID, so it's not clear which member should be used for that purpose.  Presumably, this is why the MovableType extensions to MetaWeblog include a postId field in the post structs.  </p><p>Of course, RSS does provide a GUID (Globally Uniquie Identifier) field, which seems a natural fit for the post ID.  The problem is that the RSS spec does not require that this field be present.  It could also be argued that the GUID has a meaning distinct from a blog post ID.  But either way, if the MetaWeblog spec <em>meant</em> that the GUID should be the post ID, then it should have <em>said</em> so.</p><p>Judging from the MetaWeblog spec, the only place clients can count on getting a postID is from the return value of metaWeblog.newPost.  That's fine if the client can assume it is making all posts to a blog, but it is insufficient if there is also, say, a web interface.  If your blogging client can only edit posts it created, you've just cut its usefulness in half.</p><h3>Missing Links</h3><p>The MetaWeblog API depends heavily on the Blogger 1.0 API.  By itself, it is missing too much to be truly useful for the development of rich blogging clients.  If nothing else, this is clear from the absence of something resembling blogger.getUsersBlogs.</p><p>Actually, that's not entirely fair.  There was an <a href="http://www.xmlrpc.com/stories/storyReader$2460">RFC to add the Blogger methods to MetaWeblog</a>, so the spec <em>has</em> been amended to correct this shortcoming.  Or has it?  I actually only learned about this by reading the code for the WordPress MetaWeblog implementation.  The &quot;official&quot; MetaWeblog spec doesn't actually mention this or contain a link to the new RFC.  That seems rather odd considering that the spec <em>does</em> contain notes regarding other updates.  So has the spec been ammended, superceded, or was this just a &quot;Request For <em>Comment</em>&quot; that was never actually adopted?</p><h3>Bottom Line for Implementers</h3><p>So what does all this mean for those enterprising individuals who want to try their hand at writing blogging software?  It means you've got an up-hill battle.</p><p>Don't get me wrong - it's not that implementing the various specifications is difficult.  The APIs are actually pretty simple.  The problem is that you can't trust them.</p><p>For starters, if you want to write a server that is compatible with existing rich blogging clients, you will <em>have</em> to implement the Blogger 1.0, MetaWeblog, and MovableType APIs, and you will <em>have</em> to do it all at the same URI.  This isn't really a problem, so much as an inconvenience, as you can't simply work from a single specification at a time, but have to jump back and forth between three of them just to get a workable MetaWeblog implementation.</p><p>If you're writing a client, things are just as annoying.  As previously mentioned, there's the post ID problem to deal with.  Handling that is not difficult, but you have to rely on the good will of the server to send you a sensible post struct, since it is not required to. </p><p>If you want to support MovableType, there's also their brain-damaged category handling to deal with.  Rather than using MetaWeblog categories, MT has separate mt.getPostCategories and mt.setPostCategories methods, which deal with category IDs rather than textual categories.  Again, this is not hard to deal with, but it means you have to implement category handling twice - once for MT, and once for servers that use MW categories.  But on the up side, at least MT gives you an explicit postId field.</p><h3>Conclusion</h3><p>All in all, the old blogging APIs suck.  They're imprecise, lacking in features, and tend not to be so platform-agnostic.  I think they can be best described as &quot;just barely adequate.&quot;  </p><p>I have yet to look at the Atom API.  I'm hoping it will turn out to be better, but I'm not going to hold out a lot of hope.  At the very least, I suppose it can't be any worse than the old APIs.</p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 05 Dec 2020 23:21:33 +0000</pubDate>
      <category><![CDATA[From the Archives]]></category>
      <category><![CDATA[Blogging]]></category>
      <category><![CDATA[Programming]]></category>
      <category><![CDATA[Web]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2020/12/blogging-apis.php</guid>
      <comments>https://linlog.skepticats.com/entries/2020/12/05_1821/comments/</comments>
    </item>
    <item>
      <title><![CDATA[Komodo and Vim]]></title>
      <link>https://linlog.skepticats.com/entries/2020/11/Komodo_and_Vim.php</link>
      <description><![CDATA[<p><em><strong>Author's Note:</strong></em><em> We're back with another installment of "From the Archives", the blog show where I declare writing bankruptcy and just post an old, half-finished article that's been sitting in my drafts for years.&nbsp; This entry is from April 9, 2014.&nbsp; This was in the midst of my long stint as a Komodo IDE user.&nbsp;</em></p>
<p><em>One of my favorite things about Komodo was that it had pretty good Vim emulation.&nbsp; I started using that because a few years before I'd spent a lot of time going back and forth between a Windows PC and a Macbook Pro.&nbsp; The Macbook keyboard had that weird Apple layout going and it routinely messed with me, so I eventually gave up and decided to use Vim-mode because that's the same on both platforms.</em></p>
<p><em>Of course, things have changed since then.&nbsp; I've become a <a href="../../?action=tags&amp;tag=Vim">full-time Vim user</a>, and have all the fancy faux-IDE stuff set up.&nbsp; I actually like it so much that I stopped using PHPStorm for work and switched to doing all my development in Vim.&nbsp; So this post is no longer relevant to me, but it at least has a few handy links, so enjoy!</em></p>
<hr />
<p>I've been a Vim user more or less since I started using Linux. &nbsp;Mind you, I was never really a&nbsp;<em>hard core</em>&nbsp;Vim user. &nbsp;I still use the arrow keys, for instance, and manage to get by on maybe a couple dozen keybindings and commands. &nbsp;I have no clue how Vim's scripting or configuration systems work. &nbsp;All I know about ctags is that they're a thing that exists. &nbsp;So really, I'm more of a dabbler.</p>
<p>The other part of this is that I like at least a small amount of IDE in my normal working-day editor. &nbsp;I kind of like having some sort of "project view" of my files, a code hierarchy viewer, some form of Intellisense, etc. &nbsp;And while you&nbsp;<em>can</em> get most of the stuff I like in Vim, they're not there out of the box. &nbsp;And even if you can get them, you can't count on having an obvious graphical way to manipulate them. &nbsp;Typically, you just have to read the documentation to find out what the key bindings are to trigger everything.</p>
<p>So the upshot of this is that I use&nbsp;<a href="http://komodoide.com/">Komodo IDE</a>&nbsp;with the Vi emulation setting. &nbsp;This essentially turns on a Vim emulation mode that makes the editor modal and enables a lot of the standard Vim keybindings as well as a small subset of common commands. &nbsp;So I get Vim goodness with all the convenience of a full IDE. &nbsp;I had never really looked closely at just how much of Vim Komodo would emulate, though - I just knew it supported everything I commonly used.</p>
<p>Well, I had some extra time after finishing all my bug fixes the other day, and since <em>really</em> learning Vim has been on my list of things to do for, er, over 10 years, I decided to look up some&nbsp;<a href="https://vim.rtorr.com">Vim</a>&nbsp;<a href="http://www.fprintf.net/vimCheatSheet.html">reference</a>&nbsp;<a href="http://www.viemu.com/vi-vim-cheat-sheet.gif">sheets</a> and see how many of the commands and keybindings actually worked in Komodo.&nbsp; Turns out it was a pretty decent amount.&nbsp;&nbsp;<em>(Note from the future: I didn't write down the details at the time and don't care enough to catalog now that I no longer use Komodo.&nbsp; Suffice it do say that Komodo's Vi emulation was actually pretty good.&nbsp; Maybe not as good as <a href="https://github.com/JetBrains/ideavim">IdeaVim</a>, but pretty good.)</em></p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 07 Nov 2020 23:20:50 +0000</pubDate>
      <category><![CDATA[Komodo]]></category>
      <category><![CDATA[Programming]]></category>
      <category><![CDATA[From the Archives]]></category>
      <category><![CDATA[Vim]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2020/11/Komodo_and_Vim.php</guid>
      <comments>https://linlog.skepticats.com/entries/2020/11/07_1820/comments/</comments>
    </item>
    <item>
      <title><![CDATA[Code sharing, pros and cons]]></title>
      <link>https://linlog.skepticats.com/entries/2020/03/Code_sharing_pros_and_cons.php</link>
      <description><![CDATA[<p>A few months ago, the DropBox blog had an interesting article on <a href="https://blogs.dropbox.com/tech/2019/08/the-not-so-hidden-cost-of-sharing-code-between-ios-and-android/">code sharing in their mobile apps</a>.&nbsp; It was a good reminder that developers should be mindful of not fetishizing code re-use.&nbsp; Like so many things in engineering, re-use is generally good, but still involves trade-offs.</p>
<p>The short-short version of the article is that DropBox originally had the idea to share code between their iOS and Android mobile applications.&nbsp; After all, why write the same app twice when you can do it once?&nbsp; Well, it turned out to be a really bad idea.&nbsp; Because they were doing things for both platforms in a custom, non-standard way, they ended up taking on a <em>lot</em> of extra work just for the sake of re-using the code.&nbsp; And not just in the amount of extra code they had to write in terms of custom libraries and tools - there's the extra effort of bringing new developers up to speed.&nbsp; In fact, they eventually realized that it would actually be <em>less</em> work to just write everything twice and ended up abandoning their code-sharing approach.</p>
<p>Of course, this is an extreme case.&nbsp; Trying to share code between two radically different platforms with different native implementation languages is bound to generate some issues.&nbsp; A more prosaic example is the <a href="https://www.theregister.co.uk/2016/03/23/npm_left_pad_chaos/">left-pad debacle</a>.&nbsp; You know, the one where a developer removed an 11-line JavaScript "library" from NPM and broke half the internet's deployment scripts.&nbsp; But in that case, the scale was reversed - instead of trying to share a significant amount of code between a couple of projects, the left-pad package shared a completely trivial amount of code between an absurdly huge number of packages.&nbsp; But the underlying problem is similar.&nbsp; By trying to share that 11 lines of JavaScript "the right way", you end up taking on an external dependency that now has to be managed and probably generates more long-term maintenance effort than you saved from not writing the code yourself.&nbsp; (I mean, seriously, why use a library for something that any half-competent programmer could write in less than 15 minutes?)</p>
<p>On the same theme, I've seen similar problems in client-side JavaScript.&nbsp; I've worked on a codebase or two where large portions of the front-end were essentially cobbled together out of jQuery plugins that sorta-kinda work together, but not really.&nbsp; Clearly the intention was to save effort by re-using existing components, but it didn't quite work out.&nbsp; Sometimes it was because they didn't play well together, other times it was just that one of the components was not very well written.&nbsp; In a couple of cases, after examining the plugins and the desired behavior, it became apparent that I could just write a version that <em>did</em> work cleanly in an hour or so - less time than it would take to debug the third-party plugin.</p>
<p>Of course, that's not to say that re-using code, whether your own or someone else's, is a bad idea.&nbsp; It's clearly not.&nbsp; Sometimes you find yourself writing nearly identical components for multiple projects, in which case it probably makes sense to abstract that into a shared library.&nbsp; Or maybe there's a third-party library that already does more or less exactly what you need, in which case it probably makes sense to just use it.&nbsp; That's all fine.</p>
<p>My point is just that "re-use some existing code," like any other idea in engineering, comes with trade-offs.&nbsp; Sometimes those trade-offs are minor, such as the cost of managing a dependency that buys you a really big chunk of functionality.&nbsp; Other times, they're pretty major, like the opportunity cost to DropBox of breaking all of the standard platform tooling.&nbsp; Either way, the important thing is to think about those trade-offs and evaluate them honestly, not just jump to an "easy" answer.</p>]]></description>
      <author><![CDATA[pageer@skepticats.com (Peter Geer)]]></author>
      <pubDate>Sat, 07 Mar 2020 23:11:06 +0000</pubDate>
      <category><![CDATA[Programming]]></category>
      <category><![CDATA[Software Engineering]]></category>
      <guid isPermalink="true">https://linlog.skepticats.com/entries/2020/03/Code_sharing_pros_and_cons.php</guid>
      <comments>https://linlog.skepticats.com/entries/2020/03/07_1811/comments/</comments>
    </item>
  </channel>
</rss>
