personal comments edit

Xev, my baby princess

On Monday, January 8, 2018, I had to say goodbye to one of my best friends of 15 years: my beautiful baby cat girl, Xev.

From the day she came home, July 2, 2002, she was trouble.

Xev out playing on the balcony

She was very playful. You can see she’s messing with a flower on the balcony. Later, she’d end up hanging from the wall just off the balcony, having been chased there by our cat, Semper, and would eventually fall into the bushes below. (She was just fine. A little scared, but no worse for the wear. And she definitely didn’t learn her lesson.)

She was enough trouble that we couldn’t just let her roam free her first few nights at home. We kept her in the bathroom instead. We made a bed for her in the sink and she loved it.

Xev has a bed in the sink

I think keeping her in the bathroom sort of affected her long-term. She loved the bathroom. If you were in there, she needed to be in there. She’d wrap string around the base of the toilet, she’d drink out of the sink… even after we moved and she was much older, she’d still get in the sink to sleep or play.

Xev still has a bed in the sink

There are a lot of bathroom stories to share. She’d come in and climb into your pants while you were… uh… doing your business. You could yell for “Pooping Cat” and she’d come to that. I’ll stop there, you get the idea.

So naughty. Always in exactly the place you needed to get and totally not interested in moving.

Xev sitting in the clothes dryer

Her favorite toys were those foil/mylar balls that made crinkling noises and anything with tassels on it. She didn’t really wrestle or do that thing some cats do where they roll over and kick with their back feet. She was more of a “grab and bite” kind of cat.

Xev with a tinsel streamer

She mellowed out a little with age and loved to sleep in the windowsill or on the floor in that one spot of sun that would come through. She didn’t fight over much, but she’d totally push the other cats out of the way to get there if needed.

Xev in the windowsill

When my daughter, Phoenix, was born, Xev was there from day one to be the watchful mother cat.

Xev with newborn Phoenix

Our other cats were friendly to Phoenix, but they never really played with her or cuddled with her. Xev… Xev was Phoenix’s older cat-sister. They were best buddies.

Xev with six-year-old Phoenix

As you can see, Xev loved being held like a baby and getting her tummy rubbed. She’d purr so loud that if you were watching TV you could barely hear your show.

This past weekend we noticed Xev had basically stopped eating. She looked a bit thin, but she was drinking. We didn’t think much of it because she was always sort of a “free spirit” and did what she wanted when she wanted. However, after a couple of days of not eating, we really noticed how thin she was getting and that she was becoming pretty lethargic.

I took her to the vet to get her checked out and we found she was in the later stages of kidney failure. She had apparently been headed downhill for quite some time and had masked it really, really well. By the time any real symptoms showed it was too late.

Even the doctor noted that she didn’t look 15 at all. I agree, she aged very well. Her coat was beautiful, full, and clean. She smelled clean. She was so active, even up until that last day.

We made the decision to let her go instead of forcing her through painful treatments that may or may not have actually prolonged her life. I wanted her to live a good life without suffering.

She was my catbaby for 15 years and I loved her more than I can say.

Xev, my 15 year old catbaby

Goodnight, Princess Xev. We will miss you forever.

personal comments edit

Each month my six-year-old daughter comes home with a “homework menu” - a page that looks sort of like a bingo card but each square has a homework assignment in it. Of the 25 assignments listed, you get to pick 15 to do.

The assignments cover things like, “Write a list of words with a long ‘i’ sound in them” to “Count to 100 by fives.” First grade stuff, no problem. For the most part, she’s got this covered… as long as she doesn’t get off in the weeds.

The other night we did, “Make a list of ten odd numbers.” Easy enough. They’d been learning odds and evens in class, so this shouldn’t be much work. In fact, she finished in just a few seconds, listing all the way from one to 19 in short order.

To help cement the pattern in her mind, I thought I’d show her how all the odd numbers end in 1, 3, 5, 7, or 9. I wrote the numbers in a little table like this so the pattern would be easy to see:

1    11    21    31
3    13    23    33
5    15    25    35
7    17    27    37
9    19    29    39

She got pretty excited about that, then asked the question that took us off the rails.

Phoenix: Daddy, why are they called “odd” and “even” numbers?

