How I Stopped Worrying and Learned to Love the Bang

I recently stopped cold while writing a ReactJS component and experienced a very brief (albeit intense) existential crisis. I had just, without giving it excessive thought, used not just a ternary expression to determine what the component would render, but I also used a bang in my logical test.

First: My Beef With Ternaries

I learned early in my code journey about the value of legible code, of chasing the paradigm of self-documenting code, of explicitly indicating one’s intentions with a minimum of mental friction. This is largely why I resist writing ternary operations wherever possible, thinking that an item like this

var result = input > BASELINE ? "Input is above baseline" : input < BASELINE ? "Input is below baseline" : "Input matches baseline";

is a difficult-to-read unclear mess; whereas

var result = string.Empty;

if (input > BASELINE)
{
    result = "Input is above baseline";
}
else if (input < BASELINE)
{
    result = "Input is below baseline";
}
else
{
    result = "Input matches baseline";
}

puts practically zero friction on the eyeballs and takes nearly zero effort to understand.

I can understand the desire to write as few lines of code as possible, for a lot of reasons we don’t have space to get into just now. But I don’t feel that brevity was a good enough reason to make something more difficult to read. Many pair partners can attest I have a tendency to start with a classic IF-ELSE block and resist refactoring it into something more brief.

Enter the “Bang”

I might have a strong distaste for ternaries, but I absolutely despise using bangs. The fact I feel compelled to take a moment and define what the hell it is for the less technical reader seems to summarize my issue with it–it’s an overly complex tool.

A “bang,” is simply an exclamation mark (“!”). In most (all?) programming languages, we use it to mean “Take the opposite of this bool (true/false) value.”

For instance, if I have a bool variable “isDarkMode” that equals TRUE, then “!isDarkMode” means FALSE.

Nice and confusing, yes? Thanks; I hate it. To be fair, I have seen cases where using a bang is the most elegant (or least messy) way to get what we want…but more often, I’ve found it to be a sign of lazy naming, poor coordination across application layers, or someone trying to be super clever. It just smells.

// Dark Mode is enabled when the UI element isn't toggled because it's wired backwards
var isDarkMode = !uiToggle.IsToggled;

if (!isDarkMode)
{
    // set everything to light mode styles
}
else
{
    // set everything to dark mode styles
}

You might think this is contrived, but I’ve looked at similar blocks of production code more than twice, going “Why does this make my skin crawl.” A couple quick refactors (like inverting the IF and ELSE to get rid of the need for the bang or renaming the variable so we can use the <uiToggle> the way it was written) will restore sanity…but suffice to say when I see “bang” I say “Oh dear.”

You May Ask, “What Changed?” I’ll Tell You…

I essentially learned to code in C#, and then spent the first years of my career primarily in the back end of .NET Framework applications. I relish the sense of order that comes with strongly typed objects backed by interfaces. Knowing I can extend these stable items whenever I needed new behavior (and knew they’d behave the same way over and over, or throw an exception trying).

More recently I’ve been adding functionality to a React web app (as you may have gathered from my opening paragraph). I’ll own it–JavaScript in general, and ReactJS in particular, were technologies that baffled me as I tried to become fluent in C#. The differences between a strongly typed language and the chaos of JS were bad enough–but React leverages the extreme flexibility of JS in ways I couldn’t comprehend.

For instance, the fact that when using a child component you can pass in one, some, all, or none of the properties defined or used in that child component without expressly providing overloads for the component. Try that in C# and see how fast your app blows up.

// Renders an empty view in light mode
<ChildComponent />

// Displays the list data in light mode, but does not render edit options because no user
<ChildComponent
  dataList={list}
  />

// Displays the list data with all options, in dark mode
<ChildComponent
  dataList={list}
  userId={user.id}
  darkMode
  />

The magic, and my existential crisis, happen inside the child component’s Render() function, thanks to how JavaScript handles resolving objects.

render() {
  const { dataList, userId, darkMode } = this.props;

  if (darkMode) {
    setDarkModeClassNames();
  }

  return (
    <React.Fragment>
      { !dataList
        ? // render empty display
        : // render the list
      }

      { userId &&
        // render the edit/add options
      }
    </React.Fragment>
  );
}

Because JS nor React will balk if any of those three properties are unassigned, we can (and should) take different actions depending on if there’s actually an object attached to that variable. React makes this easy enough with their conditional in-line rendering.

