Our Dishonest Discourse About “The Hard R”

A controversy that began with this open letter asking Spotify to “take action against the mass-misinformation events which continue to occur on its platform” (with regards to COVID-19 and vaccines) and musicians including Neil Young and Joni Mitchell pulling their music from the platform took an interesting turn when India.Arie shared a supercut of Rogan not just using “the hard r”, but calling black people apes in talking about why she was pulling her music from Spotify. Joe Rogan has since apologized, and Spotify removed 70 podcast episodes where he used the slur.

It is possible, if not highly likely that I am being overly cynical regarding the sincerity of Rogan’s apology. My cynicism is animated at least in part by how often mea culpas for this sort of thing include phrases similar to this:
“It’s a video that’s made of clips taken out of context of me of 12 years of conversations on my podcast. It’s all smushed together and it looks f—— horrible, even to me”

and this:
“I never used it to be racist.”

and especially this:
“I do hope that this can be a teachable moment.”

This last quote in particular is one that provides an opportunity to pivot to academic usage of “the hard r”. Randall Kennedy argued last year in favor of what might be called a pedagogical exception for the word to be used in full for teaching purposes. Included in his argument however, are skepticism of some of the claims of hurt by students hearing the word used. Further, he argues that his race should not give him more leeway to use the n-word than his white colleagues. Dr. John McWhorter, a professor of linguistics, has written about the n-word on multiple occasions prior to the controversy over Rogan’s usage of it. Beyond pedagogy (in use) or virtue-signaling (in non-use), the question not being asked or adequately answered is why this debate only seems to persist around the use of a slur that only applies to black people (though there is a modifier for it that applies to Middle Eastern people that I first heard in the movie The Siege)?

This quote by James Baldwin poses and answers that question more eloquently and bluntly:
“What white people have to do is try and find out in their own hearts why it is necessary to have a ‘nigger’ in the first place, because I’m not a nigger. I’m a man. But if you think I’m a nigger, it means you need it.”

A poem written in 1912 and attributed to H.P. Lovecraft, provides another answer to where the necessity for the word (and the idea) comes from:
“When, long ago, the gods created Earth
In Jove’s fair image Man was shap’d at birth.
The beasts for lesser parts were next design’d;
Yet were they too remote from humankind.
To fill the gap, and join the rest to man,
Th’Olympian host conceiv’d a clever plan.
A beast they wrought, in semi-human figure,
Fill’d it with vice, and call’d the thing a NIGGER.”

In Lovecraft’s conception (and almost certainly in the conception of others who subscribed to the eugenics movement as he did), black people were not fully human. We were beasts to be feared, objects of and/or causes of lust, purveyors of vices, corrupters of innocence–but not human beings like everyone else. While Lovecraft is long since dead, the sentiments behind his poetically-expressed contempt for black folks live on in others–not just in the body politic, but in some of its leaders as well. This is why the governor of an entire state can say publicly that Joe Rogan should not have apologized (for using the n-word). I believe this to be at the heart of why the debate over the word continues.

To borrow from James Baldwin again, he expresses the sentiment well regarding how American society in his time used and viewed black people:
“That in a way black men were very useful for the American. Because, in a country so absolutely undefined – so amorphous – where there were no limits – no height really and no depth – there was one thing of which one could be certain. One knew where one was, by knowing where the Negro was. You knew that you were not on the bottom because the Negro was there.”
Though decades have passed since Baldwin spoke these words, it seems that America has yet to outgrow its need for black people to define where the bottom of society is, and the casual (if not unapologetic) usage of the n-word is just one manifestation of that broader sentiment. I maintain no illusions that this affliction is unique to the political right, or to libertarian ideology. Those on the political left are no shrinking violets when it comes to using “the hard r”.

It is very telling that many of the same people who rush to defend voices of dissent in other contexts lack the same concern when it comes to black people objecting to the use of a slur targeting them. The social norms against using slurs and stereotypes which attack Jews, or Italians, or the Irish, or Hispanics, or Asian people remain intact. You rarely (if ever) see people from those communities presuming to give out metaphorical hall passes for others to use slurs against them without consequences. Because black people are still not seen or treated as full citizens of this country, our opinions on “the contours of acceptable speech” lack the same weight as those of others. Too many people in this country apparently still prefer an older version of it where slurs against black people could be said without consequence. But that isn’t a version of America we’re returning to.

Is a College Degree Worth It?

