Author Topic: What made you choose an RTOS, Linux, or both RTOS and Linux for a real product  (Read 13222 times)

0 Members and 11 Guests are viewing this topic.

Online SpacedCowboy

  • Frequent Contributor
  • **
  • Posts: 429
  • Country: gb
  • Aging physicist
Given the large firms that do a crap job, getting a responsive linux box working is clearly not easy.

Makes one wonder how slow it is for the data packets ;) But at say 1500 MTU, 1k per second will be fast enough for most users.

Here is a video from a couple of weeks ago of my FreeRTOS+ system running on the respectable-but-nothing-special Zynq 7020 board from MyIR. The screen is 32-bit RGBA per pixel running at 1080p.

The key to making this responsive wasn’t anything to do with software coding, or anything particularly Linux or freeRTOS related, it was to divide the workload up intelligently. The Arm A9 runs at 866MHz so they’re not terrible even by today’s standards, but updating an RGBA32 1080p screen (~8.5MB framebuffer) in realtime at 60Hz is still beyond it, if you want smooth animation.

There’s no MALI GPU on a Zynq to use, but there’s a sea of FPGA gates and it turns out that what I really wanted from a “GPU” was just a fast blit, and one that I didn’t have to have the CPU waiting on before it issued another (most of the time, sometimes I did, for readback). This was made particularly noticeable because I had written a compositing window manager, with windows running in retained mode meaning there was only work to draw the screen when it changed.

So I wrote an AXI Blitter, that could do bilinear interpolation (or not), understanding alpha transparency (or not), with the write-operations the window system provided at the API level (or not), that could stretch in X and Y (or not) and that had a 1024-deep command-queue that you could wait for command X to complete (or not). I spent significant effort on that, and it runs at just under 800 MBytes/sec, comfortably enough to let the double-buffered framebuffer look pretty snappy.

Processes know how to draw to their own windows, but have no access to the framebuffer. The compositor shares window memory with the processes and is the only thing that can write to the framebuffer (after “damage” notifications), this leads to some inefficiency, but also means there’s no way for a process to write outside its own windows.

The part of the video towards the end, where I’m clicking around in the Fujinet window is live, I’m connecting to a remote (somewhere in the US, from the UK) server and browsing the files as if they were local. The desktop manages downloading and cache. Timed transfers to the board from my Mac via scp top out at around 750 KBytes/sec, so it’s unlikely to be the bottleneck in any data transfer (at least for this use case).

The hardest thing to get right was the drag-to-the-left live window resize, and if I’m being hyper-critical, there’s probably still a bit more performance I could drag (pun intended) out of that, but overall I’m happy with the desktop performance on this 15-year-old chip.

The point about custom being harder for others to dive in and maintain is self-evidently true, but I do like to keep my code well commented and I even [grin] write docs when I release something. Since this is a personal project that’s not quite as important as when I was working in a huge company, but code that isn’t elegantly structured and well commented offends my sensibilities anyway. Especially as I age, and my “primary cache” seems to be shrinking, I find code that isn’t elegantly structured easy to understand, and informative comments to be more and more essential.
« Last Edit: August 02, 2026, 08:22:54 am by SpacedCowboy »
 

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 8791
  • Country: 00
Quote
Here is a video from a couple of weeks ago of my FreeRTOS+ system

Very nice  :-+
 
The following users thanked this post: SpacedCowboy

Online SteveThackery

  • Super Contributor
  • ***
  • Posts: 3311
  • Country: gb
  • 50 year novice
I partly agree with that. The problem is that avoiding to use pointers in C is impossible to avoid; pointers are a core part of C.

I'm not sure what you mean. I haven't used '*' or '&' in my C code for years (as far as I can remember). What sort of thing cannot be done some other way?

I should emphasise that I'm a permanent novice, so am always willing to learn!
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 30159
  • Country: nl
    • NCT Developments
Given the large firms that do a crap job, getting a responsive linux box working is clearly not easy.
That is utter nonsense. You keep bringing up products where UI responsiveness is not the primary function. Having a slow UI is a direct result from cost cutting in the hardware for those products. It doesn't mean it can't fullfill the primary function quickly. I have been developing embedded Linux systems for nearly 20 years already and I can tell you that creating a responsive Linux box is not difficult at all. Especially with today's SOCs.
« Last Edit: August 02, 2026, 10:40:07 am by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline 5U4GB

  • Super Contributor
  • ***
  • Posts: 1736
  • Country: au
