Wednesday, July 26, 2017

Moving away from the guard rails

I started writing this in response to a post on a mailing list.

Basic idea behind the original post: I have a few decks of cards. I know that card seven in deck 12 tells me where I can start to find the 2 cards I can actually care about in decks x and y.

There's some personal stuff mixed into the middle of the career advice, so it seemed worth capturing the silliness that goes on in my head here.

I'm assuming the original poster wasn't just a troll.

There's a definite learning curve here.

Learn to spot these patterns.

Along with all the others. There's probably a Lifetime Achievement Goal for this one.

When you do something like (first xs) or (nth xs 3)...think about it!

Are you really just accessing the first element of a sequence?

I know that seems to be the "clojure idiomatic way." And, honestly, I think a lot of lisp literature probably supports this sort of approach. It's *great* if you're processing a seq by recursing over head/tail. that what you're really doing?

And, seriously, is there *ever* a really good reason to call nth in the middle of general-purpose code? (Yes, I know common lisp gurus *love* cadadar, but it gives this lesser mortal a headache just thinking about it).

In your case, it isn't. Or we wouldn't be having this conversation.

Personally, I haven't found a better solution to your dilemma than combing through the source code and looking for smelly parts like this.

One good (cross-language) rule of thumb I've run across is "If it happens once...OK. If it happens a second time, start being suspicious. If you see this pattern a third time, it's time to move it to an accessor method kind of thing."

I have the fresh wounds to be aware: I spent a good chunk of time today taking a namespace file that had grown too big for me to handle and splitting it out into multiple pieces. This meant a lot of digging through source code and updating specs for new namespaces. I'm still trying to figure out how this part actually works in clojure 1.9. I probably should have checked out Cursive again, and I haven't gotten further than installing CIDER 0.15.

There's another angle here that makes me suspicious.

Is what you're doing really complex enough to warrant "several thousand" lines of code?

I'm not saying it isn't!

I have absolutely no basis for judgement here beyond gut instinct. And no room to judge...I wouldn't pass this next check by any measure. I'm just asking questions here.

How good is your unit test coverage? How good are your commented-out REPL tests? Or maybe you moved those elsewhere to keep from polluting your production code base. (I'd personally rather see them right in the middle of what I'm testing as examples of how to call the code I'm testing, but I think I'm in a slim minority here).

I'm sorry for the long circle around your actual question.

If you have "lots of irrelevant stuff" that turn up when you search your code base for [first second nth]...what have you been doing?

If you've been slinging together a bunch of unrelated data structures into linked lists and expecting magic to come out the other end, then I feel your pain. Welcome to the real world. It doesn't work that way.

If you can pick apart the bits and pieces where you've been doing the same thing over and over again, you might be doing things that are easy to extract. Hmm...I'm calling (first (second (nth x 7))) a lot, to get to the same thing. I'll write a function that does this instead and then spend as much time as I can digging through my code to search for that pattern to refactor it to call that function instead.

Personally, I've never had any luck letting my editor do that step for me. It either finds a ton of false positives that breaks everything when I try to run my code in production, or it misses a ton of false negatives that leaves me wondering why I invested the time installing that editor in the first place. (Don't take my experience here as worthwhile: my experience is about 3 years out of date).

But, really, if you're doing the (-> x (nth 7) second first) sort of pattern often enough that you have to wonder whether you were looking for your uncle's telephone number or your sister's twitter feed...there's a bigger picture problem in your code base.

Figure that one out again. Recurse.


Personal historical perspective that doesn't add anything, except my personal amusement and possible historical interest:

I've been working with a couple of C++ developers on a python project,  and they've complained many times about this sort of thing.

I wish I had a better answer than "What did you expect was going to happen?" In a lot of ways, it feels like when I was doing C++ and everyone around me threw away days tracking down N-1 errors on their array accesses because STL vectors were just too slow/complicated.

It seems like there are probably XKCDs about this. If there aren't, the captions should be:

C gives you enough rope to shoot yourself in the foot. C++ gives you enough rope to blow your entire leg off.

With great power comes great responsibility.

No comments:

Post a Comment