Travis: Go grab me like six alphabet blocks from your room and I’ll show you.

She ran to her room, grabbed the blocks, and returned with them bundled in the front of her shirt. She dumped the whole shirt load squarely on my nuts.

Travis (recovering): OK, you know odd numbers, do you know the even ones?

Phoenix: 2, 4, 6, 8, 10.

Travis: Good. Here’s two blocks. [I hold up two blocks.] Is two even or odd?

Phoenix: Even.

Travis: Right. If I split that into two even piles there aren’t any left over. [I put one block in each hand and hold them apart from each other.] See that? Two even piles. Now here’s three blocks. [I hold up three blocks in one hand.] Is three even or odd?

Phoenix: Odd.

Travis: Correct again. If I split that into two even piles… [I put one block in each hand and hold them apart from each other, leaving the remaining block on the arm of the chair.] …then we have an odd man out. That block on the chair is extra. Odd numbers leave an odd man out. Let’s try with four. Is four even or odd?

Phoenix: Even.

Travis: OK, and when I split them [I held two blocks in each hand] I have two even piles. Is five even or odd?

Phoenix: Odd.

Travis: Yup, and when I split them [I hold two blocks in each hand and leave the fifth on the arm of the chair] I have that odd man out. That’s why they’re “even” and “odd.” If it’s an even number, I get even piles when I split it in half. If it’s an odd number, I get an odd man out. Even number - even piles. Odd number - odd man out.

Phoenix: Oh, OK!

Travis: So, let’s review. [I hold up four blocks, two in each hand.] Four is an even number, so when I split it I have… [I pulled my hands apart with two in each hand.]…?

Phoenix: Four blocks.

Travis: Well, I do have four blocks, but we were talking about even and odd. Four is even, right? So if I split it in half, I have…?

Phoenix: Two in each hand.

Travis: That’s true, but I have even piles. Even number, even piles. Five is an odd number [I hold up five blocks in my hands] so when I split it in half [I drop one block on the arm of the chair and hold two in each of my hands] I have…? [I look down at the block on the arm of the chair hopefully]

Phoenix: An extra.

Travis: Yep, but it’s odd so we can remember it easier if we think “Odd number has an odd man out.” If it’s even you have…? [I hide the block on the chair and hold two in each hand.]

Phoenix: Equal piles.

Travis: Uh… yeah, but I really want to know you’re hearing me here, so “Even number, even piles.” Not “equal piles,” but actually the literal words, “even piles.” I need you to say, “even piles.” Sooooo…. Four is even, even numbers have…

Phoenix: Four.

Travis (really close to losing my shit): Even numbers, even piles. So, even numbers have…?

Phoenix: Even piles.

Travis: Yes, and odd numbers have…? [I put the extra block back on the arm of the chair.]

Phoenix: Odd piles.

Travis: An odd man out. Odd numbers have an odd man out. Even numbers, even piles. Odd numbers, odd man out. Even numbers…?

Phoenix: Even piles.

Travis: Odd numbers…?

Phoenix: Odd man out.

Travis: HALLELUJAH!

I think this is going to be a thing with homework this year since last night we ran into basically the same thing.

Travis: OK, Phoe, you need to draw a hexagon.

Phoenix: How many sides is that?

Travis: A hexagon has six sides.

Phoenix: So, five?

AAAAAAAAAARRRRRRRGGGGGGGGGGGGGGGGHHHHHHH

architecture, process comments edit

Today I want to talk about something I’ve seen in a few places that just frustrates me to no end: the repeated failed strangler pattern.

To make sure we’re all on the same page: The strangler pattern is when you want to overhaul an existing system and you do so by wrapping it in a facade. You swap out components under the facade from old bits to new bits, eventually strangling the old system and removing the facade so only the new stuff is left. The idea is that doing this over time potentially has lower risk than rewriting an existing system from scratch.

There are a couple of articles on this pattern here:

In general, I think this is a decent pattern. However, I take issue with the implication of this line from the Fowler article (emphasis mine):

They aren’t yet at the point where the old application is strangled - but they’ve delivered valuable functionality to the business that gives the team the credibility to go further. And even if they stop now, they have a huge return on investment - which is more than many cut-over rewrites achieve.

My challenge is around the notion that you can do a partial strangler and that’s an OK - or even good - thing.