Just posted a long screed about what happens when you use Linux for controller software and don't know what you're doing.  I'm sure you can make an equally large mess with an RTOS, but some of the symptoms covered there (corrupted config files, deadlocks, queue management, a 1GHz CPU not being powerful enough to manage some batteries, multi-minute restart cycles, etc) seem to be specific to not knowing what you're doing with Linux rather than not knowing what you're doing with an RTOS.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 30159
  • Country: nl
    • NCT Developments
I partly agree with that. The problem is that avoiding to use pointers in C is impossible to avoid; pointers are a core part of C.

I'm not sure what you mean. I haven't used '*' or '&' in my C code for years (as far as I can remember). What sort of thing cannot be done some other way?
Most standard library functions and most third party libraries use pointers as a parameters. If you don't want to use pointers in C, then your world gets very small very quickly.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline 5U4GB

  • Super Contributor
  • ***
  • Posts: 1736
  • Country: au
Here is a video from a couple of weeks ago of my FreeRTOS+ system running on the respectable-but-nothing-special Zynq 7020 board from MyIR. The screen is 32-bit RGBA per pixel running at 1080p.

Uhh... so you put a complete GUI on FreeRTOS?  A system whose otherwise highest-level API is something like xQueueSendToFront()?
 

Offline EVblog1Topic starter

  • Regular Contributor
  • *
  • Posts: 145
  • Country: 00
So, for now, I'll put this discussion on hold from my side. If I come across something more specific or have a more focused question later, I'll come back and post it.

Thanks to everyone who took the time to reply.
 

Offline Kilrah

  • Supporter
  • ****
  • Posts: 1994
  • Country: ch
I'm not sure what you mean. I haven't used '*' or '&' in my C code for years (as far as I can remember).
Every time you're passing an array to a function you're actually passing a pointer to the start of that array even if not explicit.
 
The following users thanked this post: nctnico, gf

Offline gf

  • Super Contributor
  • ***
  • Posts: 1826
  • Country: de
I'm not sure what you mean. I haven't used '*' or '&' in my C code for years (as far as I can remember).
Every time you're passing an array to a function you're actually passing a pointer to the start of that array even if not explicit.

Exactly. An array is passed as a pointer; even if a function parameter is declared using array syntax, such as int param1[], it is treated by the compiler as if it were declared as int* param1.

Other reasons for using pointers or referencecs:

* Passing and returning large objects by value is frequently avoided for performance reasons.

* In C++, it is technically impossible to pass a named object by value without involving a reference (-> 1st parameter of copy constructor). The only exception is the in-place construction of arguments, where the object is synthesized directly within the function's memory space (Guaranteed Copy Elision in C++17).

* Passing an object of a derived class by value to a function expecting a base class causes "object slicing" (the derived part is stripped away). Pointers or references are strictly required to preserve polymorphic behavior and dynamic binding.
 
The following users thanked this post: SteveThackery

Online SpacedCowboy

  • Frequent Contributor
  • **
  • Posts: 429
  • Country: gb
  • Aging physicist
Here is a video from a couple of weeks ago of my FreeRTOS+ system running on the respectable-but-nothing-special Zynq 7020 board from MyIR. The screen is 32-bit RGBA per pixel running at 1080p.

Uhh... so you put a complete GUI on FreeRTOS?  A system whose otherwise highest-level API is something like xQueueSendToFront()?

The '+' in 'FreeRTOS+' is deserved, I feel. You even "thanked" that post [grin].

The end-product is slowly coming into sight, but there's no rush (being retired and all).
« Last Edit: August 02, 2026, 11:50:35 am by SpacedCowboy »
 

Online paulca

  • Super Contributor
  • ***
  • Posts: 6386
  • Country: gb
The key to embedded software design is to identify the processes and their time constraints. How to implement these processes is the next step but coding style / modularisation are at the maintenance and verification side of the spectrum rather than at the functional side.

The processes are probably modules or modular themselves.

If one thing requires a 400ns response time, then right there is your boundary which sets that bit of code aside from others.  What point would there be, say, in coupling everything to the same 400ns timing constraint?

Do other bits of code provide to this 400ns process or consume from it? 

You comment on unit testing, might miss the point.

