This post begins with a short poll. Did you ever let your end-user determine your application's thread pool size? Well if you didn't then you are a better man then us, because we did and we were wrong doing so. Thread pool size is just an example to a variety of performance parameters we tend to publish as configuration. We don't mean to but do so at some point of our application life cycle.
Like any good fairy tale at the beginning everyone are happy with our new application. Then slowly but steady complaints start coming stating it is too slow. To make it faster we use every trick we now. We start optimizing SQL's, parallel what we can, use threads and refactor the code to be more efficient. Everyone's happy? Not Yet! Now we get complaints that although the job is done fast, the application takes too many resources. "No problem", we say and immediately publish every performance parameter we have in the code as configuration. That includes stuff like batch size, poll interval, sleep time and naturally thread pool size.
This turns out to be a bad idea. It is a bad idea because the user has no way of knowing which values are adequate. Moreover the values probably depend on the hardware used, which as we know changes rapidly. It is a bad idea because it uncovers implementation details. But it is a bad idea mostly because it is not part of the user domain language.
Performance parameters should be handled just like any other feature in the software. One should think of the user story behind it and specify configuration accordingly. Some time it is only a terminology change. Instead of using "thread pool size" you use "number of client served simultaneously". Sometimes the mapping from the configuration parameter to an inner parameter will involve some computation and heuristics. So you might configure "Number of items processed per minute" which will be translated to "batch size", "poll interval" and so on....
So keep in mind. Performance parameters are not second-class citizens. It should be specified with the same abstraction layer as the rest of the software. It should hide any inner implementation details and if possible it should be hardware independent.