Tag: types

  • Porting from Perl to Go: Simplifying for Platform Engineering

    Porting from Perl to Go: Simplifying for Platform Engineering

    Rewriting a script for the Homebrew pack­age man­ag­er taught me how the Go pro­gram­ming lan­guage’s design choic­es align with platform-​ready tools.

    The problem with brew upgrade

    By default, the brew upgrade com­mand updates every for­mu­la (ter­mi­nal util­i­ty or library). It also updates every cask (GUI appli­ca­tion) it man­ages. All are upgrad­ed to the lat­est ver­sion — major, minor, and patch. That’s con­ve­nient when you want the newest fea­tures, but dis­rup­tive when you only want qui­et patch-​level fixes.

    Last week I solved this in Perl with brew-patch-upgrade.pl, a script that parsed brew upgrades JSON out­put, com­pared seman­tic ver­sions, and upgrad­ed only when the patch num­ber changed. It worked, but it also remind­ed me how much Perl leans on implic­it struc­tures and run­time flexibility.

    This week I port­ed the script to Go, the lin­gua fran­ca of DevOps. The goal was­n’t fea­ture par­i­ty — it was to see how Go’s design choic­es map onto plat­form engi­neer­ing concerns.

    Why port to Go?

    • Portfolio prac­tice: I’m build­ing a body of work that demon­strates plat­form engi­neer­ing skills.
    • Operational focus: Go is wide­ly used for tool­ing in infra­struc­ture and cloud environments.
    • Learning by con­trast: Rewriting a work­ing Perl script in Go forces me to con­front dif­fer­ences in error han­dling, type safe­ty, and distribution.

    The journey

    Error handling philosophy

    Perl gave me try/​catch (exper­i­men­tal in the Perl v5.34.1 that ships with macOS, but since accept­ed into the lan­guage in v5.40). Go, famous­ly, does not. Instead, every func­tion returns an error explicitly.

    Perl:

    use v5.34;
    use warnings;
    use experimental qw(try);
    use Carp;
    use autodie;
    
    ...
    
    try {
      system 'brew', 'upgrade', $name;
      $result = 'upgraded';
    }
    catch ($e) {
      $result = 'failed';
      carp $e;
    }

    Go:

    package main
    
    import (
      "os/exec"
      "log"
    )
    
    ...
    
    cmd := exec.Command("brew", "upgrade", name)
    if output, err := cmd.CombinedOutput(); err != nil {
      log.Printf("failed to upgrade %s: %v\n%s",
        name,
        err,
        output)
    }

    The Go ver­sion is nois­i­er, but it forces explic­it deci­sions. That’s a fea­ture in pro­duc­tion tool­ing: no silent failures.

    Dependency management

    • Perl: cpanfile + CPAN mod­ules. Distribution means install Perl (if it’s not already), install mod­ules, run script.” Tools like carton and the cpan or cpanm com­mands help auto­mate this. Additionally, one can use fur­ther tool­ing like fatpack and pp to build more self-​contained pack­ages. But those are nei­ther com­mon nor (except for cpan) dis­trib­uted with Perl.
    • Go: go.mod + go build. Distribution is a sin­gle (platform-​specific) binary.

    For oper­a­tional tools, that’s a mas­sive sim­pli­fi­ca­tion. No run­time inter­preter, no depen­den­cy dance.

    Type safety

    Perl let me parse JSON into hashrefs and trust the keys exist. Go required a struct:

    type Formula struct {
      Name              string   `json:"name"`
      CurrentVersion    string   `json:"current_version"`
      InstalledVersions []string `json:"installed_versions"`
    }

    The com­pil­er enforces assump­tions that Perl left implic­it. That fric­tion is valu­able — it sur­faces errors early.

    Binary distribution

    This is where Go shines. Instead of telling col­leagues install Perl v5.34 and CPAN mod­ules,” I can hand them a bina­ry. No need to wor­ry about script­ing run­time envi­ron­ments — just grab the right file for your system.

    Available on the release page. Download, run, done.

    Semantic versioning logic

    In Perl, I man­u­al­ly com­pared arrays of ver­sion num­bers. In Go, I import­ed golang.org/x/mod/semver:

    import (
      golang.org/x/mod/semver
    )
    
    ...
    
    if semver.MajorMinor(toSemver(formula.InstalledVersions[0])) !=
      semver.MajorMinor(toSemver(formula.CurrentVersion)) {
      log.Printf("%s is not a patch upgrade", formula.Name)
      results.skipped++
      continue
    }

    Cleaner, more leg­i­ble, and less error-​prone. The library encodes the con­ven­tion, so I don’t have to.

    Deliberate simplification

    I did­n’t port every fea­ture. Logging adapters, sig­nal han­dlers, and edge-​case diag­nos­tics remained in Perl. The Go ver­sion focus­es on the core log­ic: parse JSON, com­pare ver­sions, run upgrades. That restraint was inten­tion­al — I want­ed to learn Go’s idioms, not repli­cate every Perl flourish.

    Platform engineering insights

    Three lessons stood out:

    1. Binary dis­tri­b­u­tion mat­ters. Operational tools should be instal­lable with a sin­gle copy step. Go makes that trivial.
    2. Semantic ver­sion­ing is an oper­a­tional prac­tice. It’s not just a con­ven­tion for library authors — it’s a con­tract that tool­ing can enforce.
    3. Go’s design aligns with plat­form needs. Explicit errors, type safe­ty, and sta­t­ic bina­ries all reduce sur­pris­es in production.

    Bringing it home

    This isn’t a Perl vs. Go” sto­ry. It’s a sto­ry about delib­er­ate sim­pli­fi­ca­tion, tak­ing a work­ing Perl script and recast­ing it in Go. The aim is to see how the lan­guage’s choic­es shape a solu­tion to the same problem.

    The result is homebrew-semver-guard v0.1.0, a small but stur­dy tool. It’s not feature-​finished, but it’s production-​ready in the ways that matter.

    Next up: I’m con­sid­er­ing more Go tools, maybe even Kubernetes for ser­vices on my home serv­er. This port was prac­tice, an arti­fact demon­strat­ing plat­form engi­neer­ing in action.


    Links

  • Video for Better Perl: Subroutine signatures and type validation

    Video for my pre­sen­ta­tion to Houston Perl Mongers last month, based on this blog post. Slides are here. Sorry about all the um“s and ah“s.

  • Tuesday at Boston.pm: Perl subroutine signatures and type validation

    I’ll be repris­ing my pre­sen­ta­tion on Perl sub­rou­tine sig­na­tures and type val­i­da­tion for the Boston Perl Mongers on Tuesday, March 9 at 7 PM EST. Visit their wiki for details; they’ll be post­ing the Jitsi URL short­ly before the meet­ing. There’s also a Meetup page.

  • Better Perl: More on signatures and types

    A few weeks ago I wrote an arti­cle cov­er­ing six ways to do sub­rou­tine sig­na­tures and type con­straints in Perl. Some of the feed­back I got indi­cat­ed that there were more options to con­sid­er, so for the pre­sen­ta­tion I gave at Houston Perl Mongers I quick­ly sum­ma­rized at the end sev­en more mod­ules from CPAN that offer these fea­tures. Still more feed­back showed that I had missed five more mod­ules, so at the risk of becom­ing the sig­na­tures guy” here they are.

    Class::ParamParser (updated)

    First released in 2000 as part of a larg­er project, this may be the first general-​purpose para­me­ter pars­er to appear on CPAN. Although the doc­u­men­ta­tion exam­ples use it as a par­ent class, you should fol­low the sug­ges­tion fur­ther down and use its two meth­ods params_to_hash and params_to_array direct­ly from the class. Both take the same list of argu­ments, and only dif­fer on whether they return a hash ref­er­ence con­tain­ing named para­me­ters or an array ref­er­ence con­tain­ing posi­tion­al parameters.

    There are options for slurp­ing extra passed val­ues into anoth­er hash buck­et and low­er­cas­ing named para­me­ters, and it will auto­mat­i­cal­ly chop off any lead­ing hyphens in your para­me­ter names. You can also alias mul­ti­ple named para­me­ters to the same result­ing argu­ment. The mod­ule does­n’t pro­vide any facil­i­ty for type val­i­da­tion, though.

    Method::ParamValidator

    This adds the inter­est­ing wrin­kle of being con­fig­urable with an exter­nal JSON file; oth­er­wise, it seems you have to call var­i­ous meth­ods on a val­ida­tor object to add para­me­ters (which it calls fields) or meth­ods to val­i­date. It does­n’t seem to sup­port slurp­ing extra val­ues nor posi­tion­al para­me­ters, but its type val­i­da­tion lets you use arbi­trary code ref­er­ences. The doc­u­men­ta­tion could use a bit of work with more exam­ples of real-​world usage rather than test script extracts. The author says it’s just a pro­to­type,” though.

    Mojolicious::Validator

    The Mojolicious real-​time web frame­work has a built-​in val­ida­tor, but it’s geared towards val­i­dat­ing HTTP para­me­ters rather than sub­rou­tine argu­ments. There’s also a MojoX::Validator wrap­per for Input::Validator that per­forms much the same task. You could press either into ser­vice as sub­rou­tine val­ida­tors if you’re already using Mojolicious, but they aren’t struc­tured that way.

    Return::Type

    This isn’t for input para­me­ters to sub­rou­tines; rather, it pro­vides an attribute that spec­i­fies what type your sub­rou­tines return. As such, it’s com­pli­men­ta­ry to most of the oth­er tech­niques cov­ered in this series. It works with Type::Tiny, MooseX::Types, or MouseX::Types, and because Perl func­tions can tell whether they’re in scalar or list con­text, you can spec­i­fy dif­fer­ent type con­straints for each.

    There are sev­er­al oth­er mod­ules with sim­i­lar func­tion­al­i­ty, but these are out­side the scope of this article.

    routines

    Based on Function::Parameters (cov­ered pre­vi­ous­ly), this prag­ma adds sup­port for a reg­istry for stor­ing Type::Tiny type libraries. It does­n’t appear to offer any oth­er sig­na­ture fea­tures, though. Feel free to cor­rect me in the comments.

    As I said in my slide deck, maybe we’re tak­ing TMTOWTDI too far? It’s nice to be spoiled for options, though. I still rec­om­mend Type::Tinys Type::Params for its per­for­mance and flex­i­bil­i­ty, or Params::ValidationCompiler if you’re using type libraries from Specio or Moose. Some use­ful side-​by-​side bench­marks would be nice; maybe I’ll save that for anoth­er arti­cle and fur­ther risk being labeled the sig­na­tures guy.”

  • Better Perl: Subroutine Signatures and Type Validation presentation slides

    Here they are from tonight’s pre­sen­ta­tion, typo-​corrected and ready for review. Video to follow.

    Animated slideshow of Better Perl: Subroutine Signatures and Type Validation
    It seemed like the time just flew by…

    The orig­i­nal arti­cle that inspired this pre­sen­ta­tion is here.