The real issue is plain text, and files and folders.
File names, folder names/hierarchies, function names, class names are all _arbitrary_. You could randomize them all and your code would still run.
What is not arbitrary is: the call graph, and the data flow/dependecy graph.
Every line/block of code could be wrapped in a function.
And classes...your class methods are just functions with an implicit parameter of an object of a certain type...and practically, not the entire object, just the parts it that it actually uses in the function body.
So if you just focus on what your functions do, the boundaries and groupings of your code will become self-evident.
To add to this: the code you are writing and how you access it can be distinct. A static function with all parameters available is accessible but hard to use; adding a builder layer in-front makes it usable without changing the logic.
CLI, RPC, Rest, are all different methods of interfacing with the underlying core function. I too-often see folks make a "microservice rpc server" rather than "function exposed via rpc microservice".
File names, folder names/hierarchies, function names, class names are all _arbitrary_. You could randomize them all and your code would still run.
What is not arbitrary is: the call graph, and the data flow/dependecy graph.
Every line/block of code could be wrapped in a function.
And classes...your class methods are just functions with an implicit parameter of an object of a certain type...and practically, not the entire object, just the parts it that it actually uses in the function body.
So if you just focus on what your functions do, the boundaries and groupings of your code will become self-evident.