Il modo più semplice per scrivere software procedurale logico in un linguaggio OO

9

Sono un ingegnere elettronico e non so cosa diavolo sto facendo. Si prega di salvare i futuri manutentori del mio codice.

Recentemente ho lavorato su un numero di programmi più piccoli (in C #) la cui funzionalità è logicamente "procedurale". Ad esempio, uno di essi è un programma che raccoglie informazioni da diversi database, utilizza tali informazioni per generare una sorta di pagina di riepilogo, la stampa e quindi esce.

La logica richiesta per tutto questo è di circa 2000 linee. Certamente non voglio aggiungere tutto ciò in un singolo main() e poi "ripulirlo" con #region s come hanno fatto alcuni sviluppatori precedenti (shudder).

Ecco alcune cose che ho già provato senza troppe soddisfazioni:

Crea utilità statiche per ogni bit di funzionalità generale, ad es. un DatabaseInfoGetter, SummaryPageGenerator e PrintUtility. Rendere la funzione principale simile a:

int main()
{
    var thisThing = DatabaseInfoGetter.GetThis();
    var thatThing = DatabaseInfoGetter.GetThat();
    var summary = SummaryPageGenerator.GeneratePage(thisThing, thatThing);

    PrintUtility.Print(summary);
}

Per un programma sono persino andato con le interfacce

int main()
{
    /* pardon the psuedocode */

    List<Function> toDoList = new List<Function>();
    toDoList.Add(new DatabaseInfoGetter(serverUrl));
    toDoList.Add(new SummaryPageGenerator());
    toDoList.Add(new PrintUtility());

    foreach (Function f in toDoList)
        f.Do();
}

Nessuna di queste sembra giusta. Man mano che il codice si allunga, entrambi questi approcci cominciano a diventare brutti.

Qual è un buon modo per strutturare cose del genere?

    
posta Lombard 15.06.2015 - 23:22
fonte

3 risposte

15

Dato che non sei un programmatore professionista, ti consiglio di attenermi alla semplicità. Sarà molto più facile per il programmatore prendere il tuo codice procedurale modularizzato e renderlo OO più tardi, piuttosto che per loro fissare un programma OO scritto male. Se non sei esperto, è possibile creare programmi OO che possono trasformarsi in un disastro empio che non ti aiuterà né a chi ti verrà dopo.

Penso che il tuo primo istinto, il codice "questa cosa-quella cosa" nel primo esempio sia la traccia giusta. È chiaro e ovvio cosa vuoi fare. Non preoccuparti troppo dell'efficienza del codice, la chiarezza è molto più importante.

Se un segmento di codice è troppo lungo, suddividilo in blocchi di dimensioni ridotte, ognuno con la propria funzione. Se è troppo corto, considera di utilizzare meno moduli e di mettere più in fila.

---- Postscript: OO Design Trap

Lavorare con successo con la programmazione OO può essere complicato. Esistono anche alcune persone che considerano il intero modello imperfetto. C'è un ottimo libro che ho usato quando ho iniziato a studiare la programmazione OO chiamato Thinking in Java (ora alla sua 4a edizione) . Lo stesso autore ha un libro corrispondente per C ++. C'è in realtà un'altra domanda sui programmatori che si occupano di problemi comuni nella programmazione orientata agli oggetti .

Alcune insidie sono sofisticate, ma ci sono molti modi per creare problemi in modi molto semplici. Ad esempio, un paio di anni fa c'era uno stagista nella mia azienda che ha scritto la prima versione di alcuni software che ho ereditato e ha creato interfacce per tutto ciò che potrebbe un giorno avere implementazioni multiple. Naturalmente, nel 98% dei casi c'era solo una singola implementazione, quindi il codice è stato caricato con interfacce inutilizzate che hanno reso il debug molto fastidioso perché non è possibile tornare indietro attraverso una chiamata all'interfaccia, quindi si finisce per dover fare una ricerca del testo per l'implementazione (anche se ora uso IntelliJ era una funzionalità "Mostra tutte le implementazioni", ma nel giorno in cui non avevo questo). La regola qui è la stessa della programmazione procedurale: sempre una cosa hardcode. Solo quando hai due o più cose, crea un'astrazione.

Un simile errore di progettazione si può trovare nell'API Java Swing. Utilizzano un modello di sottoscrizione di pubblicazione per il sistema di menu Swing. Ciò rende la creazione e il debug di menu in Swing un incubo completo. L'ironia è che è completamente inutile. Non c'è praticamente mai una situazione in cui più funzioni avrebbero bisogno di "iscriversi" a un clic del menu. Inoltre, pubblicare-iscriversi era un completo errore di attivazione perché normalmente un sistema di menu è sempre in uso. Non è come se le funzioni fossero abbonate e poi cancellate in modo casuale. Il fatto che gli sviluppatori "professionisti" di Sun abbiano commesso uno svarione del genere dimostra semplicemente quanto sia facile per i professionisti fare degli sconvolgenti scoppi nel design OO.

Sono uno sviluppatore molto esperto con decenni di esperienza nella programmazione OO, ma anche io sarei il primo ad ammettere che ci sono tonnellate che non conosco e anche ora sono molto cauto nell'usare un sacco di OO. Ascoltavo le lunghe lezioni di un collega che era un fanatico della OO su come fare progetti particolari. Sapeva davvero cosa stava facendo, ma in tutta onestà ho avuto difficoltà a capire i suoi programmi perché avevano modelli di design così sofisticati.

    
risposta data 16.06.2015 - 00:41
fonte
1

Il primo approccio va bene. Nei linguaggi procedurali, come C, l'approccio standard è quello di dividere le funzionalità in spazi dei nomi - l'uso di classi statiche come DatabaseInfoGetter è praticamente la stessa cosa. Ovviamente questo approccio porta a un codice più semplice, più modulare e più leggibile / gestibile che a inserire tutto in un'unica classe, anche se tutto è suddiviso in metodi.

A proposito, cerca di limitare i metodi per eseguire il minor numero possibile di azioni. Alcuni programmatori preferiscono una piccola meno granularità, ma i metodi enormi sono sempre considerati dannosi.

Se sei ancora alle prese con la complessità, è molto probabile che tu debba abbattere ulteriormente il tuo programma. Crea più livelli nella gerarchia: forse DatabaseInfoGetter deve fare riferimento ad altre classi come ProductTableEntry o qualcosa del genere. Stai scrivendo codice procedurale, ma ricorda che stai utilizzando C # e OOP ti offre una serie di strumenti per ridurre la complessità, ad esempio:

int main() 
{
    var thisthat = Database.GetThisThat();
}

public class ThisThatClass
{
    public String This;
    public String That;
}

public static class Database 
{
    public ThisThatClass GetThisThat()
    {
        return new ThisThatClass 
        {
            This = GetThis(),
            That = GetThat()
        };
    }

    public static String GetThis() 
    { 
        //stuff
    }
    public static String GetThat() 
    { 
        //stuff
    }

}

Inoltre, fai attenzione con le classi statiche. Le classi di database sono buoni candidati ... purché di solito si abbia un database ... si ottiene l'idea.

In ultima analisi, se pensi in funzioni matematiche e C # non si adatta al tuo stile, prova qualcosa come Scala, Haskell, ecc. Anche loro sono fantastici.

    
risposta data 16.06.2015 - 03:23
fonte
-1

Sono a mio parere, dovresti cambiare il codice in modo che sia semplice, coerente e leggibile.

Ho scritto alcuni post di blog su questo argomento, e credimi sono semplici da capire: Che cos'è un buon codice

Semplice: proprio come un circuito stampato contiene pezzi diversi, ognuno con una responsabilità. Il codice dovrebbe essere diviso in parti più piccole e più semplici.

Consistente: usa i picchietti, uno standard per denominare elementi e cose. Ti piacciono gli strumenti che funzionano sempre allo stesso modo e vuoi sapere dove trovarli. È lo stesso con il codice.

Leggibile: non utilizzare gli acronimi a meno che non siano ampiamente utilizzati e conosciuti all'interno del dominio che il software ha come target (mattnz), preferiscono nomi pronunciabili chiari e facili da capire.

    
risposta data 03.07.2015 - 19:41
fonte

Leggi altre domande sui tag