Definire componenti riutilizzabili avendo in mente un'applicazione specifica

3

Negli ultimi mesi ho imparato molto nella progettazione e nelle pratiche del software in diverse lingue e strutture. Per me, i modelli di design più attraenti e utili sono quelli che seguono un approccio orientato agli oggetti. In particolare, sono attratto da un approccio che promuova la riusabilità, la modulazione, la comprensione (riutilizzo del codice capito) e altro ancora.

L'approccio generale che mi trovo spesso ad usare è quello che incapsula la funzionalità del programma in componenti separati con un accoppiamento minimo. Quando visualizzo questo disegno, spesso immagino una struttura gerarchica di oggetti e sottooggetti, in cui ognuno è solo consapevole della propria interfaccia e di quelli dei suoi membri. Come ho capito, quest'ultima parte è essenziale per raggiungere le caratteristiche ricercate che ho citato sopra.

Tenendo presente questo, per i vari progetti sui quali ho lavorato negli ultimi due mesi mi sono trovato a colpire i blocchi stradali del design. In che modo esattamente definisco un oggetto tale che sia in grado di soddisfare le sue funzionalità previste all'interno della mia applicazione pur avendo anche un'interfaccia semplice e intuitiva? Più specificamente (e forse in parole più semplici), come posso implementare la funzionalità necessaria in un oggetto, che non è troppo specifico per le applicazioni comuni?

Descriverò un caso in cui sto affrontando questo problema:

Lavorare con il framework Java Server Faces (JSF) per creare un'applicazione web, quindi il mio design è incentrato sul template di pagina. Ciò comporta la scrittura di modelli XHTML che possono essere riutilizzati quando necessario.

Voglio creare un modello di intestazione che contenga tutto il margine di intestazione che userò in tutto il mio sito web. Ecco un esempio:

<!-- header.xhtml -->

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html />

<html  xmlns="http://www.w3.org/1999/xhtml"    
       xmlns:ui="http://java.sun.com/jsf/facelets">

<body>
    <div class="title">My Website</div>
</body>

</html>

Ora, se voglio aggiungere un po 'di flessibilità per servire diversi titoli di intestazione, posso aggiungere un tag insert in questo modo:

<body>
    <div class="title">
        <ui:insert name="insertTitle">My Website</ui:insert>
    </div>
</body>

I dettagli non sono importanti per questa discussione, ma il tag insert consente alle pagine che utilizzano questo modello di aggiungere un titolo personalizzato al posto del My Website predefinito.

Questa funzionalità aggiunta al modello sembra appropriata e potrebbe sicuramente ricevere un uso comune.

Che cosa succede se, tuttavia, ho una singola pagina sul mio sito web che necessita di un pulsante nell'intestazione? Devo aggiungere un altro tag di inserimento per questo scopo, anche se ha un singolo utilizzo? In tutti gli altri usi del modello questa funzionalità viene ignorata e quindi potrebbe essere considerata spreco di codice.

Questo mio problema non si presenta solo quando si lavora con il template HTML, ma per qualsiasi approccio che implichi la progettazione di sottocomponenti riutilizzabili. Qualsiasi suggerimento o idea di progettazione per la scelta della funzionalità sarebbe molto apprezzato.

    
posta Dan 26.07.2016 - 22:08
fonte

2 risposte

3

Potrei essere down-votato per averti detto di non usare OOP, ma: non usare OOP.

Cercherò di spiegare perché senza esaurire lo spazio:)

Particularly I am drawn to an approach that promotes reusability, modularity, understanding (reusing understood code), and more.

Certo che lo sei! Questo è ciò a cui tutti gli ingegneri del software puntano. È il Santo Graal. Nessuno sta intenzionalmente cercando di creare codice anti-modulare. Inoltre, nessuna lingua può fare in modo che tutto il codice che scrivi corrisponda a questi criteri. Non esiste un linguaggio di programmazione per scopi generici di magic-bullet.

The general approach that I find myself using often is one which encapsulates program functionality into separate components with minimal coupling.

Questo è l'obiettivo, non un approccio. Come decidi quali componenti creare? Come modellali e le loro relazioni? Quali sono le interfacce? Qual è il livello di astrazione? Queste sono le decisioni importanti.

When I visualize this design I often imagine a hierarchical structure of objects and sub-objects, where each is only aware of its own interface and those of its members. As I understand, this last part is essential to achieving the sought after characteristics I mention above.

Falso.

In primo luogo, le gerarchie, sebbene piacevoli da immaginare nelle nostre teste, sono raramente così semplici. Questo è vero nel campo qualsiasi . Hai mai provato a studiare la classificazione degli organismi viventi? È un casino. Sfortunatamente, costruire ontologie corrette e semanticamente significative è un compito quasi impossibile per gli umani. Questo è stato dimostrato più e più volte.

