OOP sta diventando più facile o più difficile? [chiuso]


36

Quando i concetti della programmazione orientata agli oggetti sono stati introdotti ai programmatori anni fa, sembra interessante e la programmazione era più pulita. OOP era così

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);

Era più facile da capire con un nome auto-descrittivo.

Ma ora OOP, con pattern come Data Transfer Objects, Value Objects, Repository, Dependency Injection ecc., È diventato più complesso. Per ottenere quanto sopra potrebbe essere necessario creare diverse classi (ad es. Abstract, factory, DAO ecc.) E implementare diverse interfacce

Nota: non sono contrario alle migliori pratiche che semplificano la collaborazione, i test e l'integrazione


23
Creare una buona architettura software è sempre stato difficile e (molto probabilmente) lo sarà sempre.
johannes,

6
Rinominerei addItemper adde removeItemper remove. Perché è più facile da leggere. stock.add(item)o stock.remove(item). E più orientato verso OOP.
razpeitia,

1
OOP originale non assomigliava quasi a quello che hai mostrato. OOP non riguarda la sintassi , riguarda una sorta di astrazione resa popolare da Smalltalk. Questo non dimostra necessariamente che il tuo punto sia sbagliato, né la premessa è errata; piuttosto, è ancora più vero di quanto pensiate.
Konrad Rudolph,

1
stai confrontando mele e arance, secondo la tua logica, quindi la programmazione imperativa (ovvero loop e if-condition) è più semplice di tutte le cose che abbiamo oggi. La programmazione imperativa è i mattoni per le classi / OOP e le classi / OOP sono i mattoni per i modelli di progettazione. Le cose diventano più complesse man mano che progredisci perché stai risolvendo problemi più complessi.
Sdraiati Ryan l'

2
@LieRyan - Ho visto i problemi diventare complessi solo perché nessuno era in grado di risolverli con una semplice programmazione imperativa e li ha attaccati con schemi di progettazione sopra OOP oltre alla semplice soluzione imperativa che avrebbe dovuto essere implementata da sola.
mouviciel,

Risposte:


35

La stessa OOP non è cambiata molto dal suo inizio. Sono stati esplorati alcuni nuovi angoli, ma i principi fondamentali sono sempre gli stessi. Semmai, le conoscenze collettive raccolte nel corso degli anni rendono la vita del programmatore più semplice che difficile. I modelli di progettazione non sono un ostacolo; forniscono una cassetta degli attrezzi di soluzioni a problemi standard, distillati da anni e anni di esperienza.

Quindi perché percepisci OOP oggi come più complesso di quando hai iniziato a usarlo?

Uno dei motivi potrebbe essere che il codice a cui ti stai esponendo diventa più complesso, non perché OOP è diventato più complesso, ma perché sei avanzato sulla scala di apprendimento e leggi basi di codice più grandi e complesse.

Un altro motivo potrebbe essere che mentre il paradigma della complessità non è cambiato, le dimensioni e la complessità di un progetto software medio potrebbero benissimo avere. Con la potenza di elaborazione disponibile su cellulari di livello cliente che sarebbe stato il sogno di uno sviluppatore su un server meno di due decenni fa, il pubblico in generale si aspettava che le GUI animate slick fossero anche l'app a basso costo più economica e che i PC desktop entry-level fossero più potenti rispetto a un "supercomputer" degli anni '80, è naturale che la barra sia stata alzata fin dai primi giorni di Smalltalk e C ++.

E poi c'è il fatto che nelle applicazioni moderne, la concorrenza e il parallelismo sono la norma piuttosto che l'eccezione, e le applicazioni hanno spesso bisogno di comunicare tra macchine diverse, producendo e analizzando un intero zoo di protocolli. Sebbene OOP sia ottimo come paradigma organizzativo, ha i suoi limiti, proprio come qualsiasi altro paradigma: ad esempio, non fornisce molta astrazione per la concorrenza (la maggior parte delle implementazioni sono più o meno un ripensamento o esternalizzate interamente alle librerie) e non è l'approccio migliore per la creazione di parser e la trasformazione di dati. La programmazione moderna si imbatte spesso nei limiti del paradigma OOP e i modelli di progettazione non possono che portarvi così lontano. (Personalmente, Considero il fatto che abbiamo bisogno di schemi di progettazione un segno di questo: se il paradigma fornisse queste soluzioni immediatamente, sarebbe più espressivo per questi problemi e le soluzioni standard sarebbero ovvie. Non esiste un modello di progettazione per descrivere l'ereditarietà del metodo, poiché è una caratteristica fondamentale di OOP; ma esiste un modello di fabbrica, perché OOP non fornisce un modo naturale ovvio di costruire oggetti polimorficamente e in modo trasparente.)

