Friday, 21 December 2012

Need help? Know how to ask for it

G'day:
This article is borne out of exasperation rising from feeling with people on StackOverflow. But this time not the nazi muppets who like to think they are in a position of authority (and they're at it again today...), but the people asking the questions. To be fair: not all the people asking the questions, but a reasonable percentage of them. An uncomfortably high percentage of them. And the same extends to people asking questions on the Adobe ColdFusion forums, and other similar environments created for people to seek and get help.

I never cease to be amazed at how bloody useless people are at asking for help. And continue to marvel (not in a good way) at how disconnected from reality people must be to approach asking for help the way they go about it. And even before getting to the point of asking for help, how lacking in gumption people can be when it comes to trying to solve their own problems before expecting someone else to pitch-in and help them.

Before I start ranting too much (some might say "too late!" but I've only just started, trust me)... I enjoy participating on help forums. I've been doing it since I first located the alt.comp.lang.coldfusion Usenet group in 2001 (I started with CF in late 1999).  I enjoy the feeling I get when I've successfully helped someone move past a problem (both for myself, and knowing that the other bod will be pleased to move on from this stumbling block they'd encountered); I like the selfish sense of satisfaction I get when I work something out that someone else couldn't work out (I'm not proud of this, but I'm a realist, and it is a factor); most of all I like it when I initially don't know the answer to something I'm trying to help with, and end up learning something as a result. It also helps the ColdFusion community keep ticking over, which Adobe kinda leave up to us to do, so that's gotta be good for ColdFusion's viability going forward. Albeit in a very small way. But community activity is important to the viability of the language, I think.

Anyway, as much as I enjoy it, boy do I find it irritating at times. You probably got that already.

OK, so what's the problem?  Actually the problem is basically described by inference in this distillation of how to ask questions the smart way. It should be required reading for anyone signing up to a help forum. It should be required reading for everyone working in technology. Go read it. Now. But here's my take on where people go wrong when they encounter a problem they don't know the answer to, and where they start going wrong right from the outset.


Identify the problem

If you encounter a problem - like getting CF error on your screen - approach solving it coherently. A lot of people when they get bamboozled by an error simply start trying random things to try to solve it: "I'll restart CF and see if that helps". "I'll use a list instead of an array". "I'll just rewrite it, maybe it'll go away". This is a daft approach to solving things. Even if the problem does happen to go away, you probably won't end up knowing what the problem was, so you really can't be sure it's not some sort of transient problem that didn't just not occur after your remedial action because of some contributing factor that was not present at the time you tested. Plus isn't it nice to know what caused a problem so you don't do it again, rather than just masking it?  Also generally random actions like this don't help, and just make things worse, so attacking things incoherently is just a waste of time in a situation in which you're already probably not wanting to "invest" your time. This just increases frustration.

I use scientific method when I'm faced with a problem I can't nut out. Well a layperson's version of it anyhow. The process I use is basically this:
  1. Make an observation, eg: the manifestation of the error on the screen, or the unexpected results, or whatever it is.
  2. Form a hypothesis of what could be causing the error ("ah... that application-scoped variable has vanished").
  3. Identify the manifestations / side-effects of the situation being hypothesised ("well if that variable has been blitzed, I'll be able to tell by looking in this other place").
  4. Formulate an experiment to test the hypothesis, giving consideration to the bits identified in (3), as well as making sure the results of the experiment will conclusively demonstrate that the hypothesis is borne out. EG: simply restarting CF is not going to be a good experiment for testing a missing application scoped variable, as it doesn't actually identify what caused the problem in the first place. Basically you need measurable results (not just a nebulous change in state).
  5. Perform the experiment, and aggregate the results & any side-effects noticed from the experiment, which might need to be tuned-out in subsequent round of experiment.
  6. Draw a conclusion based on the results. Do the results of the experiment bear out the hypothesis? Quite possibly not, but they should help to finetune the next test of the hypothesis, or alter the hypothesis itself.
  7. Rinse and repeat as necessary.
Now I'm not suggesting one needs to don a labcoat and deploy the pocket protectors to do all this (but hey, if that's your outfit already, all good ;-).  All it means is stop and give some thought to what you're doing, work out a coherent way to test the situation and approach things logically.

Most people I know don't do this, they just throw their hands up in despair (or in a jazz-esque sort of way) and post all their code to StackOverflow going "doesn't work".