Public discourse has turned (again) to the question of whether or not a college degree is “worth it”. I say again because in the tech industry, this question has been asked about computer science (CS) degrees over a decade ago. I was prompted to revisit this blog post from over 14(!) years ago by Scott Hanselman’s response to a TikTok video saying a computer science degree is never worth it:

 

Back in 2007, I was managing a team which consisted mostly of what Tarver calls “street programmers”.   In that particular experience, Tarver was wrong about street programmers being superior to formally-trained CS graduates.  The members of my staff who consistently turned out the highest-quality code (which not coincidentally was also the best-tested and the least likely to require re-work) all had CS degrees.  In my next role, one of my colleagues was an Air Force veteran who was self-taught in software engineering.  He was one of the most skilled engineers I’ve worked with in my entire career, and taught me a ton about the practice of continuous integration over a decade ago that I still use in my work today.  

In re-reading Tarver’s post, even he concedes that the combination of hands-on programming practice and a strong grasp of theory creates a superior programmer when compared to one trained only in university or only on-the-job.  The other thing which struck me as odd in retrospect was the lack of any mention of summer internships.  Back in the early-to-mid 90s when I was earning my own computer science degree, it was definitely the expectation that CS majors would complete at least one summer internship before they graduated so they had at least a little experience with programming outside of coursework requirements.  I found an on-campus job where I worked during the semester which at least had tasks that I could automate with scripts, as well as database work.  My summer internship with The Washington Post as a tech intern turned into a part-time job my last semester of undergrad and a full-time job offer at the end of the year.  So instead of a declarative statement such as “college is never worth it” or “college is always worth it”, a better answer to the question is more like “it depends”.

Quite a lot has changed since 2007 when it comes to the variety of ways available to learn about programming.  There are lots of programmer bootcamps now.  My current employer partners with one to train college graduates with degrees in fields other than computer science for entry-level software engineering roles with us.  Beyond instructor-led bootcamps, there are a wealth of online education options both free and paid.  Having worked with engineers who came into the field via the bootcamp route at two different companies now, I’ve seen enough inconsistency in the readiness of bootcamp graduates for professional work that most require more oversight and supervision at entry-level positions than graduates from computer science programs.

At least some of the discussion about the worth of college degrees (in CS or many other fields) is a function of tuition continuing to increase at rates triple that of inflation (and have been doing so for decades).  The total amount my parents spent on in-state tuition for my CS degree in the 90s might not even cover 2 years at the same school today.  A year of tuition at my 1st-choice school today, Carnegie-Mellon University costs at least triple the $24,000 they charged in 1992.  It might be possible to rationalize paying high tuition for a STEM degree with high long-term earning potential, but those high tuition rates apply regardless of major.

Another issue that discussions of whether or not college degrees are “worth it” consistently misses is how open different fields and companies within those fields are to hiring people without formal training.  Particularly in tech, that openness exists for white men in a way that it definitely does not for people of color.   Shawn Wildermuth’s documentary Hello World gets deep into why women and minorities tend not to pursue careers in software development and even with the credential of a college degree and experience, it can be very challenging to sustain a tech career–much less advance–if you don’t look like the people who make hiring and promotion decisions.

Count me in the camp of those who believe a CS degree is worth it.  I wouldn’t have the tech career I have today without it.

False Unity and “Moving On” is Dangerous

Even before yesterday’s inauguration of Joe Biden and Kamala Harris as the new President and Vice President of the United States, there were calls for unity—even empathy—and not just from Joe Biden.  Such calls seemed very premature at the time, given the efforts of Trump and his allies to overturn the election result.  With the failure of those efforts, despite a literal assault on the entire legislative branch incited by Trump resulting in five dead, such calls for unity and healing look even more naive.

Too many so-called conservatives (and some of those further left on the political spectrum) would rather put unity ahead of accountability. MAGA adherents and believers in the QAnon conspiracy theory essentially invaded the  US Capitol and delayed the legislative branch from executing its responsibility to certify the Electoral College results at the urging of the president and his allies. They may have been aided and abetted in this insurrectionist act by multiple members of the GOP in both the Senate and the House. At least one shared the location of Speaker Pelosi on Twitter, as if to direct insurrectionists to her location.  The wife of a Supreme Court justice may have funded the transportation to the Capitol for some of these insurrections.  Even the death toll, the damage to the US Capitol, and the risk to their own lives did not prevent some Republicans from voting against certification of the Electoral College tally once the Capitol was secured.

