To ensure your customers are able to easily override aspects of your theme, the best bet is to stick with WordPress' existing conventions for this, ie: a child theme. "functions.php" is also intended for custom user-entered code, but you said you'd prefer to stay away from that, so I'll focus on other options.
The general rule of thumb is as follows:
Styles
Overriding CSS styles should be done in the "style.css" file inside a child theme.
Functions
Overriding procedural functions should be done using pluggable functions. The WordPress Codex has an example of how to setup pluggable functions.
Hooked Functions
While functions that are assigned to a hook or filter could also be made pluggable, you could also just encourage customers to unhook the function and hook in their own replacement. This would save you, at most, 2 lines of code per function in your files, as you wouldn't be making the functions pluggable.
Template Parts
If you'd like customers to be able to easily override specific sections of your theme's output without having to copy an entire template file into their child theme, you could make effective use of template parts to achieve this (for example, if your footer area contains widgets and then, maybe, a credits section, each of those could be a template part).
As mentioned above, effective placement of do_action()
calls is an easy way to allow customers to hook in their own code.
Combined with the above options, you should be well on your way to having your customers easily customise your theme using existing WordPress conventions and making it easier for them to update their copy of your theme to future versions. :)