And most people really struggle with step 4 there. Judging by the code people end up posting on the the forums, they don't generally have a concept of a portable reproduction case. If - for example - you are having an issue with a JDBC error coming back from a <cfquery> tag, the only things that are relevant are:
  • the SQL statement being passed to the DB driver;
  • any variables that contribute to the construction of said string;
  • the values of any parameters being passed;
  • the data source (and, by inference, which DB server one is using, eg: Oracle, MySQL etc);
  • depending on the nature of the error, the schemas of any tables etc being queried;
  • the error message
  • what the expected results were ("this query is supposed to return [whatever]" or similar)
What is not relevant to any of this is:
  • any code after the <cfquery> tag
  • any code before the <cfquery> tag that don't contribute to the points above;
  • never ever ever any "code" other than CFML. HTML is never going to be relevant to a CF error.
But what I often see posted to forums (or maybe in pastebin etc if the person is remotely sensible in that regard) is the contents of the entire file the error occurs in, including all mark-up, CSS, JS, and unrelated CFML. The immediate effect this has on me is to think:
  • they've done bugger-all of their own troubleshooting if they haven't actually factored-out any of that from contributing to the situation;
  • it's not occurred to them that by posting all that cruft, the person reading the issue is kinda forced to wade through it if only to find the bit they're talking about;
  • if they can't be arsed doing any troubleshooting, why would they think I should be arsed either?

Now... back to my mention of a repro case. What one should do in this situation is pull the code that's causing the problem completely out of the context it's running in, mock the variables that it uses as inputs to perform its logic, decide what one would expect to get as a result, and then run the code. There will be three possible results of this:

  1. If the code works, then one's assumptions as to what the problem is are actually incorrect.  It suggests that one of the inputs is not what one thought it is. That needs to be tracked down and then shift the repro case to that code to work out what the story is. This is forward progress because it has fine-tuned one's understanding of the issue.
  2. If the code doesn't work in a different way from the initial error then one hasn't replicated the inputs properly. This needs to be fixed, and then the experiment repeated. In doing this, it will clarify what's going on and what's contributing to the problem. By the very nature that one's initial baseline expectation of the inputs and the results were off suggests that there's something missing from the analysis of the situation. This is a forward step in solving the problem.
  3. If the code errors in exactly the same way as it was in its original context, then one has a repro case, and one has greatly reduced the factors that could be contributing to it. From here, it's generally pretty easy to work out what's wrong. Almost all issues that initially seemed "weird", "like a bug in ColdFusion", or "just don't make any sense" get solved at this point.
If one is still at stages 1-2, then one is not yet ready to post to a forum for help. Once one gets to stage 3 - and still hasn't cracked the problem - one's got a nice terse piece of code with known inputs and outputs which can be posted to a forum. At this point one will have a far better understanding of what's going on, can articulate the experimentation that has already been done and discarded as not contributing, and there's a small piece of code that someone trying to help can copy & paste down to their local system and run without having to horse around too much. It's also demonstrated that a reasonable amount of effort has already gone into trying to sort it out one's self, which will be a positive sign to anyone thinking of helping. Plus a lot of potential help suggestions will have already been tested and discarded, saving the people helping some time. It's an all-round win.

Also, if perchance the repro case demonstrates a ColdFusion bug, you've already got a repro case to send to Adobe. Excellent.

Describe the problem

A lot of this will have been covered already if the approach above has been taken. But what I mean here is too many people start a thread / question and basically say something along the lines of "I've got this code and it doesn't work. Why doesn't it work?"  The issue here is the person reading it doesn't know what constitutes "not working". It could mean there's an error. But one still doesn't know what sort of error (compile error, logic error, SQL error, etc); it could mean one was expecting ten rows back from the DB and is only getting one; it could mean the table is outputting ten rows by five columns when one wanted five rows of ten columns. The point is: one needs to identify what constitutes "not working". Seriously, this should be bloody obvious, but for some reason it is not.

Furthermore, if one has got an error, one needs to post the bloody error message. Do not describe the error (yes, people do this: "oh I got some error about the array being wrong").  And if there's code involved (OK, obviously with an error code will be involved! ;-), post the code and identify which line the error is saying is a problem.

Pay attention

Actually.... let's back up. Before posting the error... read the bloody thing. So many questions I see are asking what the problem is where the error message is saying exactly what the problem is, and is identifying the precise line and column of the line the problem is at (usually this is with compile errors). Even if they're not that explicit, ColdFusion errors are generally very descriptive, and do pretty much identify what's gone wrong. I also encounter people who say "oh, I never understand that stuff" (seriously!), but when challenged and I say "OK, which word are you struggling with?" and ask "OK, even if you've not heard the term before: what do you think a 'complex object' [for example] might be?" they realise that it's just a case of never having bothered paying attention to the error message, rather than it being impenetrable in some way. I would say 80% of errors I get asked about can be solved by simply reading the error message.

