Showing posts with label WellDuh. Show all posts
Showing posts with label WellDuh. Show all posts

2026-10-02

What the #*!! is that?!?

What is it even suppose to do?

Who wrote this $# ....

Oh. It was me.

2026-06-27

Does any one know?

Did Sir Pterry every address the question of which divinty attends to tangled cables? I mean, it seems likely to me that the duty would fall to Anoia. Right?

2026-05-12

Sometimes one facepalm is just not enough

Still working on my little JavaScript side-project as a way of learning AI workflows. Still not using AI for a lot of code-gen but instead for friction reduction. It's going fine, thanks. I mean, the last few weeks haven't seem many new features, but instead a couple of re-factoring passes intended to enable big things in the future, but I count that as progress.

Anyway, while thinking about the evolution I had a question. I was fairly sure the language would do things the "right" way, but felt the need to test, nonetheless. And being an old guy, I wrote the test code by hand:

const primes = [2, 3, 4, 5, 7, 11, 13, 17];
const fibonacci = [0, 1, 1, 2, 3, 5, 8, 13];
let combined = [...primes, ...fibonacci];
combined.sort();
console.log(`primes: ${primes}`);
console.log(`fibonacci: ${fibonacci}`);
console.log(`combined: ${combined}`);

the point of which was just to assure myself that sorting the combined array would not scramble the source arrays. I would have been very surprised if it had, but I had to check.

That said, the results were not what I expected:

primes: 2,3,4,5,7,11,13,17
fibonacci: 0,1,1,2,3,5,8,13
combined: 0,1,1,11,13,13,17,2,2,3,3,4,5,5,7,8

Wat?

An array filled entirely with numbers has been sorted lexically according to their naive string values.

And on reflection, that's not terribly surprising in a language, like JavaScript, that is both dynamically typed and quite compact because it is the prescription most likely to work in most situations. But it sure came as a surprise to a guy used to strongly typed systems intended for systems and scientific work.

2026-03-22

JavaScript, PEBKAC, and LLMs

A couple of months ago there were, at last, some promising smoke signals from corporate suggesting that IT is getting around to really thinking about, just maybe, supplying us with something by way of security-minded LLM support.

Okay, so it was a little more than that. They actually bought licenses for a commercial product (something that comes with security guarantees backed by performance penalties) for supplying that kind of thing. For the managers.1 That was a bit disappointing because I couldn't explore that space on my employer's dime.

But it got me to start thinking seriously about trying out LLM supported programming workflows, and I decided to apply it to some aspects of my hobby projects. After some thought I concluded that the models I was likely to run were going to be uninspiring on C++ projects. To maximize the utility of the tool, I needed a project where (a) the model would have seen a lot appropriate of training data and (b) I was not already highly conversant with either the domain or the tooling.

I decided to start writing some little games for the browser in JavaScript.

And, brimming over with excitement for my new project I ... spent about four weeks of spare time mucking about with tooling. Yeah.