Per questo motivo, i più moderni linguaggi OOP incorporano funzionalità di altri paradigmi, che li rende più espressivi e più potenti, ma anche più complessi. C # è il primo esempio per questo: ha ovvie radici OOP, ma caratteristiche come delegati, eventi, inferenza di tipo, tipi di dati varianti, attributi, funzioni anonime, espressioni lambda, generici, ecc., Provengono da altri paradigmi, in particolare la programmazione funzionale .


Quindi i modelli di progettazione hanno aggiunto le complessità. Significa che i modelli di progettazione non sono necessariamente OOP ma aggiunti per migliorare OOP.
Tunmise Fasipe,

@tunmisefasipe: Non del tutto. I modelli di progettazione sono solo soluzioni comprovate a problemi standard; non sono un'aggiunta a OOP, ma una conseguenza. La complessità era già lì; i modelli di progettazione forniscono solo strategie per libri di cucina per affrontarlo.
tdammers,

17

No, sta diventando più ingegnerizzato. E hai ragione: nella chat SO C ++ scherziamo spesso sul AbstractSingletonFactoryProxyBeanBridgeAdapterManagers che vediamo nel codice Java.

Ma un buon codice non mostra questa proprietà. Nel buon codice, puoi ancora dire

std::stack<int> s;
s.push(5);
s.pop();

4
Non chiaro dal tuo post, ma penso che l'ingegnerizzazione eccessiva sia evidente sia nel codice Java che in C ++. Non è una proprietà di nessuno dei due linguaggi di per sé, ma della pratica dei programmatori ... Entrambi i linguaggi consentono di scrivere un buon codice, sebbene nessuno dei due (IMO) sia particolarmente adatto a questo :) I fotogrammi in Java fanno schifo, purtroppo.
Andres F.

12
Parlando di ingegneria eccessiva, questa discussione è obbligatoria: discuss.joelonsoftware.com/default.asp?joel.3.219431
Sicuro il

3
@AndresF. vero, ma non sembra di avere così tanto di esso nel codice C ++, mentre si fa in Java e .NET: basta guardare i MVVMVMMD modello di progettazione msdn.microsoft.com/en-us/magazine/hh965661.aspx come un esempio di come si prende il 'codice semplice' e si schiaffeggia un modello di disegno per renderlo 'più semplice' e quindi si schiaffeggia un altro modello di disegno sul modello di disegno perché il modello originale non era semplice come pubblicizzato. L'ingegneria eccessiva sta diventando sempre più banale.
gbjbaanb,

5
Discuterei con il "divenire". L'ingegneria eccessiva è vecchia quanto l'ingegneria.
Gort the Robot il

4
@AndresF. Siamo particolarmente anti-Java nella chat ma è vero che Java, più che C ++ , incoraggia un eccesso di ingegneria perché lo rende più economico (GC) e le popolari librerie Java aziendali hanno reso popolare questo stile, come hai notato te stesso.
Konrad Rudolph,

10

Direi che i problemi di "complessità" che lei menziona non hanno nulla a che fare con OOP. Ha più a che fare con la separazione delle preoccupazioni.

Molti anni fa ho lavorato su un sistema, in cui la classe di dominio aveva la responsabilità di caricarsi dal database, ad es

var userId = Request.QueryString["UserID"].ToInt();
var user = new User(userId);
user.Name = ...;
...
user.Save();

Questo è un codice molto chiaro. Nessun problema nel capirlo. Il problema sarebbe tuttavia nell'unità di test del codice. Vale a dire, come testerei l'unità della Userclasse senza doverne caricare una dal database? E come testerei questa richiesta di gestione del codice Web senza avere accesso al database? Semplicemente non è possibile.

Ecco perché abbiamo un modello come un repository, per separare la responsabilità di gestire la logica di dominio da un utente dalla funzionalità di caricare e salvare effettivamente uno in un archivio dati. Il CIO aiuta a ridurre l'accoppiamento, rendendo anche il codice più testabile, ecc.

Quindi, se torniamo all'esempio che scrivi, cosa faresti con lo stock dopo averlo creato? Salvalo nel database

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);
this.StockRepository.Add(stock);

