The work a system does and the interface to that work should be separated from one another. This is a concept that evolves from the Single Responsibility Principle and from Test Driven Development. Whether this work be hosted in a console program, a GUI program, exposed as a service for outside systems to utilize, or any other possible configuration, follow SRP and keep the work separate from the hosting interface that exposes the work to a client (a client in this case can be a person or another software system).
What does this mean in practice? It means you should think of a program as an interface to a set of classes that do work. That's all a program is. If you are working on a GUI program, it should barely have any code in it and it should consist of nothing more than methods that handle events. These methods should simply delegate work to core classes and wrap that work with exception handling in case of error. Other than try/catch syntax, you should strive for GUI methods that have one line in each, perhaps followed by a method call that keeps the state of the GUI correct for the task at hand.
The same goes for work reachable by other systems, such as a web service. The hosting of that work should be completely separate from the work itself. Whatever distributed framework you choose (e.g., Remoting, WCF, RMI, DCOM, CORBA, etc.) it should do nothing other than provide the services of the framework and then delegate all work to classes that are under test.
If you follow this rule (really, the rule is just an implementation of SRP) you can expose the work your software really does any way you like with very little effort. And, as always, if you follow TDD, all that work will be tested regardless of the host that is chosen to expose it.
Maximum flexibility and maximum stability with minimal effort.