Il problema si aggrava quando i membri delle ontologie stesse sono in continua evoluzione, come nel caso del software. Domani potresti dover aggiungere un nuovo componente o aggiornarne uno esistente. La tua gerarchia continuerà a essere vera?

In secondo luogo, stai combinando le due idee di eredità e sottotipo nella gerarchia una sola parola. L'ereditarietà è semplicemente un modo per scrivere programmi (ad esempio, salvare le sequenze di tasti); non ha un significato semantico. Sottotipizzazione è una relazione intrinseca esistente tra alcuni tipi (classi) in una lingua. I due concetti sono completamente separabili. Si può creare un sistema di ereditarietà in cui il sottoletto non diventa automaticamente un sottotipo della super classe Allo stesso modo, si può creare un linguaggio in cui alcuni tipi vengono automaticamente determinati come sottotipi di altri; questo è chiamato sottotipo strutturale .

Le gerarchie non sono essenziali per la programmazione modulare. Ciò che è importante per la programmazione modulare, è, beh, modules - componenti con interfacce ben definite (l'interfaccia è essa stessa una forma di tipo). Non c'è bisogno di gerarchia tra i moduli, e questo è generalmente l'approccio migliore per i piccoli progetti. Quando i progetti diventano più grandi, probabilmente hai bisogno di una qualche forma di riutilizzo; il termine formale per questo è polimorfismo . La sottotipizzazione non è che una forma di polimorfismo; Il polimorfismo parametrico è un approccio alternativo (i due possono ovviamente essere usati insieme).

Il tuo esempio

Esaminiamo il tuo esempio specifico, che dimostra in modo appropriato alcune delle carenze dell'ereditarietà. Molti non prenderebbero in considerazione la scrittura di modelli HTML per la programmazione vera, ma non ho intenzione di discutere le definizioni; è significativamente diverso dalla scrittura del codice Java, ma entrambi condividono la debolezza dell'ereditarietà.

In realtà ho esperienza pratica in questo particolare dominio. Nella mia azienda utilizziamo anche un sistema di template non-to-be-named che consente l'estensione basata su blocchi. Anche se sono principalmente uno sviluppatore back-end, ho incontrato il problema esatto che hai menzionato numerose volte quando lavoravo su funzionalità front-end. Il nostro codice è disseminato di blocchi di estensione che esistono solo per essere utilizzati da una sottoclasse specifica e non hanno senso per chiunque legga il codice. C'è solo una soluzione pulita che sono riuscito a trovare: non usare l'ereditarietà.

Se il tuo sito è piccolo, onestamente non hai bisogno di alcuna forma di riutilizzo o astrazione. Basta scrivere l'HTML "nel raw". In definitiva, ti farà risparmiare più tempo rispetto al wrestling con una gerarchia di eredità complessa.

Se il tuo sito è grande, i componenti riutilizzabili sono una soluzione alternativa che preferisco. Vuoi essere in grado di separare una pagina web in blocchi che possono essere mescolati e abbinati. Un modello non eredita da un altro modello; le pagine sono tutte costituite da un insieme di blocchi che possono o non possono essere condivisi tra le pagine. Questo è ciò che i modelli di chiusura fanno per quanto posso ricordare (è passato un po 'di tempo da quando ho lavorato con loro, ma hanno funzionato molto meglio del sistema attuale con cui sto lavorando).

Continua a imparare

Un'altra cosa prima che io finisca: leggi tutto quello che puoi. Non prendere la mia risposta o la risposta di qualcun altro a questa domanda come scrittura. Impara e continua ad imparare. Scopri nuovi linguaggi di programmazione, leggi ciò che altri hanno scritto, studia i libri di testo sulla progettazione linguistica. C'è sempre più da sapere e il design delle lingue è in continua evoluzione.

    
risposta data 27.07.2016 - 00:14
fonte
0

È impossibile progettare componenti per supportare tutte le situazioni impreviste. L'aggiunta del pulsante è esattamente quella. La prossima volta potrebbe essere una casella di ricerca e un pulsante, quindi non si sa mai.

L'approccio migliore consiste nell'usare l'approccio più semplice senza complicare le cose, basta aggiungere il titolo personalizzabile (supponendo che sia quello che vuoi in questo momento).

Ma se un pulsante dovesse mai essere necessario, potresti cambiare (non sono sicuro di come funzioni JSF ma ... spero che qualcosa del genere sia possibile)

<body>
    <div class="title">
        <insert component="ButtonComponent" default="TitleComponent"></insert>
    </div>
</body>

Quindi puoi introdurre un componente come titolo, dove può essere cambiato da una pagina all'altra. Ma se al momento non è necessario, non è necessario aggiungerlo e complicare il codice perché potrebbe non essere mai necessario.

    
risposta data 27.07.2016 - 02:34
fonte

Leggi altre domande sui tag