Qual è il design migliore per esporre le informazioni in un sistema di tracciamento dei bug?

5

Stiamo lavorando su un sistema BugTracking e siamo ancora in fase di apprendimento.

Un BugReport ha un titolo, una descrizione, (...) e anche un tag. Un tag rappresenta il progresso del BugReport, ad es.

  • Novità: BugReport appena creato
  • Sotto Revisione: una correzione è stata effettuata ed è in corso di revisione.
  • Duplicato: il BugReport è un duplicato di un altro BugReport (cioè si tratta dello stesso bug)

In quest'ultimo caso, solo un BugReport dovrebbe essere contrassegnato come duplicato e dovrebbe memorizzare il BugReport di cui è un duplicato.

C'è un caso d'uso in cui un BugReport dovrebbe essere ispezionato: "Il sistema mostra una panoramica dettagliata del rapporto bug selezionato (...)"

Tra i colleghi, c'è una discussione su quale sia il design migliore.

Considera di seguire due progetti. Vengono mostrate solo le parti rilevanti del sistema. L'interfaccia utente non è necessariamente parte del sistema.

Design 1

Pro:
Inquestaprogettazione,l'utentericeveun'istanzadell'interfacciaIBugReportincuisonodefinitigliispettoripertinenti(getTitle(),getDescription(),...).Quindi,l'utenteèingradodirecuperaresololeinformazionicherichiede.

Contro:
Questodesignimplicacheognioggettoaziendaleavràbisognodiun'interfacciachedefinisceimetodichepossonoessereutilizzatidall'utente.Inoltre,quandogetDuplicate()vienechiamatosuunBugTag,l'utentepuòrecuperareunvalorenulldaessoseilBugTagnonèunduplicato.Se,infuturo,ades.SottoRevisioneènecessarioavereuncampo(es.UncampoUtentecheindicachistarevisionandoilBugReport),imetodiaggiuntividovrannoesseredefinitieimplementatiintutteleclassiBugTagchelamaggiorpartediessirestituirànull,analogamenteagetDuplicate().

Icolleghichesonoafavorediquestodesignhannoideesimiliperaltredecisionididesign,adesempioquandopossibile,restituisconoun'interfacciadiunoggettobusiness.

Design2

[NOTA:inBugReport,inspectState()dovrebbeesserechiamatoinspectBugReport()]

Pro:
QuandoBugTagacquisiscecampiaggiuntivi,soloilmetodoinspectState()dovràesseremodificatodiconseguenza.Nonc'èbisognodiinterfacceperglioggettibusiness.ilsistemafaesattamentequellochechiedeilcasod'uso:ispezionaBugReport(cioèrestituisciunastringacherappresentalasuarappresentazione).

Contro:L'utenteottieneunastringaincuisonoconcentratetutteleinformazionidaBugReport.Sel'utentedesiderasoloiltitolo,riceveràcomunqueleinformazionicompletesulBugReport.

Icolleghichesonoafavorediquestodesignhannoideesimiliperaltredecisionidiprogettazione,cioèanalizzanoleinformazioniinunastringaelaespongonoalmondoesterno.

Siamounpiccologruppoditrepersoneincuimisonovenutainmenteilsecondodesignequalcunaltroconilprimodesign.Stiamodiscutendopesantementediquestoesiamoentrambifermamentefermi.Laterzapersonaprovaavalutareentrambiiprogettieafornireproecontro.

Stiamotentandodiapplicare principi GRASP . Accoppiamento e coesione sono principi molto importanti nel nostro design. L'estensibilità è importante così come il progetto subisce diverse iterazioni. Ogni iterazione richiede funzionalità aggiuntive. A causa di tutto ciò, sostengo che il secondo progetto è molto meglio. È, per uno, molto più estensibile.

Quali sono ulteriori vantaggi e svantaggi non menzionati sopra? Entrambi i disegni sono ok o sono uno / entrambi i disegni non realizzati?

Questa domanda è sorta dopo questo .

    
posta Auberon 20.03.2016 - 15:51
fonte

3 risposte

3

Entrambi questi disegni violano: Tell, do not ask.

Potrebbe essere troppo tardi. Il resto del tuo progetto, o la tua mente, potrebbe richiedere il modo di fare le cose. Altrimenti, considera un mondo in cui non chiedi a BugTag cosa sta succedendo. Dillo quando è ora di fare la cosa.

BugTag


display(): void

In questo modo, BugTag è un oggetto comportamento non un oggetto dati (come String). Conserverà ancora i dati ma i dati saranno incapsulati quindi nessun altro oggetto deve saperlo. Sarà necessario passare a BugTag qualcosa con cui parlare quando viene visualizzato. Ma davvero non dovresti sentirti obbligato a restituire dati a nessuno. Questi sono i tuoi dati. Custodiscilo gelosamente.

    
risposta data 20.03.2016 - 20:33
fonte
1

L'interfaccia BugTag non dovrebbe nemmeno sapere che Duplicate esiste. Nel design 2 non lo sa. Non vuole saperlo. Questo è buono. Avere getDuplicate() in BugTag in Design 1 crea una violazione del principio di apertura / chiusura in attesa di accadere.

