Qual è il design migliore per un utente leggero o un modello pesante per utenti pesanti?

1

Questa è una domanda di design e sono confuso su come progettare il mio oggetto utente. Come nella maggior parte dei sistemi, l'utente è la parte centrale della mia applicazione e molte informazioni sparse nel mio database rimandano all'utente, ad esempio un utente può avere più ordini, più indirizzi e potrebbe aver vinto più premi. Se vogliamo parlare di SOLO utente e delle sue informazioni di base, possiamo farlo con ID, firstnmae, lastname ecc. Quindi ho due scelte chiare

  1. Crea un oggetto utente leggero che assomigli al seguente:
 public Class User
{
  public int Id {get;set;}
  public string FirstName {get;set;}
  public string LastName {get;set;}
  public string SomeMoreInformation {get;set;}
}

e ricevi tutte le informazioni necessarie alle altre informazioni in fase di esecuzione come ordini e premi in base alle necessità.

o

Disegna un oggetto più contenuto che trasporta tutte le informazioni richieste con esso ma è poco pesante:

public Class User
{
  public int Id {get;set;}
  public string FirstName {get;set;}
  public string LastName {get;set;}
  public string SomeMoreInformation {get;set;}
  public Address HomeAddress {get;set;}
  public List<Prizes> Prizes {get;set;}     

}

Qual è il modello di progettazione allineato ad una buona filosofia di design? Ci sono buone pratiche nel tipo di situazione che può aiutarmi a prendere una decisione?

    
posta Lost 31.01.2015 - 02:08
fonte

6 risposte

3

Per rispondere a questa domanda devi distinguere tra fase di analisi delle informazioni e fase di progettazione; anche se i moderni metodi di ingegneria del software spesso li combinano, il modello (non deve essere un documento di 1073 pagine, può essere nella tua mente o nel codice) e il livello di dettaglio è diverso:

  • Nella fase di analisi, il tuo modello corrisponderà strettamente alla realtà, il che significa che è un solo concetto user e alcune idee su quali dati su un utente è richiesto.
  • Nella fase di progettazione, dipende da quali informazioni sull'utente la tua applicazione ha bisogno in varie situazioni e quanto è facile recuperare le informazioni.