What we see here inside the logical operators is shorthand for “Is this defined?” and when we apply the bang “Is this NOT defined?” It’s checking both that the variable has been defined, and that it has been defined in a usable way (ie, dataList isn’t null). We could do this manually and explicitly…but that’s not good, idiomatic, or smart JavaScript. It’d be like writing one’s own “string.IsNullOrEmpty()” method instead of using the built in C# method.

You’ll see I open my first ternary with a bang (aren’t you glad you’re not paying for this content??). I did this because I felt, in this case, it IS the most explicit approach. I wanted to indicate what the next person in the file should pay the most attention to–the component cares if the listData is missing. We could invert this ternary and get the same result…but, I wanted to emphasize “The weird, early-return style behavior happens when there’s no list data.”

And yes. I’m using a ternary here, two if we count the neat short circuit with the userId. For one thing, I can break it up over several lines for clarity. For another, it would be significantly more work to replicate this behavior in a different pattern. It makes sense, and (based on the existing examples in the code base plus all the reading I did) it’s idiomatic React.

TL;DR…

I had a major polyglot growth moment. I embraced the features of a language that just wouldn’t fly in my “home” tech stack, and I added a whole mess of tools to my kit to use and reference going forward. What is nonsense in a typed language is totally fine in an untyped one, and that’s okay.

Yes, We Have No NaNoWriMo: An Exploration on Priority

At this point it may be obvious, but the whole software-version-NaNoWriMo didn’t get out of the “add cards to a Github project” phase. What might not be so obvious is this totally okay. Preferred, even, though I know that’s going to sound counter-intuitive (or even like a cop-out).

So let’s talk a bit about Priority.

Merriam-Webster defines “priority” in part as

“The quality or state of being prior” or “Superiority in rank, position, or privilege”

Merriam-Webster.com

That conjures up images of “priority boarding” or “priority projects” or “making that task a priority.” We’re moving or designating something to the head of the line. Something with or or being given priority is more important than other things, for whatever reason.

“But John–does that mean your BHAG wasn’t important enough to get to the top of your priority list?”

me, impersonating the reader

Hold on just a minute — I’ve got another definition to cover that should address this.

This time, it’s a definition for “economics.”

“Economics is the art of satisfying unlimited wants with limited resources.”

A CSCC Economics Instructor Whose Name I Wish I Could Find

While economics generally uses capital, material, labor, land, and similar such as “resources,” I think of personal resources. Time is a resource. Rest (personal energy level) is a resource. Brain power (cognitive ability) is a resource. And they are absolutely finite, and absolutely limited.

As much as I might wish to, I cannot simply make myself have more energy in a day than I do. I can maximize it with good sleep hygiene, diet, and exercise–but when I’m tired, I’m tired. I only have a certain amount of cognitive cycles in a day. I can be efficient by writing code in small (test-driven) bite-sized pieces, and protect myself from burning through them all by taking frequent breaks–but I’m going to hit a point where it takes me too long to figure out whether 2+2 and 22 are equivalent. There’s only 24 hours in each day–I can be efficient with them, but at some point the the day is going to end regardless of my to-do list.

This means I have to apply economics to my life–I have to apply the lens of Priority.

When I think of Priority, it IS about what’s important, but there’s more to it. What simply can’t go undone lends something a higher Priority score. But then again, if something will increase my personal resource pool, it might gain Priority even though there’s no explicit need to do it sooner. Will something shrink my resource pool, and can I afford to that that hit right now? It’s a loose ranking of “How much this thing helps me be my best self.”

This isn’t a new concept, doing the truly important things first. Franklin Covey talks about putting big rocks a jar; my therapist talks about prioritizing self-care. It’s a pretty fundamental concept in time management–you do what’s most important first, and the rest falls by the wayside.

While most of us are good at this within individual, well-defined buckets–we’re consistently able to put an e-mail to the client ahead of watering our desk plant, putting sleep ahead of being at the bar till close on Tuesday, remembering our spouse’s birthday and celebrating it–sometimes we don’t always apply Priority to those buckets in relation to each other. Or worse, we place items in the wrong bucket–letting us allocate resources incorrectly, leaving us unbalanced and weakened.

All of this to say…

The issue with my little NoNaWriMo challenge is it’s easy to mis-bucket. It’s a project I expressly create for my personal time; a side project. This implies it should have been easy to work in–just watch less TV, or play fewer video games, or cut out that movie with the wife. But the reality of when it needs to happen does not change what bucket of personal resources is allocated to the effort. For all useful intents and purposes, a software developer’s side projects are part of their professional life. Let me say this again, for the young devs in the back who need an answer in some tech bro’s interview:

A software professional’s side projects are non-compensated professional activities, typically undertaken in time that would otherwise be spent on self-care.

This means the personal resources I have available for these projects, no matter how big or hairy, come from the same bucket as my day job. If my day job has eaten up all or more of it’s allotted brain cycles, there are none left for the side project. If I feel drained after pouring hours of energy into sprint planning and code review discussions, there is no more energy leftover for the side project. If I worked overtime to get a functionality in ahead of a deadline, then there is drastically less time available for side projects (because without one’s other activities, one is worthless). If re-engineering a module to satisfy contradicting new and legacy requirements gives me a headache by 2pm, there’s no way there’s any brain power left in the tank for that side project.

Alternately, even if work was easy and I have plenty of excess resources: if I’ve slept poorly and need to prioritize keeping my evenings low key, there’s no room for the side project. If my spouse had a bad day with work and needs extra support, there’s no time or energy for the side project. If therapy dug up some sticky stuff I need to process, there’s no ability to work on the side project. Because balance means nurturing yourself and your support network, not just your professional life.

TL/DR:

Nearly every day in November, applying this Priority lens to my left showed me one of two things: either I’d expended everything allocated for work at the day job, or I’d been presented with an opportunity to invest into myself or my personal relationships. I refuse to view this as a problem.

A Software Version of NaNoWriMo

Every month in the United States has at least one official theme (I have no idea how these get set–is it Congress? Lobbying groups? Industry organizations that just spend enough money on ad campaigns? But I digress…) and November’s is National Novel Writing Month.

This includes an initiative called NaNoWriMo that started in 1999 (hello, “Holy crap I remember things from over 20 years ago” feels) to encourage writers to tell their story–and write 50k words of their novel during the 30 days of November.

But John, What the Hell Does Novel Writing Mania Have to do with Software?

Very, very little. At first glance anyway.

I tend to make tenuous, difficult-to-explain connections between concepts. Essentially what I’m working with here is motivational techniques, specifically two concepts: Big Hairy Audacious Goals and the Buddy System.

BHAG Connection

NaNoWriMo calls for writing 50,000 words of a novel in 30 days. That’s one of the biggest, hairiest, most audacious goals I can imagine. That’s 1,667 average words a day that advance a plot, develop characters, build a world in which those characters exist. That’s a significant amount of time, brain power, and creativity to apply consistently in a fairly short amount of time (with the looming American holiday season, no less).

I’ll paraphase Jim Collins in case you didn’t click thru the link above: if you want to do great things then you need to have big goals. Collins uses the moon landing as a key example of a BHAG–in 1960, John F. Kennedy said, “We’re going to put a man on the moon by 1970.” It was big enough to beg the question “HOW?!” which is exactly what gets the brightest minds in a room excited. It was also based in reality, since this is the nation fresh off the high of inventing the atom bomb, defeating Japan, and re-conquering western Europe all in the same 4 year period–conceivably, that same energy and ability can simply be redirected.

In case anyone missed the memo, it worked–NASA pulled the collective engineering genius, industrial capability, and economic power of the nation in line behind this goal and made it happen. Without the driving force of “We have ten years to do a massive thing from scratch” it’s conceivable delays and rationalizations could have made a moon landing impossible–look at how long it took to replace the Space Shuttle program without a compelling goal.

Buddy System

One of the major draws of NaNoWriMo I’ve observed is the community. People are pack animals–we tend to be at our best when surrounded by other people with the same goals. If anyone has been on “Author Twitter” during November can cite plenty of examples–people encouraging each other, talking up each other’s efforts, giving support when people hit their wall (because it’s all too easy for a BHAG to switch from motivational to a mental health trap). It’s just easier to do difficult things when you’re not the only one doing it.

You’ll see this (sort of) with Advent of Code. Particularly on teams that use the framework for team or skill building, or groups of peers who share solutions and challenges. The fact that there are people also making themselves tinker with code after working with code all day and are expecting to see your attempt is often what’s needed to power thru. The simple knowledge that you’re not in it alone (and that others know it too) can help one tap into a powerful reserve of motivation.

Applying the Concepts to a Side Project

A developer who is employed full time and has interests outside of software is sort of like NASA in 2011–yeah it would be nice to have this accomplishment, but it’s sort of taking most of our budget (energy) coordinating Soyuz trips with Russia (writing code to pay the rent).

This is 100% valid, for the record. Your side projects (or lack of them) have nothing to do with your value as a person, a developer, or an employee.