My experience directly contradicts this. Let’s take a hypothetical example:

Let’s say you started out a long time ago, in a galaxy far, far away, with a simple string processing engine. It was long before SOAP or REST. It did what it needed to do, you sold it, and you got some customers up and running with it.

String processing engine

So far, so good. SOAP comes along, and XML is pretty awesome, so you decide you want to start moving away from arbitrary string-in, string-out and to something with more formal contracts. Cool! Strangler to the rescue. Except… you do still have some customers that won’t really be able to update right away… you need to leave access to the original string processing engine in place. New folks can take the new interface, though, so that’s good, right?

XML messages wrapping the string processing engine

Turns out the strangler to convert strings to XML wasn’t quite SOAP due to some custom extensions you needed to create to make it work with the string processing engine. You still really want some SOAP wrappers on this thing, though, so you can start decoupling things and iterate faster over individual services/features. Let’s wrap the XML message handling with actual SOAP contracts that are pretty close to but not exactly like the XML messages.

Except… you sold the XML messaging to some customers and they can’t really switch to the slightly modified contracts for the services. And you really haven’t pushed those original string processor customers to upgrade yet because they’re threatening to leave if you create any breakages.

SOAP services wrapping XML messages wrapping the string processing engine

OK, this time for reals - REST is a bit lighter weight and would lend itself better to some of the new prospective clients’ needs. Getting some REST microservice support in there could really get things going, especially since most of the developers you’re hiring now are more versed in REST and that’s the direction your market is going.

(I bet you see where this is going…)

Except… now you have customers on all three previous layers: SOAP, XML messaging, and string messaging. Gotta keep access to all three of those things. No breaking changes! Ever!

REST services wrapping SOAP services wrapping XML messages wrapping the string processing engine

Does that look at all familiar?

Seems like a bit of a design flaw...

This is why I call it “Death Star Architecture.” You’re not finishing the strangler, so instead of getting the benefit of the pattern, you’re just adding layers to your system that all need to be maintained and tested.

Finish your strangler!

Finish your strangler! In the short term it may seem like you’re getting benefits, but long term the unfinished work results in technical debt that will ultimately cause your destruction.

autofac, dotnet comments edit

Time to address a frequently asked question I see with Autofac and many other open source libraries I use or work on:

I’ve upgraded the (target framework/base libraries/build/.NET SDK version) for my application and now I see build warnings due to transitive dependencies. Why don’t you upgrade the library dependencies to a later version to address an issue I see in my application?

I see this a lot in the .NET Core realm, where use of many small dependencies rather than a big installed framework is a new thing. It’s not so much a question in places like Node.js where the use of many small, chained dependencies has been around for a while.

What it boils down to is that there’s a difference in how you manage dependencies in libraries and applications.

Libraries Target Compatibility

When you have a library, you want to make sure it’s stable and compatible for your consumers, both at the outset and across upgrades. People want the latest features and bug fixes, right? This means a lot of things including:

  • Interfaces need to be stable. If you change an interface, people consuming your library may not be able to take the next update. That means for any public and protected interfaces and classes you have to be very mindful about changes.
  • Dependencies need to be stable. If the library takes an update to a dependency, at a minimum that means anyone taking the next version of your library is forced to take an indirect update to the dependency. It may mean forcing a breaking change onto the library consumers who may be directly referencing the dependency and can’t take that update.
  • Target the lowest common denominator. That means targeting the lowest version of the .NET Framework or .NET Standard that you can. Lower target version means more compatibility. This also means targeting the lowest version of dependencies you can for the same reason - lower version means generally more compatibility, especially with folks who are already using the transitive dependency.
  • Keep the target framework stable. Increasing that target .NET Standard or framework version means the new version of the library may not be compatible with existing applications - people will be forced to update their applications or may just be locked out of using the new version of the library.

As you can imagine, any changes here can cause unforeseen ripple effects. Upgrading a dependency version may fix one issue but could cause downstream consumers problems you can’t anticipate.

The general rule for dependency/framework versions is to target low and keep it stable.

Applications Target Features