Placing unity before accountability too many times before is what has led the country here. Unity before accountability killed Reconstruction, subjecting black Americans to almost another century of domestic terrorism, property theft, and subjugation at the hands of whites. The Nixon pardon, the Iran/Contra pardons, and the lack of accountability for those who engaged in torture and warrant less wiretapping of US citizens all placed unity before accountability.  All of these actions paved the way for President Trump to be acquitted despite clear evidence that he tried to shake down the president of Ukraine in exchange for the announcement of an investigation into Hunter Biden.

Less than a year has elapsed between the Senate’s acquittal of Trump on two impeachment charges and the insurrection on January 6.  Only a tiny number of GOP House members put their country ahead of their party in voting for a second impeachment.  A second acquittal for Trump seems likely–and we will live to regret it.

Does Your Business Card Run Linux?

Mine sure doesn’t, but George Hilliard’s does:

https://www.thirtythreeforty.net/posts/2019/12/my-business-card-runs-linux/

Though I’ve spent the majority of my career building web and desktop applications, I’ve always been fascinated by embedded systems. More than 20 years after earning my bachelor’s in CS, the most fun course by far was a robotics elective I took my final semester. I’ve forgotten the name of the boards we programmed, but we wrote the code for them in Objective-C and built the robots out of whatever sensors, gears, and LEGOs we had (this was years before LEGO Mindstorms).

The end-of-semester competition was to build a robot that navigated a maze, found a light, touched it, and played a little tune. The robot my team programmed and built placed 2nd (our robot got to the light and touched it first, but didn’t play the tune for some reason).

Since then, I’ve played around with the blink(1) a little bit, but not more complex things like Arduino or Raspberry Pi. I’ve not had much success with the whole new year’s resolution thing, but in 2020 I want to complete a project that runs on some hardware. I haven’t picked the hardware yet, but definitely something that involves sensors and data collection. A weather station is probably the most ambitious idea that comes to mind that I might pursue further. In the interest of crawling before walking (or running), I probably need to start with something much simpler.

Getting (and Staying) Organized

During the past year-and-a-half as a software development manager for a local consulting firm, I’ve tried a number of different tools and techniques to keep me organized.  As my role expanded to include business development, hiring, and project management tasks, there’s been a lot more to keep track of.  I meet weekly or twice-monthly 1-on-1 with each team member on my current project.  “Move it out of e-mail” is my primary objective for getting organized.  The rest of this post will elaborate on the specific alternatives to e-mail that I tried on the way to my current “manager tools”.
Outlook
Beyond e-mail and calendar functionality, Outlook offers a To-Do List and Tasks for keeping organized.  Both provide start dates and due dates.  The To-Do List is tied directly to individual e-mails, while Tasks are stand-alone items.  I abandoned the use of task functionality pretty quickly.  I used the To-Do List as recently as July of this year, but I see it as a bad habit now.  I rarely end up clearly the various options to flag an e-mail for follow-up (Today, Tomorrow, This Week, Next Week, No Date & Custom), so they become an ever-growing list where I only very occasionally mark items as complete.  In addition, the search functionality in Outlook never works as well as I need it to when I’m trying to find something.
Lighthouse
Once I passed the six month mark with my employer, I felt comfortable enough to introduce weekly 1-on-1s as a practice on my project.  After a couple of weeks of filling out a paper template from these guys for each team member on my project, the need for a better solution became readily apparent.  Lighthouse is the name of the company and their product, a web-based application for managing your 1-on-1s with staff.  After the free trial, I chose not to renew.  While I like Lighthouse, and the cost wasn’t prohibitive, my employer wasn’t going to pay for it.
I liked the ideas in Lighthouse enough that I tried to build a simpler, custom version of it myself.  Increasing work responsibilities (and the birth of my twins, Elliott and Emily) erased the free time I had for that side project.  Lighthouse maintains a leadership and management blog that I’ve found to be worthwhile reading.
Trello
I first started using Trello years ago for something not at all related to work–requesting bug fixes and enhancements to a custom website my fantasy football league uses.  I didn’t consider using it for work until I was re-introduced to it by a VP who uses it to keep himself organized.  Once I reviewed a few example boards and set up a board to moderate weekly business development meeting, new possibilities for its use revealed themselves very quickly.  As of today, I’ve got 4 different boards active: 1 for “hiring funnel” activities, another board for business development tasks, a 3rd for project-specific tasks that don’t fall into a current Scrum sprint, and a 4th board as a general to-do list.  The last board turned out to be a great solution for capturing information from my 1-on-1 meetings.  It also tracks my progress toward annual goals, training reminders, and other “good corporate citizen” tasks.
The free tier of Trello service offers the functionality that matters most:
  • create multiple boards
  • define workflows as simple or complex as you need
  • create cards as simple or complex as you need