But say that because of who you are as a person, you’re frustrated by the lack of momentum on an idea you want to bring to life. Having that BHAG to move things forward significantly might be what motivates you to solve the problem of “How.” Finding a buddy or community working similarly big, hairy, and audacious goals can provide the support and accountability typically missing from these solo projects.

So when a friend of mine suggested I join in on NaNoWriMo with her this year, it planted the seed of “Yes, and what if I wrote software instead of a novel?”

So if not a Novel, then what’s the BHAG?

My goal is to deploy an MVP of a product I’ve had percolating for a couple months now. Shove it from the current v0.1 up to v1.0 and reevaluate.

Currently, I’m sitting on a non-trivial shell product:

  • One can create an account with a customized flow
  • One can see slightly different content whether they’re logged in or not
  • I have a CI/CD pipeline using Github Actions
  • I have a test environment in Azure

And that’s it. It started as an excuse to play with ASP.net Core and then I stalled once I reached those 4 milestones, little more than a Sprint Zero well done.

So what’s involved?

My product is yet another way to teach people how to write software (because there are plenty of resources for learning to code–but turning code into software is another sport altogether). I plan to develop my own platform (because writing code I want to write is different from code I’m paid to write) as well as the content.

I have 31 initial stories across 9 features–but there’s several spikes that I expect will lead to additional stories. That’s already more than 1 story per day–and based on my “Sprint Zero Point 2” work this past week, that’s 100% not realistic.

So Why Do It?

Because I’m pragmatic. And agile. I feel goals–even BHAGs–are guidelines, landmarks to track to gauge progress and priority. They’re a thing to aid in decision making. If I get to Thanksgiving and I’m looking at 40 cards in the “Done” column, I’ve learned things. If I’m instead looking at 4 cards, I’ve also learned things.

And in either case (or the more likely middle ground case) I’m still closer to the ultimate goal than if I did nothing.

Beverly Hills FizzBuzz

I recently started spending a likely-unhealthy amount of time watching TikTok videos. This is only of interest (possibly) to blog readers because it led to undertaking this little piece of video art.

That’s right. Over the course of a month or so, I dedicated free time to test driving a non-trivial implementation of FizzBuzz. It involved not just FizzBuzz, but a SongPlayer, a song structure, and a console app to display the process. I also spent way too much time figuring out how long Fizz and Buzz and FizzBuzz should be played, in order to best sync to the music.

If you’re at all interested, I have the whole thing in a Github repo. This should at least explain why I haven’t been continuing the battleship game walking skeleton…

Battleship Travis-CI

The What:

There are a lot of CI/CD systems out there. If you’re in .NET land, Azure DevOps has some pretty excellent tooling out there. Jenkins is another that has some extremely robust capabilities. There are oodles more I’ve never even brushed up against, including rolling your own on a virtual machine somewhere in the cloud (or even on your own machine).

But wait. What the heck is a CI/CD pipeline? Why do you need one? If you’re asking either of those questions, please take a look at this recent post of mine.

The Why:

This post is about Travis-CI, because

  • It’s free (for our use case, anyway)
  • It integrates beautifully with GitHub (which is my repo of choice)
  • It’s platform agnostic (works equally well for a variety of tech stacks)

The How:

Step One is to get yourself a Travis account. This is absurdly, almost suspiciously easy: you sign up with your GitHub account.

This means you may need to allow Travis as an authorized connection or app in your GitHub account, because Travis will be accessing your repo in order to detect changes and to clone the repo so it can build the application.

Screencapture of the Travis-ci.org webpage with sign-up buttons
The “Sign Up” button will give you another button to use your GitHub account

You’ll end up at your dashboard, which eventually will display your most recent build and a quick link to your repositories–for now, you shouldn’t see anything.

Step Two is to link a repository, which means you need to access your profile settings. Click your avatar in the top right of the screen, then the “Settings” link.

Screen cap of the travis-ci.org home page with arrows point to the profile menu and settings link

Step Three is to find and switch on your repository so Travis knows to check it for builds. Your public repos are all listed under the “Repositories” tab, which should be the default view (private repos required a paid subscription with travis-ci.com, currently).

Screen capture of the travis-ci.org settings page for jdmac020 with arrows pointing out the repository tab and list

It can take several minutes for your repositories to show up in Travis the first time. You may have to click the “sync account” button. It also may take refreshing the browser window itself–I once waited almost ten minutes to see a repo list and as soon as I refreshed the browser it all showed up.

Find the one you want to activate, and toggle it on.

