But take a room full of kids and get them to write a program that blinks an LED, or drive a simple 'robot' forward, and it's awesome. Easy to use. I've never burned out a board (even driving considerable current through them). Things are tolerably well marked. Lots of teaching tools. Lots of different suppliers of easy to connect motors, servos, lights, sensors, etc.
For the same reason, if you are not an embedded engineer, but need a simple micro-controller to turn something on an off like a heater in a chicken coop, it's fantastic. And if you want, buy the $5 knock-off Uno. It should be the same, except that it doesn't support the (now defunct) foundation.
Specific AVR Arduino annoyances I remember:
* Strings loaded to RAM instead of program memory, so you use up all your RAM if you have a lot of text. Easily fixed with a macro
* serial.println blocks, so your whole program has to stop and wait for the string to be transmitted. Easily fixed with a buffer and ISR
* Floating-point used everywhere, because fuck you
* No printf(). It's in avr-libc, and it's easy plumbed in, but the first C/C++ function that everybody ever learned to use was somehow too complicated or something.
* A hacked-together preprocessor that concatenated everything, which meant you could only have your includes in one place, thus breaking perfectly good, portable code.
I think they ultimately did a disservice to novice programmers by giving them something that was almost a standard C++ environment, but just not quite.
Modern AVRs have program memory mapped into the RAM address space. The GCC linker scripts for the parts that support this put strings into .rodata within that memory region, obviating the need for special macros to retrieve them. However, you won't find this on most of the usual suspects in the Arduino AVR ecosystem.
While it does concatenate, does it break something regarding the include mechanism, assuming said files use include guards? You can include stuff wherever anyway (though doing it within a scope needs special considerations).
It's true that you can (and always could) use avr-gcc and libc, but the core sale was what makes it not this.
The "locked in"/captured API and IDE were directly extensions of a language and IDE called Processing.
Processing overlaid an art-focussed layer on top of Java, providing a simpler API, and an IDE with just two buttons.
Arduino was based on this - the same IDE format, similar API conventions (just on top of C++), precisely to allow these same artists to move into physical installations and art.
Arduino was not designed initially to be so general, it was tool written by and for this specific group of people, so has opinions and handrails that limit the space to provide the same affordances as Processing specifically.
Most vendor lock-in isn't "it's impossible to do the thing" but "it's hard enough to do the thing any other way, so this is effectively the only practical way to do it"
I put together a simple setup to skip the arduino ide on an AVR design, but still be able to use their serial.println and other utilities. You can use it side by side with manual register masks for enabling IO.
How so? It uses bog standard avr-gcc and avrdude. There is nothing stopping you from using those yourself.
What's hard about it?