Come sviluppatore di strumenti / automazione, posso utilizzare meglio OOP?

3

Il mio tempo come sviluppatore (~ 8 anni) è stato speso nella creazione di tooling / automazione di un tipo o dell'altro. Gli strumenti che sviluppo di solito si interfacciano con una o più API. Queste API possono essere Win32, WMI, VMWare, un'applicazione di help desk, LDAP, ottieni l'immagine. Le app che sviluppo potrebbero essere solo per recuperare dati e archiviare / segnalare. Potrebbe essere il provisioning di gruppi di VM per creare live come ambienti fittizi, aggiornare un trouble ticket ecc.

Ho sviluppato in .Net e attualmente sto leggendo gli schemi di progettazione e sto cercando di pensare a come migliorare le mie capacità per utilizzare meglio e aumentare la mia comprensione di OOP. Per esempio, non ho mai usato un'interfaccia di mio interesse nella rabbia (che probabilmente non è una buona cosa), perché onestamente non riesco a identificare dove usare uno sarebbe utile in seguito quando modificherò il mio codice. Le mie classi sono in genere molto specifiche e non creo classi simili con proprietà / metodi simili che potrebbero utilizzare un'interfaccia comune (come forse una concessionaria di auto o un'applicazione di negozio potrebbe).

In genere utilizzo un approccio a più livelli per le mie app, con un livello di presentazione, un livello di business logic / manager che si interfaccia con i layer che effettuano chiamate all'API con cui sto lavorando. Le mie entità aziendali sono sempre solo oggetti container privi di metodo, che popolano con dati e passano avanti e indietro tra il mio livello di interfaccia API utilizzando metodi statici per proxy / convalida tra front e back end.

Il mio codice per natura del mio lavoro, ha pochi componenti comuni, almeno da quello che vedo. Quindi sto lottando per vedere come posso utilizzare meglio il design OOP e forse i modelli riutilizzabili.

Ho ragione ad essere preoccupato che potrei essere più intelligente su come lavoro, o è quello che sto facendo ora giusto per il mio lavoro? Oppure, mi manca qualcosa di fondamentale in OOP?

EDIT: Ecco un codice di base per mostrare come funzionano i miei layer mgr e api. Uso le classi statiche in quanto non mantengono alcun dato, ma facilitano lo spostamento tra i livelli.

public static class MgrClass
{
    public static bool PowerOnVM(string VMName)
    {
        // Perform logic to validate or apply biz logic
        // call APIClass to do the work
        return APIClass.PowerOnVM(VMName);
    }
}

public static class APIClass
{
    public static bool PowerOnVM(string VMName)
    {
        // Calls to 3rd party API to power on a virtual machine
        // returns true or false if was successful for example
    }
}
    
posta Tom Pickles 04.04.2012 - 21:18
fonte

4 risposte

2

Sembra che manchi molto. Gli schemi di sviluppo sono in circolazione da molto tempo e aiutano davvero con OOP. Suggerirei di leggere su questi modelli.

Per prima cosa dai un'occhiata a SOLID - link ) Esistono 5 modelli di sviluppo di base.

Per quanto riguarda le interfacce, sono davvero utili. L'interfaccia definisce i metodi disponibili e la classe concreta fornisce l'implementazione. Se si utilizzano interfacce, è possibile scambiare facilmente le classi per fornire funzionalità diverse (senza dover modificare il resto dell'applicazione). Un esempio di questo sarebbe il livello di accesso ai dati. Immagina se sviluppi la tua applicazione che usa LINQ in SQL. Qualche tempo dopo, il requisito è di cambiare il fornitore di dati in qualcos'altro. Ora, se fosse in esecuzione un'interfaccia con il modello di comando correttamente implementato, sarebbe molto semplice. Dovresti solo creare un nuovo livello di accesso ai dati, implementare l'interfaccia e il gioco è fatto.

Vale la pena leggere gli schemi di progettazione e tutte le funzionalità fornite da OOP.

Spero che ti aiuti.

Aggiorna

In base all'esempio, APIClass segue già un modello di responsabilità singola.

Il modo in cui potresti implementare l'interfaccia sarebbe:

public interface IVMManager
{
    bool PowerOnVM(string VMName);
    bool PowerOffVM(string VMName);
}

public class MgrClass 
{ 
    private IVMManager _vmManager;

    public MgrClass(IVMManager vmManager)
    {
        _vmManager = vmManager;
    }

    public bool PowerOnVM(string VMName) 
    { 
        // Perform logic to validate or apply biz logic 
        // call APIClass to do the work 
        return _vmManager.PowerOnVM(VMName); 
    } 
} 

public class APIClass : IVMManager
{    
    public bool PowerOnVM(string VMName)    
    {
        //IMPLEMENTATION
    }    
}    

RICORDATI: i metodi statici non possono essere esposti tramite l'interfaccia!

Questo esempio segue anche lo schema di comando. VM Manager è facilmente sostituibile con diverse implementazioni. Puoi anche testare questa classe con l'unità.

Spero di darti un'idea di come utilizzare i modelli di progettazione e di quanto sia potente OOP.

    
risposta data 04.04.2012 - 21:40
fonte
2

Ti consiglio di dare un'occhiata a SOLID (ecco un link) e da quelli iniziano con la separazione delle interfacce, il principio dell'iniezione delle dipendenze e il principio della responsabilità unica. Stanno tutti bene, ma posso immediatamente vedere che IS e DI potrebbero aiutarti.

Dopodiché dai un'occhiata ai test unitari e allo sviluppo basato sui test. Quando guardi TDD (Test Driven Development) ricorda che c'è anche TAD (After invece di driven). Significa solo che codifichi come hai sempre fatto e scrivi i test in seguito. Perderai i benefici di TDD, ma ti aiuta ancora a iniziare a pensare in termini di risultati e unità.

Quando guardi i test inizierai a vedere il riferimento al mocking. Mocking significa prendere un po 'di codice che vuoi testare che dipende da bit di codice che non vuoi testare e deridere (sostituendo con un falso funzionale) i bit che non vuoi testare.

Ci sono poi molti modelli che sono utili, e quasi sicuramente ne usi già molti. Dai un'occhiata al modello di strategia. È carino.

Infine guarda i modelli anti. Potrebbe essere semplicemente interessante avere l'idea che, proprio come ci sono comunemente buoni modelli di riuso del codice, ci sono anche quelli cattivi in cui non dovresti cadere.

Questo non dovrebbe essere un tutorial completo, ma ti spinge nella direzione giusta per iniziare a vedere i benefici da solo. Penso che.

    
risposta data 04.04.2012 - 21:40
fonte
1

Se non utilizzi mai le interfacce e utilizzi un approccio a più livelli, sembra abbastanza probabile che potresti perdere un'opportunità di disaccoppiamento e / o riutilizzo, ma è davvero impossibile dirlo senza vedere il codice.

Una cosa che potrei considerare è chiedersi se scrivi o meno test automatici (test unitari). Le interfacce sono spesso piuttosto utili a questo e tendono ad emergere in modo naturale quando si cercano modi per isolare le unità testabili. Se non sei un test unitario, ti manchi non solo una parte potenziale di OOP, ma una parte fondamentale della scrittura di un buon software affidabile. Quindi, se non lo fai, ti suggerirei di provarlo, e vedere se qualche uso dell'interfaccia (e forse anche l'uso del modello di progettazione) non emerge "organicamente" come lo fai tu.

    
risposta data 04.04.2012 - 21:23
fonte
1

Il punto chiave di OOP che spesso si perde nella confusione acronimo / pattern / kool-aid è che stai pensando in termini di oggetti che governano i domini dei problemi che interagiscono tra loro piuttosto che una pila di metodi (o uno- classi di metodi senza altre proprietà) che eseguono solo i dati attraverso una serie di cerchi.

Ci sono davvero solo due cose su cui mi concentro quando penso a come scrivere classi / costruttori.

incapsulamento

Quando i dati sono essenzialmente solo consumati e rielaborati attraverso 20 chiamate di metodo in una lunga catena di ritorno / param che vivono in luoghi diversi, quanto è diverso dal fatto di avere una variabile globale su cui agiscono tutti? Modificare la struttura di questi dati significa probabilmente dover modificare tutti i 20 metodi ed eseguire il debug di who-dun-its richiederà comunque di seguire una traccia completa per arrivare all'origine di un problema poiché non c'è modo di sapere quale angolo di un l'app stava toccando quei dati quando si è rotta.

Se i dati sono presenti in una classe, entrano solo in un dato sistema attraverso quella classe. Devi solo convalidarlo, impacchetterlo e canonizzarlo una volta in quel punto finché non lo sposti definitivamente su qualche altro oggetto come una fase importante di un processo (ad esempio, db layer per gestire la classe di gestione o la classe di gestione dei servizi sul client).

Ora può sembrare che io stia sostenendo classi di gigantor che fanno tutto sotto il sole. Affatto. La cosa fondamentale per avere un punto di accesso singolo non è avere classi enormi (anche se direi che SOLID ha portato gli sviluppatori a pensare che classi troppo piccole siano più appropriate di quanto non lo siano spesso nei codebase in cui ho lavorato). Ma piuttosto stratificare per compositing secondo necessità. Basta fare in modo che il punto di ingresso ricopra la responsabilità di una classe di livello superiore, quindi qualsiasi cosa venga utilizzata al suo interno tramite compositing / classi interne non è necessario.

Scrittura su un'interfaccia

No, non è la cosa che rimandi ad una definizione di classe per far valere un contratto in C # / Java. Intendo l'effettivo insieme di metodi che esponi come API. Più scrivi le tue classi / oggetti come se avessi un ruolo da riempire fornendo un insieme di metodi utili che danno una granularità sufficiente senza farti rifare nessuno dei dettagli inutili, meno sarai in grado di scovare i dati e creare inflessibilità e dipendenze inutili. E meno sarai tentato di mettere test e contratti su assolutamente tutto nella tua base di codice, perché hai creato un casino dalle cose creando un inutile nido di dipendenze.

La cosa fondamentale è smettere di pensare in termini di serie di passaggi per passare dal punto A al punto B a ... e invece pensare a chi deve essere in grado di fare cosa, stabilire quelle classi e metodi e poi riempire negli spazi vuoti e farli lavorare tra loro.

Le vittorie che dovresti ottenere

  • Più facile da leggere / comprendere / eseguire il debug: ad un livello più alto dovresti vedere alcuni oggetti che interagiscono. E poi vedere maggiori dettagli mentre scendi. Attraverso questo, dovrebbe essere più facile restringere quali componenti di un'app sono responsabili di un problema prima ancora di impostare il primo punto di interruzione. Se in genere esegui sempre il debug trovando il trigger per qualcosa e tracciando l'intero processo senza nemmeno provare a leggere il codice come un essere umano per primo, probabilmente non stai utilizzando un OOD molto buono.
  • Più facile da modificare: incapsulare / progettare bene riduce le dipendenze. Finché un'interfaccia di una determinata classe / oggetto fa quello che ci si aspetta che funzioni, non devi mai preoccuparti di come le altre modifiche apportate all'interno influenzeranno il resto di un'app.
  • Più facile da riutilizzare: classi ben progettate dovrebbero semplificare lo spostamento di ampie porzioni di funzionalità correlate in altre codebase con un minimo di modifiche.
risposta data 21.05.2013 - 17:35
fonte

Leggi altre domande sui tag