Quello rosso! Non c'è movimento nella progressione di OOP che suggerisce che dovrebbe essere più difficile. Sfortunatamente, se scegli di utilizzare un mapper OR per il tuo codice di accesso ai dati, potresti riscontrare il problema che il mapper OR sta ponendo delle restrizioni su come scrivere il tuo sistema. Ma questa è un'altra questione.

Se non conosci questi schemi, potresti dover imparare un nuovo stile di programmazione. Ma questo stile di programmazione non è affatto più difficile della programmazione OOP della vecchia scuola.


Conosci lo sforzo che devi compiere per configurare il tuo repository. Anche se dopo averlo impostato, diventa riutilizzabile.
Tunmise Fasipe,

forse il problema è con i test unitari, se avessimo strumenti migliori per testare il tutto (come devi comunque) invece dei piccoli pezzi, avremmo sistemi con meno bug?
gbjbaanb,

2
@gbjbaanb: ce l'abbiamo già, si chiama test di integrazione / funzionale. I test unitari hanno uno scopo diverso ma ugualmente necessario
Kevin,

@gbjbaanb - Disponiamo già di ottimi strumenti per i test a livello di sistema / accettazione, ad esempio Cucumber sulla piattaforma Rails. Ma i team che sono davvero bravi e scrivono pochissimi bug, ma forniscono anche velocemente, scrivono molti test unitari e solo pochi test a livello di sistema. Vedi il "Triangolo di prova", ad esempio qui jonkruger.com/blog/2010/02/08/the-automated-testing-triangle
Pete l'

4

Né. I nostri problemi non sono realmente cambiati; la barra per il codice accettabile è stata alzata.

Per ottenere quanto sopra potrebbe essere necessario creare diverse classi (ad es. Abstract, factory, DAO ecc.) E implementare diverse interfacce

Non devi farlo. Ma se non lo fai allora sorgono problemi; problemi che ci sono sempre stati. Ora, tuttavia, i programmatori hanno abbastanza esperienza nel farlo per identificare quei problemi e fornire meccanismi per alleviarli (se necessario). Impariamo di più su questi e troviamo soluzioni migliori (vedi ad esempio le opinioni dei programmatori sul singleton).

Ma devi anche capire che l'introduzione di programmatori a OO (o qualsiasi altra cosa) tenderà a sorvolare le circostanze eccezionali. È semplicemente più facile spiegare il percorso felice e preoccuparsi per il resto una volta che i principianti lo hanno abbandonato. Non c'è proiettile d'argento; quindi sì, suppongo che le cose sembreranno sempre più difficili quando quell'illusione idilliaca viene spezzata ...


3

Gli esempi di "introduzione a OO" sono molto più semplici di un'applicazione del mondo reale. Hai solo bisogno di una classe per ottenere quanto sopra. Il problema è che non fa molto. Alcuni modelli di progettazione cercano di avvicinarsi (come ActiveRecord). Ma alla fine, qualsiasi esempio non banale avrà più di una classe; va bene.


Si noti inoltre che i framework si accumulano nel tempo. Quindi sì, la programmazione richiede maggiori conoscenze. Significa anche che si può fare di più in meno tempo.
Jeanne Boyarsky,

3

I linguaggi di programmazione che utilizzano OO oggi stanno cercando di soddisfare requisiti complessi e ambienti che continuano a cambiare. OO consente ai suoi utenti di nascondere una varietà di livelli di complessità (tra le altre caratteristiche) in modo che la codifica diventi più chiara e più facile da costruire e comprendere. Tuttavia, questa funzione non è sempre pronta all'uso. Nel tuo esempio, OO ti ha permesso di nascondermi alcuni dettagli fornendo un metodo per gestire gli elementi in una raccolta e potrebbe anche essere persistente usando il metodo "AddItem". Spendere sforzi per nascondere la complessità può risultare in un quadro facile da usare e riutilizzabile che semplifica la vita. Ad esempio, molte implementazioni ORM consentono di comunicare con i database senza che il programmatore scriva i dettagli SQL. Questo è davvero potente e lo rende più semplice per lo sviluppatore.

