Addressing your questions...
...would it be wrong to recommend a super-simple architecture, even to solve a complex problem, for an enterprise client?
Absolutely not.
From the Client Perspective
As stated above, it largely depends on the client. It also depends on your ability to accurately gauge which solutions are right for your client. While there is always going to be a perceived cost to desired value, as a consultant it is your job to set the appropriate expectations of the client. In some cases, you'll have to meet that perception. In others, it will be in your best interest to correct them. After all, you should be the expert for your client. And if you aren't, you should have the knowledge to be able to become that expert. That's what they pay you for.
From the Developer Perspective
The hardest part about choosing which architecture to use is, often, correctly estimating the amount of work required to utilize the technology to meet the specific needs. This can very quickly lead to projects that fail client expectations. Understand that some projects are actually made faster using these "complex" pieces of code that you mention. It is also understood that some are not. You have to provide that measurement, based on what you or your team knows.
Is it complexity that defines enterprise solutions, or is it the reliability, # concurrent users, ease-of-maintenance, or all of the above?
While specifics may vary, in general, an enterprise solution is a software solution that applies to a wide co-mingled audience. The number of concurrent users may or may not be a factor, though often is. The total number of users, frequently in a variety of business roles, is one of the largest determining factors as to whether the solution is "enterprise".
Many enterprise solutions are highly complex, but some are quite simple. While enterprise gives an air of reliability (and should certainly be held to a certain standard), different solutions have different levels of reliability.
Ease of Maintenance is something that I think every developer (independent or team member) strives for, it is not necessarily as easily achieved. What is important is that there is a maintenance procedure that has firm guidelines, rather than it be "easy". Remember, different code-bases will have substantially differing levels of ease depending upon the philosophies, methodologies, (business) environment activity, and complexity of the code.
Reacting to your other statements...
In all cases, there was never a need to actually make code swappable or reusable
There is often never a specific need to do so. This should be your goal, at all times, however. Consider this... You might have a client that requires the ability to access or display their calender from the web page. If you make your own code reusable, then when another client asks for the same thing, you already have some of the work done. If you don't, then you have to do it all over again. Every client problem is often one that another client in the future may need. In other words, every client you work with should have the potential to reduce the cost of work for your future clients (not necessarily the cost of the product).
and the tests were never actually maintained past the first iteration because requirements changed, it was too time-consuming,
I would argue here that the testing methodology was not abstracted enough. I recently used a piece of code that did its own unit tests directly within itself. A custom assert
and expect
function were made that accommodated the needs of the project. Anytime a unit test was needed, it could be applied without even adjusting the code. In fact, the code is actively distributed with the asserts and expects still in there. It made those checks as part of the working code.
... deadlines, business pressure, etc etc....
I have often found that extra business pressure and deadlines impeding the coding process have been the fault of the developer, not of the client. While this isn't always the case, many times business pressure is caused by a perception of failure to meet client expectations. When deadlines impede code, it is often because the developer failed to accurately gauge the amount of work required for usable functional code. In other words, schedule them (clients expect it), measure them (future clients expect it), perform them (users require it), and get paid for them (your contract should demand it).