There is no such thing as telepathy

People also have a tendency to assume that just because they know something (or are aware of something about their environment) that everyone else magically will. This is not the case. No-one else is privy to the internal mechinations of your mind, nor with they know your enviroment (or even your ColdFusion version, etc). One needs to make sure that any environment consideration or other peripheral factor needs to be actually articulated. People might be able to guess, but people probably actually can't. But either way: they shouldn't be made to guess. If nothing else it's a barrier to them helping you, which is counterproductive for you.  Consider this problem (this is actually something that I have had to deal with in the past):

SELECT        *
FROM        someTable
WHERE        someColumn = #someValue#
ORDER BY    anotherColumn
LIMIT        5

My DSN is MySQL, but this errors for some reason. If I run the same query in MySQL it works fine.
The problem isn't the filter or the table schema or anything like that. It's that this code wasn't a DB query, it was a QoQ on an earlier-fetched record set. The initial data came from MySQL, sure... but it didn't occur to the person that a QoQ is not run on the DB server, it's run on CF's own little SQL stub thing, and that doesn't support LIMIT.

Now the person should have just read the damned error message (and posted it), but at the very least they should have mentioned that this wasn't a DB query.

There is no such thing as telepathy (redux)

Another thing you need to do is to research the issue, once you've identified it. This means googling error messages, programming constructs you're struggling with, and anything else relevant. And if one still needs to ask for help (TBH, googling will solve 80% of problems: very few problems are unique), then part of your question should also detail what sort of research you've already done. Because if you don't mention it, then the first valid sugggestion one ought to offer you is "did you google it?". Some of you might think "well of course I will have researched it first, that goes without saying", but let me assure you: you're the good 'uns. Most people are bloody useless, and all they do is use StackOverflow and other forums as a kind of mechanical turk: to try to get other people to be their search engines. So let us know what you've already found. Also let us know what things you've found which might seem like a solution, but turned out not to be: this will save us making the same suggestion to you, and it's also useful information to fine-tune your issue.

Most errors are your fault

A lot of people posting questions start off from a fairly defensive position that whatever is going wrong, it's not their fault. They'll say "I don't know what's wrong, because my code works fine", or "I've found a bug in ColdFusion".  I'm sorry, but almost always this is not the case. 99% of the time... perhaps more... it's a problem with the code or the approach, or something like that. ColdFusion might have a number of bugs, but they're generally pretty esoteric these days, so the odds of someone who is having a problem with a listAppend() statement having suddenly found a new bug in listAppend() is rather small.

The problem I have with this way of thinking is that it's much easier to discover what a problem is if one starts with the mindset that it's one's self who's cocked-up, rather than someone else or Adobe. Firstly because it almost certainly is them, but secondly because is one is troubleshooting in a defensive way and going "well I know that works, so it can't be that", one's not going to spot the fact that actually it is that code that's got the problem. I think it's also a logical fallacy that "well my code works, so it can't be that, it must be something else", because the evidence that has lead one to decide something is wrong will be manifesting from a line in one's own code, so - really - even on first indications that's probably where the problem lies.

Approach this stuff with... um... an open mind (or just a neutral mind... just not a closed mind), and one will be in the best place mentally to find the problem.

Also one comes across as a bit of a cock if one starts asserting it's a bug in CF but it happens to be that they don't know the difference between listFind() and listContains() (or just didn't spot they'd used the wrong one). And it's best to not look like a cock if possible, yes? ;-)


Well that was a nice rant for a Friday just before Xmas, wasn't it?

I'm off to Ireland from tomorrow through until Dec 27 - I get to see my son for a dozen or so hours in that time... thankfully 2h of which is on Xmas Day - so I dunno how much attention this blog will get across that period. On one hand I'll have my laptop with me, but on the other hand finding internet connectivity is tricky. But I'm mostly stuck out in the middle of nowhere with little else to do, so perhaps wittering on will pass the time. Who knows?  I'll at least get part 3 of the regex stuff posted at some stage in the next coupla days.

In case this is it before you head off to do festive things that are more interesting than hanging on my every blog-written word, have a good break. And make sure to eat too much. And have a beer for me.

Merry Xmas.

--
Adam