Come, quindi, si crea un collegamento navigabile da un BugReport ad un altro? Bene, lo fai come il design 1. Basta chiamarlo qualcosa che non implica Duplicate esiste.

BugTag


getLinkedBugReport(): BugReport
inspectState(): String

Ora hai un design che non si rompe se in seguito devi aggiungere un Working BugTag o anche un Revisiting BugTag che si collega a BugReport .

    
risposta data 20.03.2016 - 20:16
fonte
1

Suggerimento: dividere il modello di modello di dati / modello di entità dal modello a oggetti dell'applicazione

In entrambi gli scenari sembra che il tuo modello di dati / entità sia confuso con il comportamento dell'applicazione.

Dalle prime entità dati che vedo nel tuo modello, sembra che possano essere riassunte come:

  • Segnala bug
  • Tag
  • Duplica

Da una prospettiva di dati grezzi / entità, non sembra esserci alcuna reale necessità per entità separate di rappresentare i tag New o Under Review ; Nel tuo secondo diagramma hai diverse% di% di entità che sembrano differire solo dai loro dati memorizzati; rendendo ridondanti quelle entità.

Inoltre, le entità di cui sopra avrebbero sicuramente senso nel tuo modello di dati / livello di accesso ai dati, ma non sembrano avere senso come oggetti di applicazione (cioè gli oggetti che contengono comportamenti / metodi relativi a i tuoi requisiti funzionali, principalmente quelli che circondano l'interfaccia utente / le viste.

Considerare le funzioni tipiche per un'applicazione di interfaccia utente CRUD

  • Visualizzazione di sola lettura per un elenco di dati parzialmente visibili / record abbreviati
  • Visualizza i dati compresi i campi calcolati in base a uno snapshot del database
  • Casella dell'editor per aggiungere / aggiornare nuovi dati
  • Anteprima delle modifiche prima del commit finale (con l'opzione di annullare)
  • Convalida i dati appena digitati prima di attivare un pulsante

Il problema di legare il tuo comportamento al tuo modello di entità è che non solo rendi più difficile eseguire molte tipiche operazioni dell'interfaccia utente di CRUD, ma finisci anche con quelle classi di entità che violano SRP.

Esistono entità di dati da un modello di dati per rappresentare i dati persistenti / memorizzati per la vostra applicazione e nient'altro. Quindi: nessuna convalida, nessun comportamento UI / Display, nessuna query, nessuna logica, solo semplici dati strutturati.

Considera la possibilità di inserire il tuo modello dati completo (con dati non elaborati, nessun comportamento) in una classe Tag , che potrebbe includere funzioni per il tuo archivio persistente come Load / Save e accessors per i dati stessi.

Quindi, utilizzando il modello dati per l'accesso ai dati, è possibile incapsulare il resto del comportamento dell'applicazione in oggetti dell'applicazione, che sono a conoscenza del modello dati e della sua struttura, il cui scopo tra l'altro è generare Visualizza dati (alias "modelli di visualizzazione" per coniare un termine di interfaccia utente comune - in cui le preoccupazioni come la convalida dell'interfaccia utente potrebbero generalmente vivere; i modelli di visualizzazione sono oggetti dell'applicazione comunemente utilizzati in modelli come MVC / MVP / MVVM per popolare i dati di visualizzazione e passare i dati dell'interfaccia utente all'applicazione principale verso il basso).

ad esempio:

// Possible ORM model:
class DataModel{
    public List<BugReport> reports;
    public List<Tag> tags;
    public List<Duplicate> duplicates;

    public void CreateReport(BugReport bugReport) { /* etc.. */ }
    public void CreateTag(Tag tag) { /* etc.. */ }
    public void Commit() { /* ... */ }
}

class BugReportMainApplication {
    private DataModel model;

    public BugReportMainApplication(DataModel dataModel) {
        model = dataModel;
    }

    public BugReportListViewModel GetReportList(List<Tag> queryTags) {
        // etc.
    }

    public EditorViewModel GetChangableReport(int id) {
        // etc.
    }

    public void AssignTag(int bugReportId, Tag tag) {
        // etc.
    }
}

Le entità di dati grezzi generalmente non dovrebbero essere interessate alle interfacce / al polimorfismo perché non hanno alcun comportamento - quindi il problema riguardante il tuo metodo di interfaccia DataModel sarebbe irrilevante per il modello di entità; gestita invece in qualsiasi parte della logica dell'applicazione che si occupa in modo specifico della visualizzazione / gestione dei link per duplicare getDuplicate() s.

Per riassumere - prendi in considerazione la possibilità di suddividere l'applicazione in Livelli per evitare di inquinare le entità che rappresentano i tuoi dati non elaborati con logica specifica dell'applicazione e di evitare di essere costretti a scrivere compromessi / aggira le imperfezioni delle astrazioni come l'interfaccia BugReport .

    
risposta data 20.03.2016 - 21:33
fonte

Leggi altre domande sui tag