EmbeddedRelated.com
Forums
The 2026 Embedded Online Conference

Modern debuggers cause bad code quality

Started by Oliver Betz December 2, 2014
Tim Wescott wrote:
> On Wed, 03 Dec 2014 07:46:21 -0600, Les Cargill wrote: > >> Tim Wescott wrote: >>> On Tue, 02 Dec 2014 19:40:05 -0600, Les Cargill wrote: >>> >>>> Tim Wescott wrote: >>>>> On Tue, 02 Dec 2014 16:31:52 +0100, Oliver Betz wrote: >>>>> >>>>>> Hi All, >>>>>> >>>>>> of course, the subject is just a rant to make you read and comment >>>>>> this. >>>>>> >>>>>> Did developers two decades ago think better before they started >>>>>> coding? >>>>>> >>>>>> In the early days of embedded computing, most embedded developers >>>>>> could use a TTY interface at best and instrumented the code with >>>>>> some print statements if something went wrong. >>>>>> >>>>>> A build and test cycle took several minutes because erasing and >>>>>> programming EPROMs took so long. >>>>>> >>>>>> ICEs were extremly expensive and didn't even provide the >>>>>> capabilities of modern tools. >>>>>> >>>>>> Today, you can get some kind of "background debug interface" nearly >>>>>> for free, and build and upload new code in seconds. >>>>>> >>>>>> On the ESE Kongress in Sindelfingen, Jack Ganssle lamented today in >>>>>> his keynote about developers spending 50% of their time on >>>>>> debugging. >>>>>> >>>>>> Could it be that today's sophisticated tools lead to more "try and >>>>>> error", less thinking before doing? >>>>> >>>>> Are you thumping your cane on the floor as you complain about kids >>>>> these days, and how the world is degenerating into crap because of >>>>> them? >>>>> >>>>> I think if you look, you'll probably find similar complaints in the >>>>> Bible, >>>>> or perhaps written in hieroglyphics on stelae in Egypt someplace. >>>>> >>>>> Times change. The details of the screwups change. The nature of the >>>>> thinking leading to the screwups doesn't change, nor does the basic >>>>> solutions. >>>>> >>>>> On a related note, I've been taking more and more to test driven >>>>> development over the last decade, because it seems to help my >>>>> development a lot. In the last two years I've gotten much more >>>>> strict about doing everything I possibly can under TDD, even if I >>>>> have to add hardware abstraction layers to do it. >>>>> >>>>> My code has gotten better as a consequence. Not because so much more >>>>> of my code is -- perforce -- unit tested, but because the level of >>>>> detail of testing that TDD calls upon you to do forces you to think >>>>> about what you're doing in much greater detail, and to verify that >>>>> your head is screwed on straight as you did the thinking. >>>>> >>>>> >>>>> >>>> The Big Thing is keeping a comprehensive set of test vectors. Putting >>>> thought into how to apply test vectors to an embedded device is time >>>> well spent. >>>> >>>> Most stuff has an Ethernet NIC these days; even if the PHY is a depop >>>> on the production version, being able to use Ethernet is a really big >>>> game changer. >>>> >>>> If you don't have a NIC, you'll probably have a serial port, and RasPi >>>> class computers will act as the "Ethernet port". >>> >>> Maybe most stuff you work on. The board in front of me right now is >>> about 1.25 square inches. It has two chips, a transistor, a diode, a >>> button, and some discretes. Rev 2 will have vastly enhanced I/O -- >>> it'll have an LED. >>> >>> >> In that case, the thing better be sufficiently constrained to allow for >> reasoning about operation at the source code level. >> >> I hope you have some way to at least pull error counters without >> stopping the CPU. > > I happened to have an extreme counter-example sitting in front of me, so I > used it. > > The board's whole purpose in life is to turn a motor on for 30 seconds at > a button press, then stop. It can (and a previous revision did) be done > with a couple of transistors and some discretes. >
Should be tractable as provably ( or close enough ) correct, then.
> Rev 2 will allow the user to program the timer interval and save it in > flash -- which will probably take up the bulk of the code. >
Yep. -- Les Cargill
"Boudewijn Dijkstra" wrote:

[...]

>> Could it be that today's sophisticated tools lead to more "try and >> error", less thinking before doing? > >Don't blame the debuggers, by far the most developers don't even use >high-end "sophisticated" debuggers with can make full use of the on-chip >debug logic and provide reliable CPU trace. Today's hardware and software
IMO that's no counter-argument. My point is, that a painful test cycle motivates people to think before stupidly trying dozens of changes.
>are way more complex, however. Below are some cynical remarks. > >We use hardware with badly documented and/or broken peripherals, which >requires debugging.
Also to me, "hardware debugging" is one of the most important aspects of a powerful debugger. Not only bad or broken foreign hardware but also own hardware under development. Being able ad-hoc to twiddle with my peripheral or front-end without the need of programming a dedicatred "interface" is priceless. Oliver -- Oliver Betz, Munich http://oliverbetz.de/
Tim Wescott wrote:

[...]

>> Could it be that today's sophisticated tools lead to more "try and >> error", less thinking before doing? > >Are you thumping your cane on the floor as you complain about kids these >days, and how the world is degenerating into crap because of them?
no, although age helps developing discipline, it's no guarantee, and I think older developers are also affected. It's tempting to try changes if it is ostensibly quicker. And if you know that a cycle for a new try is painful, you get external motivation (compensation for a lack of intrinsic motivation).
>I think if you look, you'll probably find similar complaints in the Bible, >or perhaps written in hieroglyphics on stelae in Egypt someplace. > >Times change. The details of the screwups change. The nature of the >thinking leading to the screwups doesn't change, nor does the basic >solutions.
Any good example supporting this?
>On a related note, I've been taking more and more to test driven >development over the last decade, because it seems to help my development >a lot. In the last two years I've gotten much more strict about doing
I agree that TDD promotes thinking on the problem but it's IMO not the key. Oliver -- Oliver Betz, Munich http://oliverbetz.de/
"tim....." wrote:

[...]

>> In the early days of embedded computing, most embedded developers >> could use a TTY interface at best and instrumented the code with some >> print statements if something went wrong. >> >> A build and test cycle took several minutes because erasing and >> programming EPROMs took so long. > >OMG what did you work on > >back in 87, which is not even the early days of embedded, a build cycle >could take hours
I prefer to work on simple systems. My first embedded system was 1986 a 6502 based controller for a weighing machine http://oliverbetz.de/pages/Museum/Schuettwaagen My build system was an Apple// with a hard disk, object code size likely around 8K. Most time was programming and erasing EPROMs. Printing the source code took rathern long, though. Oliver -- Oliver Betz, Munich http://oliverbetz.de/
Paul E Bennett wrote:

[...]

>> Could it be that today's sophisticated tools lead to more "try and >> error", less thinking before doing? > >Talk about cats amongst pigeons.
causing the foreseeable defensiveness. [...]
>Errors that creep into projects are quite language and technology agnostic.
Ganssle presented numbers: 50..100 errors/KLOC in C, 5..10 in ADA, zero with SPARK. Of course, this doesn't disagree with your next statement:
>44% of the projects errors will be inserted within the specification stage >(See "Out of Control by the UK Health and Safety Executive). This is why it >makes sense to remove those errors before you start the design effort.
Oliver -- Oliver Betz, Munich http://oliverbetz.de/
Don Y wrote:

[...]

>> We not only ask "What am I ASSUMING, here?" but we document the assumptions, >> test them thoroughly and even record the reason why it is valid or invalid. > >Exactly. When I write code, the assumptions get coded as invariants *in* >the code. E.g., instead of: > > if (elapsed_time != 0) > average_speed = distance_traveled / elapsed_time; > else > average_speed = ... > >I would write: > > ASSERT(elapsed_time != 0) > average_speed = distance_traveled / elapsed_time;
so you use the same ASSERT for test and production? IMO your example is not very well chosen. It /might/ be suitable if the "assumption" results from a calculation you proved (designed) to yield nonzero results previously. But even then I would try to handle a zero result in a less disruptive way if possible. Oliver -- Oliver Betz, Munich http://oliverbetz.de/
rickman wrote:

[...]

>> In the early days of embedded computing, most embedded developers >> could use a TTY interface at best and instrumented the code with some >> print statements if something went wrong. > >What do you mean "early days"? That still works for me.
it's often (not always) inefficient compared to on-chip-debugging. Oliver -- Oliver Betz, Munich http://oliverbetz.de/
On 12/4/2014 3:51 AM, Oliver Betz wrote:
> Don Y wrote: > > [...] > >>> We not only ask "What am I ASSUMING, here?" but we document the assumptions, >>> test them thoroughly and even record the reason why it is valid or invalid. >> >> Exactly. When I write code, the assumptions get coded as invariants *in* >> the code. E.g., instead of: >> >> if (elapsed_time != 0) >> average_speed = distance_traveled / elapsed_time; >> else >> average_speed = ... >> >> I would write: >> >> ASSERT(elapsed_time != 0) >> average_speed = distance_traveled / elapsed_time; > > so you use the same ASSERT for test and production?
In production, assertions become no-ops -- they don't have handlers associated with them (because they are NEVER supposed to be violated)
> IMO your example is not very well chosen. > > It /might/ be suitable if the "assumption" results from a calculation > you proved (designed) to yield nonzero results previously. But even > then I would try to handle a zero result in a less disruptive way if > possible.
The example was chosen to illustrate something to which most readers could relate -- without knowledge of a particular application. And, to highlight an example where one would TYPICALLY expect to see some explicit code to handle the "zero case" -- code that would effectively be "dead code" (never executed) simply because of the constraints that the invariant clarifies. The presence of this invariant PROCLAIMS that elapsed_time WILL NOT BE ZERO at this point. The developer can read the preceding code to see why that is the case. Or, look at the contract for the routine in which the code fragment is included. The invariant simply makes the assumptions crystal clear in a way that "commentary" would only obfuscate: "The elapsed_time parameter can not be zero because this function is only invoked by "update_display_parameters(). The contract for THAT function states that it will only be updated at some finite frequency which ensures that SOME time will have elapsed between invocations. As a result, *this* function inherits that constraint." YadaYadaYada
On 12/4/2014 5:51 AM, Oliver Betz wrote:
> rickman wrote: > > [...] > >>> In the early days of embedded computing, most embedded developers >>> could use a TTY interface at best and instrumented the code with some >>> print statements if something went wrong. >> >> What do you mean "early days"? That still works for me. > > it's often (not always) inefficient compared to on-chip-debugging.
Define inefficient. I can do the TTY thing with the absolute minimum of hardware and nearly no supporting software. How exactly is that inefficient? -- Rick
Don Y wrote:
>> Don Y wrote:
>>> I would write: >>> >>> ASSERT(elapsed_time != 0) >>> average_speed = distance_traveled / elapsed_time;
> In production, assertions become no-ops -- they don't have handlers > associated with them (because they are NEVER supposed to be violated)
I only disable assertions if I can't afford not to. Failed assertion checks are - when possible - logged, and the impacted component is restarted. If I have to disable some assertions, I prefer to have a (machine generated) proof that the assertion is always true. Greetings, Jacob -- Atheism is a non-prophet organisation.
The 2026 Embedded Online Conference