Condivisione codice DAL - MicroService v Libreria condivisa [chiusa]

5

Qual è l'opzione migliore per condividere il codice DAL.

Abbiamo una bella libreria c # che include i metodi SQl.Data.SqlClient come .ExecuteNonQuery, ExecuteReader, ExecuteScalar ecc. Aggiunge funzioni di logging e helper attorno ai Parametri e restituisce in genere IDataRecords pre-polimerizzati. Questo è il codice standard che vorremmo condividere con molte e molte delle nostre applicazioni. Ma inevitabilmente cambia.

Se facciamo il percorso della libreria shard (DLL), il lato negativo è, se aggiorniamo questo codice, per evitare di mantenere più versioni in circolazione, dobbiamo aggiornare / rilasciare più di 50 applicazioni. Se lo avvolgiamo in un microservizio, allora possiamo gestire il controllo delle versioni, ma c'è un sovraccarico nel passare i dati attraverso il filo.

Qualche idea qui, come fanno gli altri a risolvere questo.

    
posta PeteN 16.03.2017 - 12:01
fonte

3 risposte

4

In caso di dubbio, KISS e YAGNI .

Tuttavia, trovarsi di fronte a una decisione architettonica come questa ha anche implicazioni commerciali chiare.

Da un lato, la costruzione di più indiretta (e quindi maggiore complessità, costi di sviluppo più elevati e più codice da mantenere) è un costo aggiuntivo abbastanza quantificabile rispetto alla soluzione più semplice; considera anche il costo (o l'efficienza) di KISS e YAGNI in termini reali.

  1. Quanto costa (quanto tempo ci vuole) per aggiornare le tue applicazioni live?

  2. Con quale frequenza avvengono gli inevitabili cambiamenti? Il processo di rilascio del software può essere modificato per ridurre la frequenza con cui vengono implementate tali modifiche? (magari anche inserito con altre versioni programmate sul lato client?)

  3. Se il costo è elevato, ci sono dei miglioramenti "quick win" che potresti apportare al processo di implementazione per ridurre in modo significativo tale costo? (Ad esempio, implementazione di ClickOnce)

  4. Quanto è dirompente il processo di aggiornamento per ogni cliente / cliente? (e ancora, ci sono delle vincite veloci che potrebbero ridurre l'interruzione?)

  5. Chi è coinvolto nel processo di distribuzione che sarebbe interessato dalla necessità di implementare gli aggiornamenti e come si sentono riguardo al costo? Il processo potrebbe essere gestito da personale economico / junior (se non lo ha già fatto)?

Sebbene nessuno di questi aspetti sia di natura tecnica, la risposta "giusta" a molte decisioni tecniche deve spesso essere presa da una prospettiva aziendale e finanziaria.

Se il business case per spendere ulteriore sforzo su un microservizio non è giustificabile adesso , ciò non significa che non lo sarà in futuro. Prendi in considerazione la possibilità di scrivere la DLL in modo tale che la tua decisione possa essere posticipata ad una data successiva.

Ciò implica la progettazione dell'interfaccia alla DLL in modo tale che sia più facilmente intercambiabile con una DLL Client Microservice. La chiave per questo è garantire che nessuna delle applicazioni abbia alcuna dipendenza diretta da nessuna delle classi del wrapper SQL. Utilizzare una classe "proxy" con le proprie interfacce e i propri modelli DTO (ovvero i modelli proxy distinti da qualsiasi classe utilizzata dal wrapper del client SQL).

Mentre una classe proxy di questo genere sarebbe un mucchio di regole le cui classi iniziano ad apparire come una shell vuota di altre classi esistenti e il cui comportamento è limitato alla mappatura da un'interfaccia all'altra, la motivazione per farlo è:

  • Riduce al minimo le interruzioni future causate dalla sostituzione della DLL wrapper SQL con una DLL client Microservice.
  • Mantiene una separazione netta tra il codice di wrapper SQL del tuo DAL e le tue applicazioni.
  • Forza almeno parte del duro lavoro nella creazione dell'API Microservice in anticipo senza implementare effettivamente il servizio stesso.
risposta data 16.03.2017 - 13:39
fonte
3

Abbiamo creato una Dll condivisa per cui raccomanderei questo approccio. Abbiamo un server Nuget privato in cui è memorizzato il componente in modo che i clienti possano ottenere nuove versioni in qualsiasi momento. Non cambia molto Quando cambia, semplicemente aggiorniamo il codice e quindi inseriamo un nuovo pacchetto Nuget. I clienti possono prendere la nuova versione dalle loro app poiché si tratta di un riferimento Nuget. Lo rendiamo compatibile all'indietro in modo che le versioni precedenti possano esistere con le versioni più recenti.

Le tue prestazioni saranno peggiori perché ora c'è un altro salto nel tuo data store se segui il percorso del servizio. Se hai molti clienti diversi, un servizio può essere una scelta migliore dal momento che sia .net che java possono utilizzare il servizio anziché una Dll specifica per piattaforma. Ma se tutti i client .Net non posso immaginare un servizio per questo.

Come @Ben ha commentato, abbiamo implementato così l'unico riferimento al bisogno del client .Net è System.Data . Tutti gli altri riferimenti sono nel componente Dll che sarà gestito dal pacchetto Nuget. Quindi, se l'implementazione di Sql Server cambia, i client non ne sono consapevoli. Se la dll è impostata in questo modo, avrà una buona separazione delle preoccupazioni.

Implementazione del codice client di esempio:

            IDbCommand command = CommandFactory.Create("GetSampleById");
            command.Parameters.Add(ParameterFactory.Create("@Id", 11));

            var db = new SampleReader {ConnectionString = connectionString};
            var samples = db.ExecuteReader(command);

Per indirizzo @ commenti di Vincent sotto ...

Il mapping della colonna viene gestito dal client, non dall'API. L'API esegue semplicemente i comandi forniti ad esso.

Lettore: fornisce mapper.

    public class SampleReader : Database<Sample>
    {
        protected override MapperBase<Sample> GetMapper()
        {
            MapperBase<Sample> mapper = new SampleMapper();
            return mapper;
        }
    }

Mapper: esegue il mapping degli IRecords a un DTO.

IRecord appartiene a System.Data quindi nessuna dipendenza diretta dalle dipendenze di Sql Server. Se vuoi mappare un'altra colonna, aggiungila al mappatore ...

public class SampleMapper : MapperBase<Sample>
{
    private const string Id = "Id";
    private const string Name = "Name";
    private const string DataValue = "DataValue";
    private const string Created = "Created";

    protected override Sample Map(IDataRecord record)
    {
        return new Sample(
            Utility.ConvertObjectToType<Int64>(record[Id]),
            Utility.ConvertObjectToType<String>(record[Name]),
            Utility.ConvertObjectToType<Int32>(record[DataValue]),
            Utility.ConvertObjectToType<DateTime>(record[Created])
            );
    }
 }          

La classe di utilità appartiene all'API e gestisce le conversioni di tipo SQL Server in C #.

Naturalmente, i mapper e i lettori possono essere automaticamente generati automaticamente dalla stored procedure e / o query fornite per un tipo di applicazione ORM di peso leggero.

    
risposta data 16.03.2017 - 15:34
fonte
0

Fai entrambi. La libreria condivisa costituisce la base per molti dei tuoi microservizi.

Ovviamente hai bisogno di un'altra libreria condivisa per l'utilizzo di tutti i tuoi microservizi. Quindi alla fine avvolgi un servizio intorno a questo. E poi hai bisogno di una nuova libreria per il servizio. E così via, fino a quando un giorno ti guarderai indietro e le tartarughe arriveranno fino in fondo :D

    
risposta data 16.03.2017 - 17:26
fonte

Leggi altre domande sui tag