Creare delle buone architetture fa in modo che il codice che scrivi non sia fine a se stesso ma sia espandibile, manutentibile, flessibile... questi sono tra gli aggettivi che vengono utilizzati più frequentemente.
Per quanto riguarda il primo punto, se hai deciso che vale la pena implementare un architettura 3 tyer, opterei per la creazione di Stored Procedure: oltre al fatto che SQL server dopo averle eseguite la prima volta le ottimizza e le tiene in memoria fornendo indubbi vantaggi in termini di prestazioni, otterrai un ottima separazione con il livello soprastante e renderai possibili e semplici futre modifiche.
A livello DataAccessLayer puoi anche decidere di implementare un architettura ProviderModel creando una classe astratta con l'elenco dei metodi e poi una serie di provider, ad esempio il provider SQL, che fanno l'ovverride dei metodi virtual della classe abstract, crei una customSection nel web.config e la usi anche per salvare il tipo di provider che utilizzi. In questo modo, se un giorno decidi di passare a MySql ad esempio, dovrai solo aggiungere questo provider e cambiare una riga nel web.config.
A livello BLL, ad esempio, si fa il controllo sui dati, si "adattano i dati da passare alla User Interface"... ad esempio se nel database devi salvare un numero che rappresenta una temperatura, a questo livello formatterai il valore in modo che abbia senso nella UI.
In BLL c'è molto lavoro da fare per ottimizzare le prestazioni: qui ad esempio si implementano i vari meccanismi di CACHING in modo da evitare gli inutili accessi diretti al database per ogni richiesta...
Se hai nel database un elenco di articoli ed hai un metodo a livello DAL che restituisce gli articoli di una determinata categoria, alla prima richiesta, a livello BLL, accedi al database, recuperi i valori, crei una sezione nella cache dove metti i valori recuperati, e li passi alla UI.
Alle successive richieste, a livello BLL, prima di accedere a DAL controlli che la cache non sia vuota per la chiave "articoli per una determinata categoria". Se la cache non è vuota recuperi i valori direttamente da li.
Poi nei metodi che inseriscono un nuovo articolo o ne cancellano uno, a livello BLL ti occuperai anche di cancellare la cache in modo che il metodo precendente che recupera l'elenco degli articoli per una determinata categoria, riacceda alla sorgente dati e ricrei la cache aggiornata.
Altra cosa che si implementa a livello BLL e sulla quale ti consiglio di documentarti è il LazyLoading ovvero, tornando all'esempio degli articoli, il corpo dell'articolo non ti serve da visualizzare negli elenchi ma solo nei dettagli quindi farai un paio di override dei metodi che restituiscono gli articoli: uno che restituisce anche il corpo e uno che non lo carica neanche in memoria... questo detto rapidamente e banalmente: comunque è un argomento molto comune e non ti sarà difficile reperire informazioni.
Già con queste poche cose che ho illustrato credo siano evidenti i vantaggi che si hanno al prezzo di una maggiore fatica: prestazioni, manutentibilità, espandibilità, flessibilità.