I modelli a cui ti riferisci sono proprio questo. Dovrebbero semplificarti la vita. Ma sta a te adottarli e adattarli. Il fatto che sia richiesto più lavoro è solo perché si ottengono più benefici. È come pagare di più per una Ferrari. Se vuoi gli extra, li paghi. Pertanto, se si decide di creare una soluzione di livello N scalabile che può essere eseguita su più server e database back-end diversi, ciò comporta un costo. Se la tua applicazione non richiede questa complessità, ignora i pezzi extra e torna alla soluzione più semplice che soddisfa le tue esigenze (KISS & YAGNI).

Quindi, per concludere, non penso che OOP come concetto stesso stia diventando più complesso, noi utenti di OOP abbiamo la scelta di usarlo in modi diversi, e questa è una buona cosa.


Punti chiari. Conosco YAGNI. Che cos'è KISS?
Tunmise Fasipe,

2
@tunmisefasipe, KISS è un nome breve per un principio di design. Le parole originali sono "Keep It Simple (Stupid)" (ref: en.wikipedia.org/wiki/KISS_principle ) ma un frase più educato può essere "Keep It So Simple".
NoChance,

3
@tunmisefasipe - KISS = Keep It Simple, Stupid. Una frase che ripeto a me stesso OVER, e OVER, e OVER, e non sembra ancora affondare.
Michael Kohne

@MichaelKohne, lo facciamo tutti! Immagino che sia un'arte riuscire a semplificare le cose. E = M C C dice molto in una forma molto concisa!
NoChance,

3

Risposta breve : Sì, perché hai a che fare con problemi più difficili.

Risposta lunga (fortemente distorta) : per me i modelli di progettazione indicano solitamente che alcuni paradigmi hanno problemi in una determinata area. I modelli OOP affrontano i problemi di OOP (a livello inferiore i modelli Java affrontano i problemi di Java), i modelli FP affrontano i problemi di FP ecc.

Durante la programmazione potresti avere diverse priorità. Potresti voler avere un programma corretto, potresti avere un time-to-market più breve, un programma più veloce possibile, manutenibilità a lungo termine o manutenibilità istantanea da parte di un nuovo assunto. A seconda della boscosità in cui ci si trova, si avrà una grande differenza: se si sta programmando un controller di una centrale elettrica, si desidera farlo correttamente la prima volta e non correggere errori ogni tanto ("La fusione si verifica ogni volta che si preme Ctrl+Alt+Del?"). Se ti trovi in ​​HPC, la logica può essere relativamente semplice ma vuoi eseguirla il più velocemente possibile, ecc. Ecc. Inoltre alcuni paradigmi si adattano meglio a determinati problemi (ad esempio programmazione AI e logica, dati e database relazionali).

OOP è in qualche modo "troppo buono" in casi semplici ed è una storia "modellistica dal vivo reale". Per esempio nel primo libro su OOP ho letto c'erano le classi Person, Employeee Managercon is-arapporto. Fin qui tutto bene, ma cosa succede se il dipendente viene promosso a manager?

D'altra parte, altri paradigmi hanno lezioni per la prima volta più difficili - ad esempio FP con variabili immutabili (la cosa divertente è che le persone che hanno avuto esperienza con la programmazione spesso trovano più difficile da imparare rispetto a coloro per i quali questa è la prima lingua) - comunque alla fine lo sono non più difficile di OOP. Testare le funzioni pure è banale e in Haskell / Scala / ... hai strumenti che generano test per te.

PS. Sì, la risposta è distorta nei confronti di OOP e ammetto che per certi versi è "in reazione" a OOP. OOP ha i suoi usi, ma non è l'unica, ultima soluzione secondo me.

PPS. Sì, utilizza i modelli di progettazione e semplifica notevolmente la programmazione OOP.

PPPS. Ho usato OOP come sinonimo di programmazione imperativa OOP.


2

Penso che sia più un caso che documenti ed esempi diventino più realistici.

I primi libri di OOP (in particolare i primi libri di Java) presentavano una visione assurdamente semplificata della programmazione delle applicazioni. Gli esempi "Addebitare un conto bancario con un programma Java a 10 righe" sono sempre stati particolarmente fastidiosi in quanto ho visto esempi di vita reale di questo semplice compito in esecuzione su 6000 righe di codice COBOL (e il tentativo di sostituzione Java in esecuzione su 3500 righe prima che fosse abbandonato come impossibile!).

Per fortuna i libri di OO ora tendono a riconoscere le complessità della vita reale e forniscono esempi utili su come affrontarli.

Ma se vuoi vedere come eseguire un conto bancario in sole 15 righe di codice programmazione funzionale è il tuo uomo

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.