• I've always liked an "interface" approach, using stored procedures.

    If a developer needs to access customer information, you give them a "GetCustomer" stored procedure.

    This insulates them from the schema and schema changes... you can completely re-architect the underlying tables as long as their interface works the same. This also gives you excellent control over security, as you can have separate interfaces like "GetCustomer" and "GetCustomerPlusConfidentialData", each with its own permissions.

    Unfortunately, this takes more work up front, and it tends to get messy over time when you end with 10 different "GetCustomer" flavors (of which you probably only need 2-3).

    In my experience the view approach usually leads to performance problems. It's OK when the view is SELECT a,b,c FROM [sometable], but as soon as the views get more complicated, queries joining multiple views together get hard for the query optimizer to work with.