Due librerie che si collegano al database, portando all'odore del codice?

2

Nell'attuale compagnia per cui lavoro c'è una grande libreria di utilità. È stato scritto qualche anno fa (molto prima che mi unissi) e nel tempo è cresciuto in modo ergonomico per fare ora tutto:

  • Invio di email
  • Esportazione di file in diversi formati, ad esempio CSV, delimitato da tabulazioni
  • Ricezione di dati da fornitori di terze parti, ad esempio Bloomberg, Facset
  • Invio di file a siti SFTP
  • Connessione al database generico

L'elenco continua ed è davvero brutto davvero.

Lo sviluppatore originale qui lo ha usato in ogni applicazione che ha scritto per convenienza e aggiunto ad esso se necessario. La stessa libreria di utilità contiene riferimenti a API di terze parti per eseguire alcuni dati in ricezione da Bloomberg / Factset. L'utilizzo di queste API di terze parti significa che qualsiasi progetto che voglia fare riferimento alla grande libreria di servizi di utilità deve anche avere le API dell'API di Bloomberg e le API di Facset. Anche la lista sta iniziando a crescere e sta diventando molto intrattabile e inutile avere tutte queste DLL di terze parti accompagnate da questo grande progetto di utilità, ma è necessario compilarle.

Voglio riscrivere l'intera libreria in librerie più gestibili. cioè:

  • CompanyName.Email
  • CompanyName.FileExporter
  • CompanyName.Bloomberg

Ogni progetto quindi farà riferimento solo ai progetti necessari di cui ha bisogno per svolgere il proprio lavoro. riferimento a CompanyName.Email per inviare e-mail. Non ho problemi a farlo, ma la complicazione che ho di fronte è che alcune delle nuove librerie richiederanno la loro connessione al database e le loro query. L'esempio sotto è:

[HolidayChecker]
[HolidayChecker.DAL]

Memorizziamo un elenco di giorni festivi nel database. Quello che vorrei che il progetto di HolidayCheck dovesse fare è esporre un metodo (tra gli altri) per verificare se una determinata data è una festività.

public interface IHolidayChecker
{
    bool IsHoliday(DateTime dateToCheck);
}
public class HolidayChecker : IHolidayChecker
{
    public bool IsHoliday(DateTime dateToCheck)
    {
        //Query database for date logic...
    }
}

Molte applicazioni faranno riferimento a questo progetto di HolidayCheck e utilizzeranno il metodo IsHoliday. Queste applicazioni avranno anche una propria connessione e query al database per eseguire le proprie attività.

[GenericApplication (References HolidayChecker)]
[GenericApplication.BusinessLogic]
[GenericApplication.DAL]

Se l'applicazione e il progetto di HolidayChecker accedono entrambi al database e interrogano i dati, questo si verifica pesantemente come l'odore del codice. Qualcuno è a conoscenza di un modo più ordinato per raggiungere questo obiettivo? O c'è? È qualcosa con cui dovrò solo convivere?

EDIT:

Pensando a questo durante la notte, non penso che sia un brutto primo pensiero. Progetti come ELMAH sono indipendenti che si collegano anche al database e fanno le loro domande. Come ha sottolineato @ Allan, è solo questione di progettare correttamente il mio progetto di HolidayCheck.

    
posta Gibson 24.05.2013 - 18:38
fonte

4 risposte

5

Suggerirei che l'organizzazione potrebbe essere più importante della separazione. Separare le cose in DLL separate potrebbe essere utile quando una libreria client richiede solo una parte (ma non tutte) della funzionalità totale.

Il mio suggerimento sarebbe di seguire il principio DRY - non duplicare il codice. Il codice condiviso può essere inserito in una libreria di base condivisa tra quelle più specializzate. Fai solo attenzione che non ti trovi in un inferno di dipendenza / DLL in cui devi pasticciare con un intero albero delle dipendenze ...

Per aggirare l'inferno della DLL, consiglierei di creare un singolo file di soluzione (.sln) per l'intera operazione, quindi suddividere le DLL separate come progetti al suo interno. In questo modo puoi ricostruire tutto in una volta, ma avere comunque una certa flessibilità.

Un altro pensiero: mentre lavori attraverso il tuo codice base, potresti scoprire che l'organizzazione in base al caso di utilizzo aziendale potrebbe non essere efficace quanto il tipo di funzionalità o qualcos'altro.

    
risposta data 24.05.2013 - 18:46
fonte
1

Wait. Hai un problema in primo luogo? Cosa stai cercando di risolvere?

Troppo grande

Dici di avere una libreria che è troppo grande . Cosa significa? Può significare che:

  • Il file binario è così grande che difficilmente è possibile distribuirlo. Nessuno vuole includere (e quindi distribuire) un file DLL da 100 MB per poter utilizzare solo alcuni dei metodi.

    È questo il tuo caso? Quanto spazio ci vuole? 100 MB? 1 GB? Raramente ho visto librerie .NET più grandi di pochi megabyte. Date le velocità di connessione media effettive, il prezzo per GB di memoria e spazio su disco, ecc., Un megabyte più o meno non conta, e ovviamente non vale la pena sprecare giorni, settimane o mesi di tempo.

  • La libreria contiene così tanti metodi che non riesci a trovare quello che ti serve.

    Questo non è il problema delle dimensioni, ma piuttosto il problema con l'organizzazione. Crea spazi dei nomi aggiuntivi, se OOP non è stato compreso dal tuo predecessore - refactator pesantemente, ma non dividere una grande libreria in più piccole, solo perché il codice è un casino: probabilmente non risolverà il problema.

Too dependent

Dici che qualsiasi progetto che fa riferimento alla libreria delle utilità dovrebbe fare riferimento anche alle diverse API. Come vengono implementate queste API? Ciò che rende obbligatorio il riferimento a loro? In casi ordinari, in .NET Framework, quando il progetto A fa riferimento al progetto B che fa riferimento al progetto C, A dovrebbe fare riferimento a C se e solo se A utilizza C a B. Pertanto, per risolvere questo particolare problema, è sufficiente correggere il modo in cui tali API vengono referenziate.

Troppo lento?

Potresti anche dire che una grande libreria è più lenta da caricare. Non farlo. Utilizza un profiler, raccogli le metriche e, se e solo se tali metriche mostrano che esiste un intervallo enorme tra il caricamento di una libreria da 1 MB o il caricamento, ad esempio, di quattro librerie da 150 KB, puoi ottimizzare. Senza risultati precisi del profiler, i discorsi sulle prestazioni rimangono pura speculazione.

Quindi, una libreria per tutto?

Ci sono sono ragioni per dividere una grande libreria in diverse più piccole.

  • Tempi di compilazione.

    Su un PC non molto veloce, una grande libreria impiegherà troppo tempo per essere costruita. Se stai lavorando attivamente su una parte della libreria, mentre altre parti rimangono piuttosto stabili, potrebbe essere fastidioso dover ricostruire tutto ad ogni cambio. Mettere il codice su cui stai lavorando in una libreria dedicata può rendere più veloce la compilazione locale.

    Lo so, la compilazione di una libreria, anche di grandi dimensioni, è piuttosto veloce su qualsiasi configurazione decente. D'accordo, ma per quanto riguarda i contratti di codice, ad esempio? Sulla mia macchina, un progetto può essere compilato in pochi secondi, quindi richiedere minuti per eseguire il controllo statico (anche con la cache abilitata, molto sorprendentemente). Una libreria più piccola significa risultati più rapidi, ovvero cicli più brevi.

  • Sicurezza.

    Ridistribuire una libreria significa che può essere oggetto di reverse engineering. Se questo è un problema, meno codice si dà, meno è il rischio che venga rubato e riutilizzato.

  • Livelli.

    Potrebbe essere necessario assicurarsi che alcune parti della libreria non utilizzino altre parti. Ad esempio, in una normale applicazione Web, non è previsto che il livello di accesso ai dati utilizzi il livello di presentazione.

    Per applicare tali regole, userai normalmente Layer Diagram in Visual Studio, specificando quali librerie possono fare riferimento ad altre. Se tutto il codice si trova in una libreria, non esiste un modo semplice per verificare automaticamente che una parte della libreria non ne stia utilizzando un'altra.

  • Frequenti aggiornamenti.

    Se la libreria fa riferimento a un'applicazione utilizzata da centinaia di migliaia di persone e il progetto viene aggiornato quasi ogni giorno, ridurre la libreria di 100 KB significa risparmiare 20 GB di larghezza di banda al giorno, il che non è poi così male.

Conclusione

No, una grande libreria non è un odore di codice e non ha nulla a che fare con gli odori di codice. Potrebbe avere alcuni inconvenienti, ma solo in alcune circostanze particolari.

Sarei più preoccupato se esistessero, ad esempio, cinquanta piccole biblioteche. È difficile organizzarsi, è difficile da gestire e, cosa più importante, gli sviluppatori sarebbero meno inclini a spostare il codice da una libreria a un'altra piuttosto che da uno spazio dei nomi a un altro, il che prima o poi porterà alla duplicazione del codice.

    
risposta data 24.05.2013 - 19:31
fonte
0

Se ci sono molte funzioni condivise pesanti, vorrei spostare il più possibile l'implementazione in un servizio web basato su REST. Quindi tutti gli assembly della libreria possono essere trasformati in wrapper leggeri utilizzando solo le librerie .NET integrate.

Se riesci ad allontanarti dalla distribuzione di dll di client-api (es .: bloomberg) e tenerli in un posto, è molto più facile sostituirli o sostituirli in futuro.

    
risposta data 24.05.2013 - 18:54
fonte
0

Se ho bisogno di trattare con il database, mi piacerebbe avere una singola libreria che fornisce tutte le funzionalità per quel database. Va bene se hai un database di grandi dimensioni con molte operazioni, la chiave è dividere le operazioni in namespace e classi logcal .

Devi solo assicurarti di non utilizzare il database per molte cose non correlate. Sarebbe come avere una classe con bassa coesione (c'è una connessione debole tra i metodi pubblici). Se questo è il caso, dividilo in due database e poi puoi avere una libreria per ciascuno.

    
risposta data 25.05.2013 - 11:17
fonte

Leggi altre domande sui tag