When you write an app, your largest concerns are the features you need and the target environment in which it’s going to run. It means priorities shift as far as compatibility and upgrades are concerned.

  • If you need a new dependency feature, you can just take it. If you see something new you need out of a dependency - a feature, a bug fix, whatever - you can take the upgrade when you want.
  • Breaking API changes are surfaced differently. This may be a REST API, a command line argument interface, or a plugin abstraction, but bringing in a new application dependency generally doesn’t cause a breaking change for application consumers.

Application dependencies generally don’t end up affecting application consumers.

Addressing Library Dependency Scenarios

By and large, when you see an issue with a transitive dependency coming into your application, the solution is to add a direct dependency in your application to the version you want.

Some scenarios you may see in the .NET Core world to help make this concrete:

  • Security updates in .NET Core. When security issues are detected in .NET Core base class/framework libraries, the way you resolve that in your application is to manually take dependency updates to fixed versions. (This doesn’t mean libraries shouldn’t take these updates, but it does illustrate how application developers don’t necessarily get to delegate that responsibility away.)
  • .NET Standard 2.0 Release. When a new .NET Standard release is issued, that doesn’t require every library to move to that release even if that’s what your application targets. If you look at how .NET Standard works, a higher .NET Standard means more APIs are available to you, but it also means fewer existing apps that target lower .NET Standard versions are able to use your library. You can consume lower .NET Standard libraries in higher targeting applications. For example, a library may target .NET Standard 1.3 and you can totally consume that in your .NET Standard 2.0 app.
  • New dotnet SDK/CLI/build system. If you upgrade your development/build systems to use a new dotnet SDK/CLI it can start generating warnings on your applications when it finds transitive dependencies that may be stale. The solution is to add a direct reference to the later version of the stale dependency. The reason that’s the solution is that not everyone has updated to that latest version of the dotnet SDK/CLI. Libraries need to maintain backward compatibility, so forcing the update may indirectly require consumers to upgrade parts of their development or build process that they’re not ready or able to upgrade.

The point is that many of the challenges seen at the application level due to transitive dependencies can be solved by adding direct dependencies; those same challenges may not be solved in the same way at the library level.

Wrapping It Up

Hopefully this helps clarify why libraries you consume “don’t just take a dependency upgrade” when you notice something in your application.

And, of course, a lot of this is generality. In some cases apps can’t just “take upgrades when they want” because customer environments may not support those changes. In some cases libraries can make changes to public APIs or dependency versions and it doesn’t hurt anything. There’s no hard and fast rule, but basic understanding.

If this sort of discussion interests you, Nick Blumhardt has a similar post on his blog about logging abstraction usage differences between libraries and applications - libraries use abstractions (like Microsoft.Extensions.Logging or LibLog, applications use implementations (like Serilog or log4net).

javascript, tfs comments edit

For better or worse, I’m trying to host a Bower package in a Git repository hosted in Team Foundation Server 2013.

Something I noticed when trying to install the package into my project is that the default Git credential manager was totally being ignored. That is, this was happening:

PS> bower install --save http://my.tfs.server:8080/tfs/Collection/Project/_git/my-package
bower my-package#*      not-cached http://my.tfs.server:8080/tfs/Collection/Project/_git/my-package#*
bower my-package#*         resolve http://my.tfs.server:8080/tfs/Collection/Project/_git/my-package#*
bower my-package#*        download http://my.tfs.server:8080/tfs/Collection/Project/_git/my-package
bower my-package#*           EHTTP Status code of 401

I had authenticated to the TFS server before and credentials should have been stored using the Windows Credential Manager. Doing a git ls-remote on the repo didn’t prompt me for credentials.

The answer, as it turns out, is to prefix the URL with git+ and suddenly the credential manager kicks in.

PS> bower install --save git+http://my.tfs.server:8080/tfs/Collection/Project/_git/my-package
bower my-package#*      not-cached http://my.tfs.server:8080/tfs/Collection/Project/_git/my-package#*
bower my-package#*         resolve http://my.tfs.server:8080/tfs/Collection/Project/_git/my-package#*
bower my-package#*        checkout 1.2.3
bower my-package#*        progress Receiving objects:  14% (15702/112154), 71.73 MiB | 9.57 MiB/s
bower my-package#*        progress Receiving objects:  20% (22431/112154), 81.10 MiB | 9.51 MiB/s
...