I also believe that buffer as an abstraction strictly makes many harder things easier, to the point I often wonder about creating a native library based on elisp buffer manipulation APIs alone that could be embedded in other runtimes instead. So the without touching buffer is a premise/constraint I don't quite understand to begin with.
"But that's like opening a document every time I want to glue two strings together!"
Not at all. A buffer is just a fancy blob of RAM. It's not file-backed unless you make it file-backed. They do take up RAM, but you're programming on a modern computer, not a PDP-11; if you're comfortable with Python using a whole in-memory object to represent an integer, you're comfortable with buffers.
"But it's messy to leave them lying around."
It's a feature. Yes, buffers aren't well-encapsulated and if your program crashes mid-run they get left open. That's by design. You don't need encapsulation because you're not doing multithreading here (and if you are, there are primitives for that and they take a bit more work to use); emacs is for editing and there's only one you, so if the current program is creating buffers and has no way to run two copies of itself at once, who cares. And your program crashing leaving buffers around is a feature; you can inspect the buffer and see what it looked like at crash-time, or set up the buffers the way you want them before firing off the program to get the desired effect (try those tricks with most languages without slapping on a debugger). And there are scripting blocks to create temp buffers and clean up your buffers for you anyway.
"But it's weird to have two ways to talk about strings in the language!"
That's true; it's a bit weird to have the string primitives and also buffers. But that's a pretty common flavor of weird; Java has strings and also has StringBuilder. My rule of thumb is "any time I'd reach for StringBuilder in Java, I should probably consider using a buffer in elisp."