"This C files works as intended".
"Prove it."
"Ok, let me fire up the rest of the project."
"Waiting...."
"Oh, sorry the UART isn't setup, can't test it."

That or...
"It worked fine with that first UART periph we used, why doesn't the test pass now?  Which bit is broken?"

The real jewel in the crown of unit testing with proper isolation is when you "tweak that one thing" or do that "one merge" or "one bit of refactor", you at least get a "signal of confidence" when the unit tests "STILL pass".

There are those who argue if you can make ANY change at all to a code base and not have at least one test fail, you haven't got enough testing.

There are even "Dynamic unit tests" these days.  A process where by an application forces mutations on your test values and logs if the test fails or passes with "junk data".  "Mutative testing".

I'll give you a few clear examples of coupling and how unit testing pulls them out when you don't normally even see them.

You have a C module which calls an RTC to get a binary-decimal value for "now".  It might then decode that into the values it wants, like epoch.  It might then compare it to a "last watermark" and if more than 1 minuted has passed and if it's a weekday, start a process running.

Sounds fair right?  How do you test this in isolation?  "Invoke it and look at the output?".  Okay, so how do you verifiy it's working as intended? 

The options are to try and synchronise your harness clock with the DUT and wait for 1 minute to check it started the process.  On a weekday... and how do you set the last watermark run it twice?
OR
and this one is valid:  "Mock" the RTC.  Have the "fake RTC" provide that "getNow" functionality, like the real RTC.  Provide a fixed test date or array of troubling dates which cause bugs before - which is the professional touch.

It might be better to provide a "setNow" feature to the module and not have it go and get it itself.  The later plumbing is about 1 line.  Keeps the RTC gubbins, including that decode to epoch, with the RTC gubbins and away from "business logic".

You electronics folks use "Mocks" all the time and don't call them that. 

Consider testing a tranmission line.  It is modelled as a separate component on it's own for a reason.  When you are testing something which will use a transmission line, you don't give it the real one, do you?  You give it the test "mock" transmission line. 

When you want to create a latch structure which must respond to CPU 'edges' and provide edges with the correct timing.  Do you hook it up to a real CPU while in dev?  Or do you use an ARB or Logic generator to produce the edges and a scope or LA to capture the response.  If your quality and test requirements require it you have a bench model of that setup run on every board... no?

Of course it's only ONE form of testing, but arguably the first line of defense.  It also teases out the problems with code when it can't be tested insolation it means it coupled to it.  Two ore more become one.  They aren't really separate modules at all.  You can't have one without the other etc.

In isolation these all sound trival, but in aggregate they kill code bases due to untracable and undocumentable behaviours later.

In the professional side, you literally cannot submit code without unit tests.  It will be rejected instantly, "Computer says no" for a start but also the team will raise it if the pipeline does not.

« Last Edit: August 02, 2026, 12:10:55 pm by paulca »
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 4838
  • Country: us
The linux SBC is like a poorly maintained vintage car - it breaks down all the time and consumes a lot of fuel, but then again "anyone can fix it". That's the appeal. If your (or mine) MCU-based FreeRTOS solution has a serious bug or needs a large design update, the number of people who can do it is one thousandth of those who can reinstall a newer Debian or write a bash script or make systemd launch something at boot.

Or to put it another way, "any idiot can slap together a device running Linux, and they frequently do".

I think in many cases the problem is RAM.  At the low end Linux systems tend to take more RAM than alternatives.  On the other hand given any given Linux device, you can reduce the cost by reducing the DRAM so much that it is slow, but still functional.  Nearly 100% of consumer electronics devices do this.
 

Online NorthGuy

  • Super Contributor
  • ***
  • Posts: 3519
  • Country: ca
"This C files works as intended".
"Prove it."
"Ok, let me fire up the rest of the project."
"Waiting...."
"Oh, sorry the UART isn't setup, can't test it."

That or...
"It worked fine with that first UART periph we used, why doesn't the test pass now?  Which bit is broken?"

"I gave the fucking UART interrupt too high priority, so the emergency shutdown interrupt got postponed and now all the FETs are blown up"
"Why the hell your emergency shutdown uses interrupts? It must've been CPU independent!!!"
"But it worked in unit testing ... "
« Last Edit: August 02, 2026, 01:40:50 pm by NorthGuy »
 
The following users thanked this post: nctnico, KE5FX

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 11185
  • Country: fi
