Utilizzare l'approccio OOP per organizzare le regole aziendali anziché SOA in un piccolo progetto. Escludendo DDD, c'è qualche strategia per fare questo?

1

Stavo parlando con un amico un altro giorno di OOP in piccoli progetti. Nella maggior parte dei progetti che io e lui abbiamo lavorato, SOA era la regola.

Ad esempio, immagina un ordine in un'applicazione SOA. Lo scenario di questa applicazione potrebbe essere:

  • Molti servizi (UpdateOrderService, CreateOrderService, ecc.) che si chiamano a vicenda.
  • I dati dell'Ordine sono tutti aperti (molti getter e setter) da manipolare per qualsiasi Servizio.
  • Le regole aziendali sono distribuite in molti servizi.

Come ha detto Vaughn Vernon in uno dei suoi libri, questo tipo di strategia non funzionerà bene per progetti più grandi con regole aziendali più complesse. Molti di noi lo sanno anche loro.

A proposito, SOA ha molti significati diversi e sto prendendo quello semplice, descritto da Vaughn Vernon: classi di servizio che si chiamano a vicenda.

L'alternativa più ovvia è Domain Driven Design , giusto? Ma ragazzo, questa risposta per un semplice problema mi ricorda questa frase: "che è aumentata rapidamente". Quando confronti un semplice SOA vs DDD, stiamo introducendo un sacco di nuovi modelli e complessità:

  • Unità di lavoro
  • CQRS
  • Aggregazione
  • Dominio
  • sottodominio
  • Mappers
  • Eventi
  • Comando
  • Oggetto valore

E ecc. Lavoro già in un grande progetto C # usando DDD. È stata un'esperienza straordinaria e un'opportunità per imparare, ma non è pratico introdurre tutti questi concetti in un progetto più piccolo.

Esiste un approccio chiamato DDD-lite , ma non riesco a trovare esempi validi o più dettagliati a riguardo.

Nel territorio DDD-lite, Uno di questi esempi non affronta uno dei problemi principali che appaiono in alcuni progetti: usa l'entità database come oggetto dominio. Per me questo è un errore, perché non è possibile mantenere l'entità aggiornata con i cambiamenti costanti del modello e verrà mescolata con un'altra astrazione presto o tardi (come l'uso di VO per rappresentare alcuni modelli). Vedo l'entità solo come un luogo in cui salvare / aggiornare / eliminare e cercare informazioni.

E, per me, questa traduzione tra database e dominio è una delle principali sfide per creare un progetto OOP. Con tutte le associazioni di oggetti e le operazioni (creare, aggiornare ed eliminare), non ho trovato un modo semplice per introdurlo in un progetto.

Quindi, la mia domanda è: c'è un midterm tra SOA e DDD per introdurre un concetto OOP nell'applicazione senza mantenerli sui Servizi?

    
posta Dherik 23.01.2018 - 15:51
fonte

4 risposte

3

Sì, esiste un'alternativa e non solo esiste, dovrebbe essere la tua scelta predefinita ...

Si chiama incapsulare le regole aziendali in oggetti business :)

La chiave per creare un buon oggetto di business è che non ha dipendenze da niente, tranne forse da altri oggetti di business.

[Business Objects] <-- [Use Cases*] <-- [Data Access] <-- [UI]
*May not be needed for simpler projects
Arrows Show Dependency

Le classi Use Case possono essere utilizzate per modellare transazioni complesse che coinvolgono più oggetti.

Un buon oggetto business non avrà setter per i suoi campi; i suoi campi saranno impostati nel costruttore. Potrebbe avere getter, ma questi getter dovrebbero essere utilizzati solo per visualizzare le informazioni all'utente e per salvarne il contenuto nel database; i getter non dovrebbero generalmente essere usati esternamente per eseguire calcoli.

L'unico modo per modificare i campi di un oggetto business dovrebbe essere attraverso un metodo che rappresenta un'azione che la classe può eseguire.

Account account = GetAccount();
account.IsActive = false; //WRONG!!
account.Deactivate(); //Correct

In Data Access, ci dovrebbe essere un repository per classe Business. I repository dovrebbero avere solo i metodi CRUD che accettano l'argomento associato come argomento o lo restituiscono (o una raccolta di esso).

accountRepository.Deactivate(accountId); //WRONG!!
//Correct:
account = accountRepository.GetAccount(accountId);
account.Deactivate();
accountRepository.Update(account);
    
risposta data 23.01.2018 - 18:45
fonte
0

Ciò che descrivi non è in particolare SOA (Service Oriented Architecture) ma piuttosto Transaction Script sugli oggetti come strutture dati (quelle con molti getter e setter). Ciò che OOP ti porterà è pensare in termini di oggetti e responsabilità che hanno, possibilmente incapsulando certi dettagli lungo il percorso. Un punto di partenza potrebbe essere semplice come mettere metodi / funzioni sulle strutture dati che catturano la lingua e il comportamento che rappresentano e consentire solo a questi di modificare i valori delle tue strutture dati.

    
risposta data 23.01.2018 - 18:10
fonte
0

A lot of services (UpdateOrderService, CreateOrderService, etc) calling each other

Mi sbaglio se pensi che stai complicando le cose direttamente dal salto per un "piccolo progetto"?

Ho la sensazione di avere spesso in mente dei pattern all'inizio dei progetti e di usarli subito, a volte in modo inappropriato.

Per una piccola applicazione, perché non iniziare semplicemente con ciò di cui hai bisogno? Vale a dire, un singolo servizio per contenere tutti i tuoi metodi transazionali, con la logica di business che si trova in quel servizio, e i metodi di servizio che restituiscono le strutture di base ai vari client da visualizzare / manipolare e inviare nuovamente al servizio per CRUD di base e comando e così.

    
risposta data 23.01.2018 - 21:00
fonte
0

Il Quick & Architettura sporca (non consigliato per progetti professionali)

La soluzione che sto per proporre ha dei problemi e non la consiglierei (vedi la mia prima risposta). I problemi con esso possono includere file di origine eccessivamente grandi e l'impossibilità di ridimensionare le prestazioni di persistenza.

Tuttavia, è semplice e veloce da implementare con solo due livelli e continua a incapsulare e organizza la logica aziendale. Inoltre, direi che è meglio di molto di quello che ho visto passare come architettura allo stato brado ... Usare le entità ORM sparse per tutte le applicazioni e "I repository" con logica di business sono sicuramente peggiori.

[Business Objects (With Data Functions)] <-- [UI]

Un oggetto business tipico dovrebbe assomigliare a questo:

class Account
{
      // Descriptors:
      string Name { get; set; }

      bool IsActive { get; set; }

      decimal Balance { get; set; }

      //Business Logic:
      void Deactivate()
      {
          this.IsActive = false;              
      }

      decimal CalculateOwedTax()
      {
           return this.Balance * TAX_RATE;
      }

      //Persistence
      static Account Get(int id)
      {
          return DB.Get<Account>("select * from account where AccountId=@id")
      }

      static IEnumerable<Account> GetAll()
      {
          //DB CODE
      }

      static void Create(Account account)
      {
          //DB CODE
      }

      static void Update(Account account)
      {
          //DB CODE
      }
 }

Nota, è molto importante che il codice di persistenza sia in metodi statici, non è un caso. Non vedrai alcun codice di salvataggio nei metodi di istanza, che sono dedicati all'incapsulamento della logica aziendale.

    
risposta data 23.01.2018 - 21:40
fonte

Leggi altre domande sui tag