Markdown formatting, attachment support, due dates, checklists, archiving, the ability to subscribe to individual cards, lists and/or boards and collaborate with other team members of Trello combined with the key functionality above has helped me become much better organized and able to communicate more consistently with my team members and executives in my organization.  The search capability works much better for me than Outlook as well.
I’ve only gotten a handful of co-workers in my organization to adopt Trello so far, but I keep recommending it to other co-workers.  I’d like to see our entire business unit adopt it officially so we can take advantage of the capabilities available at the Business Class tier.

Bulging Laptop Battery

Until yesterday, I’d been unaware that laptop batteries could fail in a way other than not holding a charge very well. According to the nice fellow at an Apple Genius Bar near my office, this happens occasionally.  I wish I’d been aware of it sooner, so I might have gotten it replaced before AppleCare expired.  When I did some googling, “occasionally” turned out to be a lot more often than I expected.  Half-an-hour (and $129 later), a replacement battery made everything better.  The battery had expanded to the point that it was pushing on the trackpad and making it difficult to click–in addition to preventing the laptop from sitting flush on flat surfaces.  Now that it has a fresh battery (and even though it’s only a late-2011 MacBook Pro), I’m sort of tempted to replace it with a shinier new one.  My new employer is of the “bring your own device” variety, and the MacBook Pro is quite a lot of weight to schlep to and from the office every day.

Reflection and Unit Testing

This post is prompted by a couple of things: (1) a limitation in the Moq mocking framework, (2) a look back at a unit test I wrote nearly 3 years ago when I first arrived at my current company. While you can use Moq to create an instance of a concrete class, you can’t set expectations on class members that aren’t virtual. In the case of one of our domain entities, this made it impossible to implement automated tests one of our business rules–at least not without creating real versions of multiple dependencies (and thereby creating an integration test). Or so I (incorrectly) thought.

Our solution architect sent me an unit test example that used reflection to set the non-virtual properties in question so they could be used for testing. While the approach is a bit clunky when compared to the capabilities provided by Moq, it works. Here’s some pseudo-code of an XUnit test that follows his model by using reflection to set a non-virtual property:

[Fact]
public override void RuleIsTriggered()
{
  var sde = new SomeDomainEntity(ClientId, null );
  SetWorkflowStatus(sde, SomeDomainEntityStatus.PendingFirstReview);

  var context = GetBusinessRuleContext(sde);
  Assert.True(RuleUnderTest.When(context.Object));
}

private void SetWorkflowStatus(SomeDomainEntity someDomainEntity, WorkflowStatus workflowStatus)
{
  var workflowStatusProperty = typeof(SomeDomainEntity).GetProperty("WorkflowStatus");
  workflowStatusProperty.SetValue(someDomainEntity, workflowStatus, null);
}

With the code above, if the business rule returned by RuleUnderTest looks at WorkflowStatus to determine whether or not the instance of SomeDomainEntity is valid, the value set via reflection will be what is returned. As an aside, the “context” returned from GetBusinessRuleContext is a mock configured to return sde if the business rule looks for it as part of its execution.

After seeing the previous unit test example (and a failing unit test on another branch of code), I was reminded of a unit test I wrote back in 2012 when I was getting up to speed with a new system. Based on the information I was given at the time, our value objects all needed to implement the IEquatable interface. Since we identified value objects with IValueObject (which was just a marker interface), using reflection and a bit of LINQ resulted in a test that would fail if any types implementing IValueObject did not also implement IEquatable. The test class is available here. If you need similar functionality for your own purposes, changing the types reflected on is quite a simple matter.

Pseudo-random Sampling and .NET

One of the requirements I received for my current application was to select five percent of entities generated by another process for further review by an actual person. The requirement wasn’t quite a request for a simple random sample (since the process generates entities one at a time instead of in batches), so the code I had to write needed to give each entity generated a five percent chance of being selected for further review.  In .NET, anything involving percentage chances means using the Random class in some way.  Because the class doesn’t generate truly random numbers (it generates pseudo-random numbers), additional work is needed to make the outcomes more random.