Ad esempio, osservando il lato utente di Stack Exchange possiamo dedurre che:

  • Spesso è sufficiente <user name, avatar, reputation, gold medal count, silver medal count, bronze medal count> (ad es. per visualizzare l'autore di un post o un commento).
  • Per visualizzare i commenti, è sufficiente solo user name .
  • Quando qualcuno visualizza un profilo utente, sono necessarie molte più informazioni: <user name, avatar, reputation, gold medal count, silver medal count, bronze medal count, all questions, all answers, all comments, all badges, reputation changes> .
  • Quando un utente effettua l'accesso, sono necessarie le informazioni di autenticazione e la sessione del browser; ma questi non dovrebbero assolutamente essere mostrati nelle informazioni dell'autore.

Quindi qui, concettualmente, abbiamo quattro diverse classi User . Potremmo anche optare per utilizzare <user name, avatar, reputation, gold medal count, silver medal count, bronze medal count> -structure anche per l'autore dei commenti, poiché è comunque disponibile.

Puoi utilizzare l'ereditarietà per combinare i diversi tipi di UserInfo , cioè:

class BasicUserInfo 
{
    public string Name { get; }
    public Image Avatar { get; }
    public int Reputation { get; }
    public int GoldBadgeCount { get; }
    public int SilverBadgeCount { get; }
    public int BronzeBadgeCount { get; }
}

class UserProfileInfo: BasicUserInfo
{
    public List<Post> Questions { get; }
    public List<Post> Answers { get; }
    public List<Comment> Comments { get; }
    public List<Badge> Badges { get; }
    public List<ReputationChange> Reputation { get; }
}

class UserAuthentication: BasicUserInfo
{
    public string PlainTextPassword { get; } // Not really, I hope everyone knows why and 
                                             // how to do this correctly
}

class UserSession: BasicUserInfo
{
    public List<Cookey> Cookey { get; set; }
    public UserAuthentication Authentication { get; }
}

E quindi utilizzare qualche tipo di repository per trovare oggetti UserInfo , ad esempio:

class UserRepository {
    public UserProfileInfo FindUserProfile(BasicUserInfo user)
    {
        // …
    }

    public UserSession FindLoggedInUsers(BasicUserInfo user)
    {
        // …
    }
}

Il repository utilizza deliberatamente la classe base comune, BasicUserInfo , per trovare gli oggetti UserInfo estesi, poiché:

  • consente di utilizzare qualsiasi tipo di UserInfo -object (i.e BasicUserInfo e tutte le estese% varianti diUserInfo) per cercare un esteso UserInfo -oggetto;
  • Sono diffidente nell'usare una stringa o int come ID utente, poiché dimentico le informazioni sul tipo significa che possiamo confondere una stringa o int che contiene qualcosa di completamente diverso con una contenente user id (ad esempio se (UserRepository r, BasicUserInfo u) => r.FindUserProfile(u.BronzeBadgeCount) dove supportato, darebbe risultati sorprendenti.)

TL; DR

A seconda di ciò che richiede l'applicazione, usa class User leggero,% pesante% co_de o usa diversi tipi di class User . Se utilizzi diversi tipi di UserInfo , puoi utilizzare un repository e la classe base comune leggera UserInfo per trovare il BasicUserInfo esteso.

    
risposta data 31.01.2015 - 11:27
fonte
4

Il secondo design è quasi sicuramente migliore del primo, a meno che SomeMoreInformation sia sia molto costoso che completamente opzionale.

    
risposta data 31.01.2015 - 03:42
fonte
3

Il problema con cui ci si confronta è che ci sono numerose descrizioni di "Utente", non tutte applicabili a tutti i client degli utenti.

I client dell'utente non dovrebbero essere costretti a dipendere da metodi o proprietà a cui non sono interessati. È molto meglio suddividere l'oggetto utente in interfacce più piccole, ciascuna delle quali definisce responsabilità concrete.

Vorrei iniziare con il tuo oggetto base che contiene ciò che è vero su tutti gli utenti, e quindi aggiungere funzionalità aggiuntive tramite interfacce opzionali.

Per ulteriori informazioni, consulta il principio "Segregazione interfaccia" ( link ), e ancora meglio, guarda il " SOLID "principi, qui: link

    
risposta data 02.02.2015 - 18:37
fonte
1

Bene, questa è una domanda, la cui risposta dipende in gran parte da quali requisiti dovrebbe soddisfare il modello. Ma in un caso generale voterei per la soluzione 1 (oggetti leggeri) a causa dei seguenti motivi:

  • Di tutte le regole di progettazione delle applicazioni ci sono in un mondo che considero il seguito della massima importanza: Riduci la complessità del tuo codice .

Con la complessità qui capisco la complessità generica percepibile dall'uomo. Se stai creando un puzzle per un bambino di sei anni, può contenere quiz come 2+2=? . Puoi, ovviamente, renderlo 2+2+3-1+14/2+16 e sarà ancora ok. Ma quando diventa qualcosa come sqrt(4)+2*16^2 tende a complicare inutilmente le cose;)

Quando si progetta una piccola applicazione, mettere tutto in un unico modello non importa molto poiché il codice è ancora facile da capire. Ma quando l'applicazione cresce, mettere tutto in una ciotola ti colpirà presto con un codice non gestibile.

  • Per quanto riguarda le prestazioni, è più rapido interrogare / aggiornare piccoli blocchi di dati

  • Di solito non è necessario ogni singolo pezzo di dati del modello per ogni singola operazione, in modo che piccoli blocchi siano ok. Naturalmente, il tuo livello di persistenza dovrebbe essere in grado di lavorare con i dati correlati, ma poi di nuovo, ogni ORM più o meno maturo ora può farlo bene.

risposta data 31.01.2015 - 20:55
fonte
1

Ciò che chiedi riguarda la complessità del codice, i compromessi tempo vs spazio, la strategia di memorizzazione nella cache (se presente) e i round-trip al database.

In generale, tendo ad iniziare con il primo approccio semplice. Quindi, quando e dove i requisiti di rendimento lo impongono, passerò al secondo approccio.

Punto chiave: a seconda dell'utilizzo e della strategia di memorizzazione nella cache, questa mossa potrebbe non essere mai richiesta.

Infine, quando ci si muove in questa direzione, quando si sta interrogando una relazione uno-a-molti (come ogni utente ha una serie di indirizzi e-mail), potrebbe essere possibile recuperare l'utente (i) e tutti gli indirizzi e-mail associati in un round-trip al database. È qui che possono verificarsi notevoli miglioramenti delle prestazioni, soprattutto quando c'è una maggiore latenza tra applicazione e database.

    
risposta data 01.02.2015 - 05:44
fonte
1

La risposta dipende dal tuo dominio e dal framework persistente.

Ad esempio, l'elenco di Prizes sembra essere una parte essenziale dell'utente, tuttavia se un determinato utente ha un sacco di Prizes , e se stai usando il caricamento di questo progetto sarebbe un problema in quanto influenzerebbe le prestazioni, tuttavia se utilizzi il caricamento lazy questo non sarebbe un problema, in quanto non recupererebbe effettivamente questi dati se desideri semplicemente accedere ai dati dell'utente come FirstName e LastName .

    
risposta data 02.02.2015 - 00:53
fonte

Leggi altre domande sui tag