I did eventually gets Emacs configured to know about JavaScript (including an LSP, a major side-quest what with some self-imposed limitations, but that's another post) and chose one of the multiple LLM interfaces for the editor. There were a few hiccups along the way, but a I got some advice from a couple of LLMs which really helped. Oddly all the configuration work was making me feel optimistic about the project: the models weren't really handling much tedious boilerplate, but they were getting me past some ignorance-driven friction and probably (at least maybe) saving me time. So really yeah!

Then I watched a couple of on-line tutorial videos on JavaScript animation and game-dev, created a new project repository and started random hacking about while asking the models a bunch of questions and having them try their hands at writing bits of code. In about a-week-and-a-half of spare time I had a canvas with four distinct objects moving around it, each under their own set of rules for speed, gravity, wrapping around edges and bouncing. The code quality was awful, but not because the models wrote it. The parts I wrote were just as bad because this was a "just get something working" exercise. Almost everything was in global scope and free functions poked into the depths of the object collections to manipulate internal state. Classic.

The next thing to do, of course, was impose some order on the chaos. To channel interconnectedness through designed mechanism, and achieve a degree of uniformity in implementation.

I broke everything that worked to separate some concerns here, name elements of the modeling there and so on. And after burning another week of spare time on it, this afternoon I had all the same data in the program in a much more orderly manner and the first frame drawing as expected. But nothing was changing even though it looked like I had all the plumbing back in place. The application of some judicious console.log calls2 proved that the animate function was getting called, it was iterating through the object and telling them to update themselves, and they were iterating through their update action list and calling them. But the display was not updating.

And also, I hadn't asked the LLM anything for days of real-time and hours of coding time despite (if you believe Mrs. NoSwampCoolers) a steady stream of swearing at the code. I've been "a programmer" since sometime between 1982 and 1992, depending on what you want to credit with the title (1982 was first typing the classic 2-line "hello" infinite-loop in basic; 1992 was my first production code). I have deeply ingrained habits for both learning new things and tackling problems with code-bases. And "ask the AI" does not, currently, feature in those habits. Which is a me problem to the extent that "ask the AI" is better than my other approaches, but is still a thing to be overcome if a transition is to occur.

Anyway, I did eventually think to "ask the AI". I used my LLM interaction tool to pick four (quite short) files out of the project directory and asked why the actions called by Obj2d.update were failing to update the positions.

After telling me many thing about the code that I knew (because I had designed them in), and complaining about the bits of context I hadn't show it because they did matter, noticing (out loud) that they didn't matter, and deciding (out loud) to move on, it first proclaimed that there wasn't anything reason for issue and then said, "but wait". Turns out the joker who wrote this code didn't provide setters for some concepts he's trying to set in the bowels of the Vec2d class. Which was the correct resolution of the issue.3 Facepalm. Score one for the model.


1 Whose main day-to-day complaint (at least in my unit) is that they don't get enough time to do technical work what with all the people, contracts, and paper work they're saddled with.

2 Yes, there is a debugger in the browser, and yes I've largely figured out how to use it. But my "just hack on things" machine has a small display which (added to the unfamiliarity of the language and debugger) made print-debugging feel more comfortable. Presumably I'll get over it as I go.

3 I don't think I've mentioned on the blog before, but I really hate environments that silently fail. And Firefox will let you write v.x = new_value; when v has neither a public data member nor a setting named "x". Really. So the f'ing environment gets some of the blame here.

2024-03-05

Voice-assistant fails

Accumulated over the years, but I got another one the other day that triggered me.

Me:
[Navigating to a business in the US sowthwqest]
Creppy voice assistant (CVA):
In five-hundred feet, turn left on El Camino Real Street1.
Me:
[::Sighs::]


CVA:
[Interrupts a conversation in the car]
Me:
Hold your horse, [CVA].
CVA:
[Starts reading the Wikipeia article on the idiom]


Me:
[CVA], play 2112.
CVA:
Now playing two-thousand-one-hundred-twelve.
Me:
[::Fumes:: until the music sweeps me away]

It's all about context seneitivity. Or the lack thereof.


1 With "Real" pronounced as a single sylable. Of course.

2023-08-28

The invention of fanfic

I've been reading The Hobbit to the child for bedtime story recently. Bit of a slog at times because (a) she falls asleep in the most surprising places in the text, (b) frequent stops to discuss new vocabulary and previously unknown customs, and (c) lengthy interruptions to hear how she things the story should proceed. That latter bit came to a head tonight as we neared the end of Chapter 8. She believes that the story would be better if we dispensed with the spiders and added some unicorns and has decides to make up her own, improved version.

2023-07-31

Vicarious Endings

Shortly after we moved into our present dwelling we started sending my then two year old daughter to a local preschool. That was nearly four years ago and today was her very last day there. I've managed not to think too hard about it for the last few week, but driving over to pick her up today is all hit me like a ton of bittersweet bricks. We're talking Time Stand Still playing in a loop in my head and flashbacks to my own transitions through the years.

Yikes!

The funniest part of it is that we've been scaffolding this change for her for more than a year. I just somehow forgot to scaffold it for myself.

2023-04-20

Yep. That was kinda dumb of me.

Consider the canonical Meyer's Singleton implemetaion in C++ (2011 or later standard): class Singleton { Singleton(); ~Singleton(); public: Singlton(const Singleton &) = delete; Singleton & operator=(const Singleton &) = delete; Singleton & instance() { static Singleton s; return s; } }; It has all the properties you might want of a Singleton:1 things like guaranteed single initialization and thread safety. Plus, it's easier to remember than any of the other functional variants I've seen.

But there is a subtle trap in the fact that I haven't shown you my implementation of the c'tor.2 One that I just tripped on in a big way. What happens if you were to call instance() in the constructor?

Now, it is unlikely that anyone will write Singleton::Singelton() { instance(); } and overlook the silliness of it for long after the program hangs during testing. However, writing Singleton::Singelton() { supportRoutine() } where supportRoutine() calls helperWidget() which calls instance() is a lot easier to miss for a few frustrating hours. Trust me.

This is about the object lifetime model in modern C++. And honsestly I didn't know enough about the hoary details to figure out what the standard requires when I realized what I had done, but MSVC 2019 appears to enter an infinite recursion. Luckily the internet is full of people who have more (or at least different) expertise than me, so I was able to get some help. The first source that my google-fu found was a blog post by mbedded.ninja which includes an explicit call-out to the standard3 telling us this is undefined behavior.

So, yeah. Don't do that.

Late addition: on reflection, the reason I got into that pickle in the first place was that I was using the Singleton both to manage an OS resource and and as a repository for utility code related to the resources. Having them in the same context made it too tempting to trigger some of the utility code from the c'tor and involke the recursion. Re-writing the code to better folloow the Single Responisibility Principle made the loop imnpossible in the first place and made me re-think when to invoke the utility code.


1 Assuming, of course, that you want a Singleton; more on that in another post.

2 I've left the d'tor unspecified as well for a philosophical reason: you should always decide on their implementaion as a pair. I don't want to commit to = default; for the d'tor until I know what I'm doing in the c'tor. In the instance that brought the subject up I was grabbing OS resources in the c'tor and so needed a non-trivial d'tor that would nicely give them back. Cue "but technically's" about the destruction order fiasco. I said I would discuss the (often ill-)advisability of Singletons in another post.

3 Section 6.7 paragraph 4 which says in part:

If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.

2023-01-07

Uhm...

I got a Kindle Scribe for Christmas. Yeah, now I hav an e-reader I can actually read papers on! Cool.

Of course, this just means I've been sucked into Amazon's ecosystem. You can only use a few formats on it, but that includes PDF. Except...

  • Annotation support on most PDFs is limited.
  • To get full annotation support you have to submit the file through "Send to Kindle"1 where I suppose it is pre-processed in some way and them made available for downloading to your machine.

Fine. I'll pretend I don't think they're spying on my content, and I'll even try to believe that they are spying responsibly. But honestly they already know a lot about me.

But that doesn't mean that there aren't any surprises here. You see, the machine has a web browser. It's not very good, but it's there. That browser won't save PDFs directly to the machine, which is a little weird, but the big oddity is that it also has no facility to route them through Send to Kindle. To somehow manage to make matters worse, the "Send to Kindle" page has a link for a "Send to Kindle" browser extension!

Seems like a no-brainer to me. Perhaps I should send them a note, but they make that weird, too.2


1 More "Send to Kindle" breakage: it will convert ebook files to a Kindle friendly format for you, but will silently drop on the floor any files already in Kindle preferred format (that perhaps, you downloaded from a DRM-free source like Standard EBooks).

2 The device supports a "Contact Us" feature, which lets you send missives into the void, but they specifically disavow any intention to hold a conversation as a result (or even just telling you what they are doing about it). There doesn't seem to be a customer facing issue tracker where you can see that your suggestion is already in progress or follow deliberations on how to handle an issue. I'm spoiled by the culture of the open-source world.

2022-12-25

A New One By Me

Our daughter is intensely interested in upcomming changes in her life. In particular she's aware that she is currently attending the most senior program as her pre-school (a transitional class the state will accept in lieu of kintergarten) and wants to know about where she will go to "homework school".1

The phrase is descriptive and its meaning is clear, so it's a logical neologism, but I'd never heard it before. Is that a term of art among the pre-school set?


1 A very good question about which we are currently having a slow motion panic. Much research is being conducted and many experts are being consulted.

2022-11-25

But ... I knew that. I just didn't understand the importance of what I knew.

Still more Randall Monroe greatness.

What with one thing and another I learned about the TEA project recently. Ambitious stuff, and I'm completely unprepared to talk about the project as a whole, but being a ex-academic, I wasted no time downloading the white-paper, and brought along a dead-trees version for flight as we took our spawn off to visit one set of Grandparents.1 The paper concerns itself with a distributed crytographic ledger to be used for archiving and authenticating the open-source ecosystem but also to provide a framework for distributing donations across that ecosystem.

The point is that much of the open-source ecosystem is un-sexy tooling and infrastructure that only excites the people who use it to write other open-source software, but donation come from either users (who tend to direct them to sexy top-of-the-stack end-user stuff) and companies (who direct them to things they are specifically trying to improve). Very little money flows to underlying stuff that "just works" even if it requires on-going maintenance to preserve that state of operability. There is a reason Randall uses the word "thanklessly" in the comic. Anyway, the paper observes that to perform such a distribution you would need to know how much each project contributes to the ecosystem, and then that a package manager (such as apt, pip, npm, or homebrew) is exactly an encoded version of that knowledge.

I'm pretty sure my jaw hung slack for the several seconds it took for my mind to re-orient on my freshly remade understanding of the open-source ecosystem. Of course, the package managers already know that stuff. At least collectively.2 And maybe missing the dependency links implicit in rarely used build options. But for the most part it's there.


1 Between the pandemic and our commitments taking care of honorary Grandma we'd been able to avoid this for some time. Now we will, no doubt, have to do the other Grandparents soon as well.

2 It is worth noticing that there are multiple classes of package managers and build dependency systems out there, handling independent (well, largely independent) and distinct (again, largely) ecosystems. To perform as envisioned the proposed tea protocol will need to be flexible enough to express relationships within and between all such groupings. Not easy stuff.

2022-10-13

On being "that guy"

I contacted a support desk with an issue that I should have had instructions for but didn't. So far so good.

However, I followed up by asking a question about their response that I'd have answered for myself if only I'd scrolled beyond the page break. Not a good look.

In my defense there was a huge blob of whitespace at the botom of the page and I thought I'd reached the end of the document.1

Alas, after they poliely didn't tell me what an idiot I was being, I commited the "didn't read far enough" error again. Sigh.

Sorry guys. I did frontline support for a while and I feel for 'ya.


1 Because Word is paricularly crappy at layout even by word processor standards. One of the things I miss about academia is LaTeX: the typesetting and layout might be boring but they will avoid the easy misakes by default.

2022-07-11

Little surprises #8: using the preprocessor to create latent bugs

Aside: As opposed to using the build system or the template processor which are totaly different except in the ways they are completely the same.


Languages with C-derived syntax and exceptions generally have a try-catch construct and the ones I'm familiar with have a little trap for the inattentive programmer: the catch block is a different scope from the try blocks. Which means when you merrily write try { ErrorInfo e; someRiskyOperation(e) } catch (...) { print("Risky operation failed with error %s\n",e.explanation()); } because the argument to someRiskyOperation is an out-param1 and you hope to capture the error data that was generated before the exception was thrown, you actually get a compilation error because e isn't in scope when you try to issue the message.

Not a big problem, of course, at least two work-around are obvious.

Except that I tried to send a message to our logger, so the code looked like try { ErrorInfo e; someRiskyOperation(e) } catch (...) { LOG_WARN("Risky operation failed with error " + e.explanation()); } where LOG_WARN is a macro whose purpose is to capture the file and line where the error occured.2 And that's a problem if this code occurs in a library that can be compiled with logging support turned off by simply defining the logging macros as nulls: #define LOG_WARN(explanation) , because in that case the compiler never sees the offending e.explanation. It was rewritten as nothing even before lexing. So you can test the code with logging turned off to your hearts content and never find the bug. Sigh.


1 Yes, I agree: out-params are generally evil. It's a legacy API. Perhaps we'll get around to replacing it eventually.

2 When it actually does something it looks something like #define LOG_WARN(explanation) do { \ logger:Message logmsg(__FILE__, __LINE__, explanation, logger::Warning); \ logger::getLogHandler().post(logmsg); \ while(false) and it can't be a function because __FILE__ and __LINE__ are macros and have to be evaluated in place. Unless and until the language provides operators for capturing source position data like that this is the best we can do.

2021-11-17

Some thoughts on automated switchboards

If you pick up the phone and call many businesses these days you find yourself talking to a computerized system before a human being. Such is the modern world, but a few thoughts keep coming back to me.

All the modern inconveniences
I'd prefer to stick with the old "press # for ..." system unless your voice navigation lets me respond before the prompt is finished, is consistent in recognizing many people's speech patterns, and is flexible enough that I don't have to chose exactly the right key word for every branch of the tree. A few systems do this well, some do it tolerably, but a lot of them just aren't ready for prime time.
I wonder ...
A lot of these systems give you the "this call may be monitored" warning right up front, so it applies to your interactions with the computer. Does anyone ever listen to customer interactions with the computer? Do they hear when you're snarky, impatient or frustrated with the computer? Do they take any note of the sarcastic comments you make to people around you while you're on hold? To how much you hate the hold music they've chosen?
Correction
From a UI point of view a "We're sorry, but due to higher than anticipated call volume wait times may be longer than usual." type warning is a pretty good idea. But when you get it every time you call you know they are lying to you. They realy mean "due to anticipated call volume".1
DAG nabit!
Most of these things seem to be organized as a tree, meaning there is only one set of choices that will get you to a particular leaf operation, but I feel that they could be more usefully be organized as a directed graph. Ideally acyclic because user would presumably be very annoyed to be carried around a cycle.

1 The reason is clear enough, unless they have a driving focus on customer experience they don't want to pay any call center people to sit around doing nothing, so they try to optimize their staffing so that the hold queue never never quite empties out. If their load consists of relatively few long call this means long waits for people calling in. They are optimizing for their interests at the cost of their customer, and how to make such call is a strategic choice for a business. But please don't lie to me: I notice and I care.

2021-11-02

Holding back the schadenfreude

Today my news feed included yet another article about the terrible plight of hiring managers these days. The poor dears are being left high and dry by job seekers who don't care about their wasted time and don't feel the need to offer their victims even the common courtesy of a phone call or email. Or even a text message. Such unprofessional behavior! Who could credit it?

Or something like that.

I am aghast In theory. But not in reality.

You see I conducted professional job searches in 2004-5, 2007-8, 2012-13, and 2017-18; making somewhere between 250 and 300 applications in total. Consequently I have a reasonable statistical basis on which to make some observation of what "professional, business behavior" associated with hiring situations has actually turned into over the last decade and a half. Albeit, based on my memories rather than good records. You've been warned.

First a few observations about the large scale context:

  • The vast majority of those applications were made via email or on-line form. I can't recall sending a single hard-copy packet in the last two job searches.
  • The prevalence of on-line forms over "send us these documents in a format we understand" grew steadily through the period and was total dominant by the end.
  • It is obvious (occasionally even explicit) that many of these systems use some kind of automated filtering to save the hiring managers from needing to look at all the applications.1

Before we go on, I should mention that I've sat on hiring committees. I've sat in bed next to my loving spouse pouring over a slush pile of packets sorting out those that should never have been sent from those that at least come close to having the background we asked for. The next week I was working over a subset of them to select a set of promising prospects for deeper investigation.2 I've called references. I've sat through two rounds of telephone interviews and hosted the in-person appearances. I've debated the pros and cons of the multiple interviewees who were almost but not quite the candidate we wanted, each with their own strengths and weaknesses.

I know how painful, labor intensive, and demoralizing it can be to be on the hiring end of these things.

That said, I want to focus on a particular feature of the hiring system we've developed in these glittering first decades of the twenty-first century: in many, many cases the system is designed solely for the convenience of the hiring manager at the cost of the job seeker. First I have to register with a portal to start the process. Including, of course username3, password4, and recovery questions. No, you won't be able to re-use any of that; every employer has their own portal. Then not only should I upload my carefully formatted resume (or CV), cover letter, and other documents but I also need to copy the data therein to an endless series of web forms.5 Then I get to answer a set of true/false or multiple choice questions to confirm that I have the minimum requirements for the job.6,7 Then I'm lucky even to get an automated email confirming that the system received my application8 and even more lucky to receive further communications if I don't get called for an interview.9

Total time screwing around in the web interface: 30-60 minutes. Exclusive of (a) finding the prospect, (b) any research on the company you care to do, and (c) any customization of your packet materials you care to do.

The "painful, labor intensive, and demoralizing" bit I experienced when trying to hire was never a patch on what it was like to be a job seeker.

And there are three key points here. First, no one on the other end gives a fig how well this system works for the job seeker. Your blood, sweat, or tears are of no consequence to them. Second, while people are looking for a "fit" they care more about being able to identify a reasonable fit than about finding the perfect (or even a great) fit if it means more work to do it. And finally, the last fifteen plus years have been spent normalizing the idea that one side of this negotiation is allowed to drop the other side without a word. Some folks just imagined that only one side would ever exercise the option.

Ghosting your partner in this interactions is the standard of professional business behavior in the hiring game. Because a significant fraction of hiring managers have been working hard to make it so for decades.

Now, it's just possible that the people interviewed for these articles are the compassionate few who insisted on maintaining polite, if automated, contact with applicants up to the point that the position closed with those hopefuls still outside the door.10 It could be, but I doubt it.

I started this post with the intention of writing a sly observation on the reversal of fortunes. But somewhere along the way it turned into a bit of a rant. It seems I may have a little residual anger. Something on order of a coal-seem fire, perhaps. And I'm sure I'm not the only one.

In any case, schadenfreude is an ugly emotion and I try not to indulge, but sometimes it's very tempting.


1 And let's face it: those filters are utter trash. Natural language processing has come a notable way since the early 1990s but it is still better characterized as "artificial unintelligence" than AI. If you write it by hand you use word and phrase matching, and if you hand it over ot a ML system you get a more finely weighted word and phrase matching system. Either of which suck at seeing transferable skills and related experience. You can try to fix that with some kind of mapping systems but only if you can accurately anticipate what related experience and transferable skills will appear in your application pool. And of course, if you care to spend the not inconsiderable amount of money turning such predictions into work code would require.

2 I'm positive, both as a job seeker and a hiring committee member, that good candidates get screened at this step.

3 But not that one, it's already taken.

4 But not that one, it has characters we don't allow. Or doesn't have a character from this class. Or doesn't have characters from enough classes. Or whatever.

5 Occasionally the system tries to pre-populate the forms for you by parsing the documents you uploaded. I presume this works OK if you upload in Word format (but why would you upload something like that in an editable format?!?) and use a popular template.

6 Always after you've done all the other work.

7 Which means these things are hard fails with no chance for intelligent consideration of the other factors. A friend who chaired the IT security committee at a major public university and gave talks at major security conferences was ruled out of a position in IT security because he didn't have a master's degree. Of course, you could lie to the computer, but how will the hiring manager feel about that?

8 I'd guess this was roughly 50% of systems in my earliest search reported here and had dropped to less than 25% by my latest one.

9 A few systems do make it possible for you to log back in to track the progress of your applications. For those you actually have to hold on to that username/password pair you made.

10 I even had a handful of personal emails telling me I hadn't been selected back in the noughties. One person took the time to write what looked like a personalized encouraging message. Nothing like that in the teens, however.

2021-07-10

Well, obviously...

We've had my in-laws here for the last week with our nephew for "Camp Cousins" to ensure that the youg'uns know one another. Lots of activities around the house: arts, crafts, games, and even an intoduction to Roblox development for the eight year old (which is why it had to be here and not in California where the in-laws live); and trips out to the zoo, aquarium, science museum, and even putt-putt.

I had shirts made. But they took longer than expected to come, so we didn't get them until Thursday and couldn't wear the to the zoo for the planned pictures. We rescheduled that for today (the last day). When the time came we headed out to the (new) planned location (where we could include the same mountains in the background as I had put on the shirts), only to find that it was starting rain (out of season) even as the dust storm continued (very much in season).

Rain and dust storm. Of course.

2021-03-15

Bad webmonkey, no Mt. Dew!

Given the possibility that the title could be taken as a pejorative, I should get a few things out of the way:

  • Web programming can be "real" programming. It is a cross-disciplinary task and there are so many subtleties and complexities that web programmers ought to be taken seriously.
  • Web programmers don't have the luxury of having most of their mistakes take place off camera the way some of us do.
  • In addition to the complexities of the programming environment they get to deal with UI (or UE, if you prefer) all the time. Poor things.

But ... those same bullet points explain why they get bagged on: their mistakes are highly visible, annoying, and they generally turn out to be something that some segment of the users consider to be "obvious". As in "How could anyone with half-a-brain not know that?!?" kind of obvious to some part of their audience. And they don't generally hear from the cohort who shares their ignorance.

The answer to that exasperated query is that it takes time, effort, and experience to become good at cross-disciplinary stuff. You need to know a few things in great depth, a larger number of things to moderate depth, and a little bit about a huge number of things. That takes time.

Now, twenty years ago web programming had a reputation for low barrier to entry. Is that still true? I don't hang around the right places to know what people say about it these days. But combining low barriers to entry with pretty high requirements for preparation is a recipe for disaster.

So, "What brought this on?" I hear you saying.

Well, not really because you're on the other side of the internet from me, I haven't hacked your microphone, and it's not clear that anyone actually reads this thing with any regularity. But I have a good imagination, so I hear you saying it anyway.

Setting my security questions and responses for a web site. Unfortunately,

  • The street I lived on when I was ten years old had a two word name (not counting "Road": its name was a phrase), which the person who programmed the form apparently thinks is a thing that doesn't happen.
  • I got my first job in a city in the US southwest named after a saint. In Spanish. So it, too, is two words. Again, the programmer apparently doesn't believe in such nonsense.

Now, young programmers in my end of the business are pointed at a few documents early on to give them a starting familiarity with some of the more trap-laden parts of our work. Things like What Every Programmer Should Know About Floating-Point Arithmetic and What Every Programmer Should Know About Memory (PDF link) . I would have thought that Falsehoods Programmers Believe About Names and Falsehoods Programmers Believe About Addresses would be reasonably obvious candidates for the same role among web programmers. In fact these kinds of document make up a little genre of their own, and it's one worth taking a little time to explore. I promise you'll find one or two that you're guilty of.

Rather than hurling imprecations at web programmers in general, or even at the miscreant in this particular episode I'll just ask anyone going into web programming to find some resources for how to think about these things. Please.

2021-02-03

Maybe type aliases are part of the happy medium.

Tension between conflicting goals is as much a part of software as it is of life in general. Today I am thinking in particular of the tension bewteen planning ahead and generality on one hand and KISS and YAGNI on the other. Plan too little and you either end up with multiple slightly incompatible implementations of parts of your design or you metaphorically paint yourself into a corner and have to redsign at a large scale. Plan too much and you both over complicate and waste time writing features you never use. Somewhere in the middle is a sweet spot that you aim for.

I've been working on reining in my tendency to overplan for some years, and I'm doing a lot better these days. Except for one one paricular case: making thing type-generic. If I'm writing a class and ask "Hmm ... what type of underlying data should this use?" and don't find an immediately obvious answer my first reaction is to type template <typename T>.

Looked at naively this is a good trade-off: the mental cost of writing and reading a simple template that just serves to defer the choice of underlying type is barely more than that for the untempalted code, and it increases the generality of the code. What's not to like?.

But there are hidden costs: increased compile times; latent bugs,1 and the need to chose between explcit declaration of desired instances and header-only code. And of course, header-only code makes the compile time issue worse. Now I'm aware of techniques like thin templates, but that negates my claim that the template isn't any harder to write or read than the untemaplated option.

Today, while I was waiting on yet another overly long build I had a long overdue insight. In most case that template class starts something like:

template <typename T>
class Thing 
{
public:
   using part_t = T;
   //...

That is I've borrowed the habit of naming types related to my classes using type aliases (seen in the standard library and elsewhere). But here is the crucial observation: I could write Thing without templates and still use the type alias with a interim choice for the type:

class Thing 
{
public:
   using part_t = float; // Just pick something for now...
   //...

If I change my mind about the type fixing it is a one-line edit.2 And if I find that I need multiple choices later coverting the class to a template is a straight forward refactoring step, but I don't pay the template costs until I actually make that call.


1 Even latent compile time bugs. I've had to fix compile-time bugs in code that's been in the repositoy for months because we finally instantiated it with a type where the bug surfaced.

2 As long as I am consistent in using the alias, but I'm trying to do that for readability anyway.

2020-06-18

Little surprises #4: string concatenation edition

Another one that came up at work today. A method was behaving as if an argument was taking on it's default value even though there was an argument right there in the code.

Abstracted to it's bare essentials it starts with a method

class Thing {
   // c'tors and so on
   void method(const std::string & s1, 
               const std::string & s2 = "");
};
which was called in a section of code that had significant history
Thing thing;
thing.method("string"// oldWayToDeduceString(),
             "second string");

Do you see it?

Only one argument is being passed to Thing::method due to string concatenation and the comma that used to separate the first argument from the second being commented out. The compiler doesn't complain because the second argument takes on it's default value.

The real failure here (and it was mine, if you really need to know) was not removing the commented code after testing and before committing this code the last time 'round.

2020-05-08

I didn't know that I could do that!

So, I'm watching some videos on c++. Call it continuing education.

Now, I've never formally studied c++. It wasn't part of my education, and I learned it "on the job". I have tried to read and learn as I encountered things I didn't understand, and I like to think I know a lot of things about the language. I mean, I even got a gold tag badge for it on Stack Overflow. Surely I'm not completely ignorant. Right?

One of the talks I'm watching is highlighting some parts of the Core Guidelines. The presenter brings up a case that I actually faced recently.
  1. You have a class with a const accessor method that returns the result of a computations (i.e. is not accessing a feature of the current implementation but a feature of the model that can be deduced from stored elements of the implementation)
  2. That deduction is expensive enough that you want to cache the result.
  3. You run into a conflict between the need to update the value of the cache and the desire to have the accessor marked const because it isn't changing any feature of the underlying model.
I'm happy to say that I didn't do the very bad thing (casting away the const), but I did lose the const marking on the accessor because I didn't know about mutable.

Crap.

Learn something every day.