I partly agree with that. The problem is that avoiding to use pointers in C is impossible to avoid; pointers are a core part of C.

I'm not sure what you mean. I haven't used '*' or '&' in my C code for years (as far as I can remember). What sort of thing cannot be done some other way?

I should emphasise that I'm a permanent novice, so am always willing to learn!

You are probably using pointers, still, by language quirks that bypass the explicit syntax, such as array name decaying to the pointer to the first element, and that pointer can be dereferenced by [] syntax, which you also probably use.

And because C standard library, and most code done by others, use pointers in function interfaces, you can't avoid using it yourself.

So you are using pointers all the time anyway, just that you do it unknowingly - the most dangerous way to use them! Then you get the false sense of security through antagonizing pointers, which you do use, but don't know you are using, and think you are good.

And brainfuck is turing-complete as well. But bugs are best avoided by writing clear, easy to understand, testable and reusable code. Can't totally avoid pointers on C - but yes I agree, avoid overuse and weird hacks. And you can pass arrays to functions as arrays, without relying on decaying on pointers, in which case compiler can check more. It's just traditionally not done, so, a pointer (which you don't know you are using), a size parameter, and manual range checking (if even that) inside the function is what we are used to.

C++ isn't a silver bullet. So you think references are much safer? Well nope, at least I fell into the trap where some library function was mutating my data which was very nasty to debug - I had no idea the library would mutate the argument because it's not visible from the code. C's & is good syntax: by calling func(&param) you instantly see "hey, something unusual is going on" and once you learn what it is, you understand "oh, this & here means the function can actually mutate my variable", and when you learn even more, you understand "the mechanism to this mutation is that the address of param is given to the function, so the function can directly mutate it". You are covered since the beginning. But C++ references "conveniently" hide the fact, from func(param) you can never know if param ends up being modifier or not, except to pull the declaration of func() (which IDEs helpfully do, to be fair). It's a risk that realizes. I prefer explicit over implicit, and I don't fear extra letters or symbols when they have something important to convey.
« Last Edit: August 02, 2026, 02:03:34 pm by Siwastaja »
 
The following users thanked this post: SteveThackery

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 30159
  • Country: nl
    • NCT Developments
"This C files works as intended".
"Prove it."
"Ok, let me fire up the rest of the project."
"Waiting...."
"Oh, sorry the UART isn't setup, can't test it."

That or...
"It worked fine with that first UART periph we used, why doesn't the test pass now?  Which bit is broken?"

"I gave the fucking UART interrupt too high priority, so the emergency shutdown interrupt got postponed and now all the FETs are blown up"
"Why the hell your emergency shutdown uses interrupts? It must've been CPU independent!!!"
"But it worked in unit testing ... "
I agree. Unit testing does not take execution time into account. Only function.

An example: a long time ago I designed an acoustic echo canceller. The DSP algorithm worked great on a PC when tested as a unit. However, on a microcontroller it took like 2ms per sample to execute while I only had 100us per sample.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 11185
  • Country: fi
I agree. Unit testing does not take execution time into account. Only function.

And only tiny piece of function, because on almost any real-world project, function of the whole is more than the sum of functions of the units; function comes from how the modules interact. That, by definition, cannot be unit tested. I don't understand why many professionals talk so much about unit tests when they are only a tiny piece of testing. Unit tests are good to supplement integration testing because they can sometimes reveal weird corner cases that don't come across in golden paths. They are also quick to run, but that's it. They can't replace careful design, thinking, and integration tests or end-to-end tests.
« Last Edit: August 02, 2026, 02:15:04 pm by Siwastaja »
 
The following users thanked this post: tggzzz

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 8791
  • Country: 00
But unit testing isn't done to the exclusion of everything else. You can still do all your other testing you normally do as well. It's just another means of catching silly bugs. And, as paulc points out, nicely encapsulating logic with low coupling to other units.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 11185
  • Country: fi
But unit testing isn't done to the exclusion of everything else. You can still do all your other testing you normally do as well. It's just another means of catching silly bugs. And, as paulc points out, nicely encapsulating logic with low coupling to other units.

Yeah, it's just gets out of proportion. Like paulca says, in professional world you can't submit anything without unit test and your work will be rejected etc. etc. blah blah, but no one says the same about: design, documentation or integration tests. It seems "oh, someone else will figure it out".

Our professional humans wrote unit tests and then changed the code, to see unit test fail, and then "fixed" the unit test to match the broken code, and were proud they had (A) done unit tests, (B) "fixed" them. It's an attitude problem that comes exactly from the mindset that having unit tests is important as some sort of rain dance. Having been interested about the logic user wants to see would have been more valuable, even if unit test was missing.

The fact is, unit tests very rarely fail. They are fairly easy to write, quick to run, and fail rarely, so they are a preferred form of tests by professionals - the easiest "tick the box".

But I like how paulca in this thread presented an interesting secondary use for unit test: as a litmus test to measure functional isolation - if you can't write meaningful unit tests, something's wrong in how your code is organized. I wholeheartedly agree (but add that this can fail in both extremes - too many interactions, can't test anything as paulca presented it, but also: forcefully over-isolated, can't test anything meaningful).
 

Online SteveThackery

  • Super Contributor
  • ***
  • Posts: 3311
  • Country: gb
  • 50 year novice
I partly agree with that. The problem is that avoiding to use pointers in C is impossible to avoid; pointers are a core part of C.

I'm not sure what you mean. I haven't used '*' or '&' in my C code for years (as far as I can remember). What sort of thing cannot be done some other way?
Most standard library functions and most third party libraries use pointers as a parameters. If you don't want to use pointers in C, then your world gets very small very quickly.

Ah, thank you, that's a good point which I'd overlooked. I was thinking mostly about pointer manipulation, which I try to avoid because I think I'd be prone to making bugs. But for parameter passing, pointers are fine and inevitable. I'm just embarrassed I forgot about that. 😄
 

Online SteveThackery

  • Super Contributor
  • ***
  • Posts: 3311
  • Country: gb
  • 50 year novice
I'm not sure what you mean. I haven't used '*' or '&' in my C code for years (as far as I can remember).
Every time you're passing an array to a function you're actually passing a pointer to the start of that array even if not explicit.

Exactly. An array is passed as a pointer; even if a function parameter is declared using array syntax, such as int param1[], it is treated by the compiler as if it were declared as int* param1.

Thanks guys. I'm feeling embarrassed because when I wrote that post I was thinking about pointer manipulation, which I avoid because I'd probably get it wrong. I completely overlooked the parameter-passing thing, which I use all the time. Next time I'll engage my brain first!
 

Online NorthGuy

  • Super Contributor
  • ***
  • Posts: 3519
  • Country: ca
But unit testing isn't done to the exclusion of everything else. You can still do all your other testing you normally do as well. It's just another means of catching silly bugs. And, as paulc points out, nicely encapsulating logic with low coupling to other units.

As with anything else, there are circumstances where unit testing is useful, and there are circumstances where it is not. You should do it when it helps you, you shouldn't do it when it wastes your time, and you should use wisdom to tell these situations apart.
 

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 8791
  • Country: 00
But unit testing isn't done to the exclusion of everything else. You can still do all your other testing you normally do as well. It's just another means of catching silly bugs. And, as paulc points out, nicely encapsulating logic with low coupling to other units.

As with anything else, there are circumstances where unit testing is useful, and there are circumstances where it is not. You should do it when it helps you, you shouldn't do it when it wastes your time, and you should use wisdom to tell these situations apart.

Sure. I was responding to the eye rolling negativity, as if even thinking of using it is bad, and the assumption that it would of course replace all other testing.
 

Online peter-h

  • Super Contributor
  • ***
  • Posts: 6003
  • Country: gb
  • Doing electronics since the 1960s...
Quote
Quote
I completely overlooked the parameter-passing thing, which I use all the time. Next time I'll engage my brain first!

Well I don't call that "pointers" either. The * and & is "passing a variable by its address* rather than by value. All languages AFAIK have that (maybe not Basic?).

Try to work out how this works:

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef struct Node {
    int value;
    struct Node *xor_ptr;   // XOR of the "previous" and "next" addresses
} Node;

// XOR two pointers together, treating them as integers
static Node *xor_ptrs(Node *a, Node *b) {
    return (Node *)((uintptr_t)a ^ (uintptr_t)b);
}

Node *new_node(int value) {
    Node *n = malloc(sizeof(Node));
    n->value = value;
    n->xor_ptr = NULL;
    return n;
}

// Insert `new_node` at the end of the list.
// `prev` is the node before `tail`, or NULL if the list is currently empty.
void append(Node **head, Node **tail, Node *prev, Node *new_n) {
    if (*head == NULL) {
        *head = *tail = new_n;
        return;
    }
    (*tail)->xor_ptr = xor_ptrs((*tail)->xor_ptr, new_n);   // fold in the new link
    new_n->xor_ptr = *tail;
    *tail = new_n;
}

// Traverse forward through the whole list, starting from head.
void print_list(Node *head) {
    Node *prev = NULL;
    Node *curr = head;

    while (curr != NULL) {
        printf("%d ", curr->value);
        Node *next = xor_ptrs(prev, curr->xor_ptr);
        prev = curr;
        curr = next;
    }
    printf("\n");
}

int main(void) {
    Node *head = NULL, *tail = NULL;

    Node *a = new_node(1);
    Node *b = new_node(2);
    Node *c = new_node(3);

    append(&head, &tail, NULL, a);
    append(&head, &tail, a, b);
    append(&head, &tail, b, c);

    print_list(head);   // prints: 1 2 3
    return 0;
}

Here's another

Code: [Select]
#include <stdio.h>

void duff_copy(short *to, short *from, int count) {
    int n = (count + 7) / 8;   // number of groups of 8

    switch (count % 8) {
        case 0: do { *to++ = *from++;
        case 7:      *to++ = *from++;
        case 6:      *to++ = *from++;
        case 5:      *to++ = *from++;
        case 4:      *to++ = *from++;
        case 3:      *to++ = *from++;
        case 2:      *to++ = *from++;
        case 1:      *to++ = *from++;
                } while (--n > 0);
    }
}

int main(void) {
    short src[13] = {1,2,3,4,5,6,7,8,9,10,11,12,13};
    short dst[13] = {0};

    duff_copy(dst, src, 13);

    for (int i = 0; i < 13; i++) printf("%d ", dst[i]);
    printf("\n");   // prints: 1 2 3 4 5 6 7 8 9 10 11 12 13
    return 0;
}
« Last Edit: August 03, 2026, 06:52:37 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 
The following users thanked this post: SteveThackery

Online paulca

  • Super Contributor
  • ***
  • Posts: 6386
  • Country: gb
But unit testing isn't done to the exclusion of everything else. You can still do all your other testing you normally do as well. It's just another means of catching silly bugs. And, as paulc points out, nicely encapsulating logic with low coupling to other units.

Yeah, it's just gets out of proportion. Like paulca says, in professional world you can't submit anything without unit test and your work will be rejected etc. etc. blah blah, but no one says the same about: design, documentation or integration tests. It seems "oh, someone else will figure it out".

Our professional humans wrote unit tests and then changed the code, to see unit test fail, and then "fixed" the unit test to match the broken code, and were proud they had (A) done unit tests, (B) "fixed" them. It's an attitude problem that comes exactly from the mindset that having unit tests is important as some sort of rain dance. Having been interested about the logic user wants to see would have been more valuable, even if unit test was missing.

The fact is, unit tests very rarely fail. They are fairly easy to write, quick to run, and fail rarely, so they are a preferred form of tests by professionals - the easiest "tick the box".

But I like how paulca in this thread presented an interesting secondary use for unit test: as a litmus test to measure functional isolation - if you can't write meaningful unit tests, something's wrong in how your code is organized. I wholeheartedly agree (but add that this can fail in both extremes - too many interactions, can't test anything as paulca presented it, but also: forcefully over-isolated, can't test anything meaningful).

The unit tests themselves have "quality". Some good ones, some bad ones.

The unit test is not there to tell you "the whole thing works."  It is there to tell you:

"This works as I intended it to."
"This STILL works as I intended it to."

They developer level tests.  They test "This unit does X as I intended".  It does not test that it's right. 

Integration tests is usually where the most effort is.  I would agree, not enough is done.  AI will hopefully change this as it removes the barrier of "work" form it.   Integration tests are very high effort.  If done right there are 5 time THAT effort.  You are not meant to put "everything" into integration and test it, thats a systems test or e2e.  You are meant to test integration  points in isolation, each at a time.  Then in groups, etc.

You can mock at the ceremony of having units tests, but I would say, the mockery is in having "none at all".
« Last Edit: August 03, 2026, 07:46:31 am by paulca »
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf