You can configure WCF from code without creating more coupling than using configuration files.
I like to use the following partitioning:
Server:
- One assembly for your data contracts (models/DTO).
- One assembly for your service contracts (your WCF interfaces).
- One assembly for your service implementations.
- One assembly for your service host creation logic. That assembly will contain a class (WCFHostsLoader) that instantiate the service hosts for all your endpoints.
- One program to wire up the WCF host. Under ASP.Net that could be the Globas.asax. In Globas.asax you would call WCFHostsLoader.Configure().
Client:
The client is a whole separate issue. You implied that the client would have to share the same assemblies (models) as the server. Although that is possible (this is what we do in our project); it is not mandatory.
Option 1 is to share the same model assembly and service contract assembly. As far as I'm concerned, this is the best approach if the client app is written in .Net (and written by you or by a party to whom your can give the two required assemblies). The main advantage is that on the client you don't end up with a bunch on ugly generated classes. I also think this approach is more elegant. Go look at the GoF Proxy pattern. In the pure proxy pattern, one does not proxy the parameters (models) to the service that is proxied.
Options 2 is to use a set of proxy classes generated from the server's WSDL. I think is much more common because a) Visual Studio's Add Service Reference makes this easy. b) If the client is not .Net, it is the only option. If you use the classes generated by Visual Studio's Add Service Reference you might have a hard time trying to take control of the channel factory creation process to configure everything from code instead of from config files (I have never tried to do it). Other tools might exist to generate proxy classes that would be more code configuration friendly.
I hope this helps