Screen capture of jdmac020's repository list with arrows pointing out battleship-tdd and the activated toggle switch

Now Travis is going to be scanning that repo through GitHub APIs and looking for a .travis.yml file to get build instructions. Which means…

Step Four is to create a .travis.yml file in the root of your repository. The dot-travis file is, as you might guess from the dot starting the name, a configuration file used by the Travis-CI build system to know what language you’re using, what build environment to use, what commands to run, and any deployment steps. It’s sort of a big deal, and if there’s no .travis.yml file found in the code pushed to GitHub, Travis simply won’t do anything.

Again, you want to create an empty file in the root of your repository–not necessarily the root of your code base. Find the .git folder, and save your yml file there. I do this step typically in VS Code or Notepad++, depending what OS I’m on.

A save file dialogue showing the root of a git repository

Step Five is to define the build configuration. This will vary significantly depending on which language you’re developing in and what flavor of that tech stack you prefer, and the folks at Travis do a really great job documenting what goes in the .travis file.

Screen capture of travis-ci documentation with an arrow pointing to the list of supported languages

The .travis.yml file I will use for this project including some helpful (to me, anyway) comments about what each line means…

language: csharp
# Mono is used to build .NET on Linux--we don't need it with Core.
mono: none
# Needed to run commands in the Xenial CLI
sudo: required
# The version of Ubuntu to run the Travis virtual machine -- needed for .NET Core
dist: xenial
# Your SDK version, not your run-time version
dotnet: 2.2
script: # These commands are executed in the Travis VM just like you would on your local machine
# Use a "cd" command to move the Travis command line prompt into your solution directory
# - cd /home/travis/build/<yourTravisAccount>/<yourRepoRootDirectory>/.../<yourSolutionDirectory>/
  - cd ./BattleshipTDD/
# Use these to build the project without tests
# - dotnet restore
# - dotnet build
# if your project has tests, you can skip "restore" and "build" and just use "test" command -- "test" will run the other two automatically
  - dotnet test

Step Six is to commit the new file and push it up to your repo, where Travis should catch the change and trigger a build.

A computer terminal screen displaying the commands to add, commit, and push the the .travis.yml file to the repository
You could do this in a GUI if you’d prefer, 100%

Step Seven is to review the build in Travis. Even before I was done prepping the terminal photo above for the post, I got an e-mail from Travis saying my build passed–hooray!

When we look at the dashboard we get some key items right away. The repository name and a build badge are at the top, and then the specific build info–what branch was built, the commit message, commit ID, the build number, how long it ran for are all front and center.

Screen capture of Travis-CI dashboard with a passing build

If we keep scrolling down, you can see the actual build logs, starting with info on the build environment–handy for debugging problems, like when your build is fine locally, but fails when Travis tries it.

For instance, if one tries to run a .NET Core app in the default Travis Linux OS, it won’t work–hence needing to specify Xenial to make sure we were running on Ubuntu. Being able to compare the build environment with the suggestion on a help document was key to figuring this out.

A build log with environment info

Scrolling down further we get to the actual build process. Each command you specify in the .travis.yml is listed out separately–you can see on line 246, even the “cd ./BattleshipTDD/” got it’s own result output (and yes, I have seen this fail, especially on complicated solution structures where I was missing a directory level in the path).

The test output is particularly helpful–my one test passes here, but should it fail it outputs the exception message just like any other test runner, letting you know what failed and why.

At the very bottom, the build status gets reported–if any of the commands exited with anything except a 0 code, the entire build is marked as a failure.

A build log showing the results of build tasks

Some examples of unhappy build logs…

Build log displaying a bad change directory command
You get the results of a bad command, guiding you toward a fix

Build log with failing test info
Failing tests give you the output of your testing framework–no guessing what happened

Wrapping It All Up:

What we’ve done here is linked your GitHub to Travis-CI, which will build the project and run tests against it whenever changes are pushed to master. This by itself may not provide a lot of value (I mean, if you’re not running your tests before pushing code, we need to talk) but it does lay an important foundation.

From here, we’re able to automate deployment, headless browser testing, dockerizing, packaging, updating a badge on your repo to tell the world your code is sound, and more. And it happens without having to remember it–push the code, and Travis checks it. It’s one heck of a safety net, if nothing else. It lets you focus more on the code than on the boring devopsy* stuff.

*I mean, I don’t exactly think devops is boring stuff, but no shame if you do–most programmers get into code to write code, not manage deployments and QA etc etc etc.

Blog at WordPress.com.

Up ↑