The first part of my approach to making the outcomes more random was to simplify the five percent aspect of the requirement to a yes or no decision, where “yes” meant treat the entity normally and “no” meant select the entity for further review.  I modeled this as a collection of 100 boolean values with 95 true and five false.  I ended up using a for-loop to populate the boolean list with 95 true values.  Another option I considered was using Enumerable.Repeat (described in great detail in this post), but apparently that operation is quite a bit slower.  I could have used Enumerable.Range instead, and may investigate the possibility later to see what advantages or disadvantages there are in performance and code clarity.

Having created the list of decisions, I needed to randomize their order.  To accomplish this, I used LINQ to sort the list by the value of newly-generated GUIDs:

decisions.OrderBy(d => Guid.NewGuid()) //decisions is a list of bool

With a randomly-ordered list of decisions, the final step was to select a decision from a random location in the list.  For that, I turned to a Jon Skeet post that provided a provided a helper class (see the end of that post) for retrieving a thread-safe instance of Random to use for generating a pseudo-random value within the range of possible decisions.  The resulting code is as follows:

return decisions.OrderBy(d => Guid.NewGuid()).ToArray()[RandomProvider.GetThreadRandom().Next(100)]; //decisions is a list of bool

I used LINQPad to test my code and over multiple executions, I got between 3 and 6 “no” results.

Farewell RockNUG!

Last week was the final monthly meeting of the Rockville .NET User Group (aka RockNUG) after a seven-year run. I greatly appreciate the leadership of Dean Fiala. It takes a lot of effort to find sponsors, meeting locations, and speakers consistently, and he always came through. Fortunately, the name and domain will live on for future use in special events (like another Robocode programming contest).

Being part of this group made an important impact on my career as a software developer in the DC metropolitan area. I learned a ton from the different keynote speakers over the years. The n00b talk portion of each monthly meeting gave me opportunities to present shorter talks of my own. In these, I learned a lot from the research needed to give a good presentation and from the audience who received it (through their questions and other information they volunteered). I’ve met a number of friends in the industry through this group, and even recruited one of them to join me at my current employer.

A lot has changed since RockNUG first started. For one thing, there are far more user groups now than there were 7 years ago. This means a lot more competition to find speakers. The other change has been in web development on the Microsoft stack–it requires fewer Microsoft-exclusive technologies today than in the past. The increasing popularity of web applications and the success of frameworks like Ruby on Rails, jQuery, node.js, knockout.js (as well as languages like JavaScript) has broadened what those of us working in Microsoft shops need to know in order to be successful. So very few of the talks over the past couple of years have had a .NET-specific focus. Finally, there is a lot of great learning material available on the web now. Between companies like Pluralsight, WintellectNOW, and conferences that post their keynote presentations online, there are a wealth of learning opportunities for developers that don’t even require them to leave their desk.

None of these online options can replace the in-person interaction, networking and opportunities to build friendships that a user group like RockNUG can provide. So even though RockNUG has come to an end, I still believe in user groups. I’ll be on the lookout for groups just like it (or perhaps even create one).

Infinity, Epsilon and NaN

I inadvertently learned some new things about the .NET double struct while refactoring some code over the past couple of days.  A large set of test data we received recently revealed that we weren’t correctly handling the following edge cases of body mass index (BMI) calculation.

  • Edge case 1: a height of zero inches
  • Edge case 2: a weight of zero pounds and a height of zero inches
  • Edge case 3: a weight of zero pounds and a non-zero height

Incorrectly handling the first case resulted in an overflow exception in our code, but only because it tried to pass the result of a BMI calculation that returned the constant PositiveInfinity into another method.  To handle this condition more gracefully (since a height of zero inches and/or a weight of zero pounds are considered valid inputs), a check for PositiveInfinity is needed.  The .NET framework provides the static method IsPositiveInfinity for such comparisons.

Incorrect handling of the second case caused an error as well.  But this time the BMI calculation returned the constant NaN.  Like PositiveInfinity, NaN has a static method to check for it (IsNaN).

Enough time has gone by (and enough code changes have taken place) since I first started this post back in September that I don’t recall precisely what the original code did in the third case.  Under normal circumstances the BMI calculation would return zero, but our implementation returns the NaN constant if the BMI (or inputs to it) falls outside what are considered valid ranges.