Quali "best practice" popolari non sono sempre le migliori, e perché? [chiuso]


100

Le "migliori pratiche" sono ovunque nel nostro settore. Una ricerca di Google sulle "migliori pratiche di codifica" genera quasi 1,5 milioni di risultati. L'idea sembra portare conforto a molti; basta seguire le istruzioni e tutto andrà bene.

Quando leggo di una best practice - per esempio, ne ho appena letti diversi in Clean Code di recente - mi innervosisco. Questo significa che dovrei sempre usare questa pratica? Ci sono condizioni associate? Ci sono situazioni in cui potrebbe non essere una buona pratica? Come posso sapere con certezza fino a quando non avrò imparato di più sul problema?

Molte delle pratiche menzionate in Clean Code non mi andavano bene, ma onestamente non sono sicuro se ciò sia dovuto al fatto che sono potenzialmente cattive o se è solo il mio pregiudizio personale a parlare. So che molte persone di spicco nel settore tecnologico sembrano pensare che non ci siano buone pratiche , quindi almeno i miei fastidiosi dubbi mi mettono in buona compagnia.

Il numero di best practice di cui ho letto è semplicemente troppo numeroso per elencarlo qui o porre domande individuali, quindi vorrei formulare questa frase come una domanda generale:

Quali pratiche di codifica che sono comunemente etichettate come "migliori pratiche" possono essere non ottimali o addirittura dannose in determinate circostanze? Quali sono queste circostanze e perché rendono la pratica povera?

Preferirei conoscere esempi ed esperienze specifici.


8
Quali sono le pratiche con cui non sei d'accordo ?, solo curiosi.
Sergio Acosta,

Chiunque può scrivere un libro e non devo essere d'accordo, è semplice.
Giobbe

Una cosa che mi piace del libro "Code Complete" di Steve McConnell è che sostiene tutti i suoi consigli con prove concrete e ricerche. Solo dicendo
JW01

5
@Walter: è aperto da mesi, è decisamente costruttivo, perché chiuderlo?
Orbling

2
Visto come il mio nome viene menzionato qui, suppongo che dovrei entrare in chip: credo che le risposte qui siano preziose, ma la domanda potrebbe essere riformulata in qualcosa di definitivamente meno simile a un sondaggio senza invalidare nessuna delle risposte. Titolo di esempio: "Quali" best practice "popolari possono talvolta essere dannose e quando / perché?"
Aaronaught il

Risposte:


125

Penso che tu abbia colpito l'unghia sulla testa con questa affermazione

Odierei prendere le cose al valore nominale e non pensarci criticamente

Ignoro quasi tutte le migliori pratiche quando non viene fornita una spiegazione sul perché esiste

Raymond Chen lo mette meglio in questo articolo quando dice

Un buon consiglio viene fornito con una logica in modo da poter dire quando diventa un cattivo consiglio. Se non capisci perché qualcosa dovrebbe essere fatto, allora sei caduto nella trappola della programmazione di culto del carico e continuerai a farlo anche quando non è più necessario o addirittura diventa deleteria.


4
Citazione meravigliosa.
David Thornley,

Il prossimo paragrafo di quella citazione di Raymond Chen probabilmente descriverà la notazione ungherese! La maggior parte delle aziende che vedo usarlo senza una vera buona ragione che possono spiegare.
Craig,

3
Spero che le persone non lo considerino una scusa per non cercare quale sia il ragionamento alla base delle migliori pratiche. ;) Sfortunatamente, ho visto sviluppatori con questo atteggiamento.
Vetle,

3
La logica è buona. La ricerca è migliore
Jon Purdy,

7
Assolutamente vero, e ho detto lo stesso prima. Forse il primo standard in qualsiasi documento "Standard" dovrebbe essere: "Nell'interesse di condividere le conoscenze e fornire le informazioni necessarie per annullare gli standard in un secondo momento, tutti gli standard devono includere i motivi della loro esistenza".
Scott Whitlock,

95

Potrebbe anche buttarlo sul ring:

Premature optimization is the root of all evil.

No non lo è.

Il preventivo completo:

"Dovremmo dimenticare le piccole efficienze, diciamo circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali. Eppure non dovremmo rinunciare alle nostre opportunità in quel 3% critico".

Ciò significa che sfrutti miglioramenti specifici e strategici delle prestazioni durante tutto il processo di progettazione. Significa che si utilizzano strutture di dati e algoritmi coerenti con gli obiettivi di prestazione. Significa che sei a conoscenza di considerazioni di progettazione che influiscono sulle prestazioni. Ma significa anche che non si ottimizza frivolosamente quando lo si fa, si otterranno piccoli guadagni a spese della manutenibilità.

Le applicazioni devono essere ben progettate, in modo che non cadano alla fine quando si applica un piccolo carico su di esse e quindi si finisce per riscriverle. Il pericolo con la citazione abbreviata è che, troppo spesso, gli sviluppatori lo usano come una scusa per non pensare alle prestazioni fino alla fine, quando potrebbe essere troppo tardi per fare qualcosa al riguardo. È meglio ottenere buone prestazioni fin dall'inizio, a condizione che non ci si concentri sulle minuzie.

Supponiamo che tu stia creando un'applicazione in tempo reale su un sistema incorporato. Scegli Python come linguaggio di programmazione, perché "L'ottimizzazione prematura è la radice di tutti i mali". Ora non ho nulla contro Python, ma è un linguaggio interpretato. Se la potenza di elaborazione è limitata e una certa quantità di lavoro deve essere eseguita in tempo reale o quasi in tempo reale e si sceglie una lingua che richiede più potenza di elaborazione per il lavoro di quella che si possiede, si viene fregati in modo regale, perché si ora devo ricominciare con un linguaggio capace.


4
+1 per il forte No, non lo è.
Stephen,

21
Ma se hai già riconosciuto che una particolare ottimizzazione rientra in quel 3% critico, sei prematuro nell'ottimizzarla?
Giovanni,

7
@Robert: Allora qual è il punto di disaccordo con l'affermazione che "l'ottimizzazione prematura è la radice di tutti i mali"?
Giovanni,

8
Non è mai prematuro ottimizzare il design di alto livello e le decisioni tecniche come la scelta della lingua. Tuttavia, spesso è solo dopo aver completato per lo più un progetto che le sue inefficienze diventano parziali, motivo per cui Fred Brooks ha affermato che la maggior parte dei team scrive una versione da buttare, sia che lo vogliano o meno. Un altro argomento per la prototipazione.
Dominique McDonnell,

8
@Robert, la citazione di Knuth è stata ottimizzata prematuramente ...

94

Un ritorno per funzione / metodo.


7
Stavo per dirlo. Mi piacciono alcune dichiarazioni di ritorno anticipate.
Carson Myers,

4
Assolutamente! Le persone escogitano un flusso di programma piuttosto interessante per evitare una returndichiarazione anticipata . Strutture di controllo profondamente annidate o controlli continui. Questo può davvero gonfiare un metodo quando si if returnpotrebbe davvero semplificare questo problema.
snmcdonald,

4
Se hai bisogno di più ritorni in una funzione (a parte le protezioni) la tua funzione è probabilmente troppo lunga.
EricSchaefer,

18
Non ha senso avere una parola chiave return a meno che non sia stata progettata per apparire in più punti. Ritorna presto, ritorna spesso. Servirà solo per semplificare ulteriormente il codice. Se le persone riescono a capire come funzionano le dichiarazioni break / continue, perché lottano per il ritorno?
Evan Plaice,

7
Penso che questa sia una best practice molto obsoleta. Non penso che sia una buona pratica moderna.
Skilldrick,

87

Non reinventare la ruota è un dogma ampiamente mal utilizzato. La sua idea è che se esiste una soluzione adatta, usala invece di crearne una tua; oltre allo sforzo di risparmio, la soluzione esistente è probabilmente meglio implementata (senza errori, efficiente, testata) rispetto a quella che verrebbe inizialmente. Fin qui tutto bene.

Il problema è che raramente esiste una soluzione adatta al 100%. Potrebbe esistere una soluzione adatta all'80% e il suo utilizzo probabilmente va bene. Ma come circa il 60% adatto? 40%? Dove disegni la linea? Se non disegni la linea, potresti finire con l'incorporare una libreria gonfiata al tuo progetto perché stai usando il 10% delle sue funzionalità - solo perché vuoi evitare di "reinventare la ruota".

Se reinventi la ruota, otterrai esattamente ciò che desideri. Imparerai anche come realizzare le ruote. L'apprendimento facendo non dovrebbe essere sottovalutato. E alla fine, una ruota personalizzata potrebbe essere migliore della ruota generica standard.


3
Ho fatto succedere il contrario. Ho creato il mio componente ajax grid perché all'epoca non c'era nessuno che facesse quello che volevo, ma in seguito lo ho sostituito con le griglie Ext JS. Mi ha aiutato a fare fin dall'inizio il presupposto che il livello di visualizzazione sarebbe stato sostituito.
Joeri Sebrechts,

20
Concordato. Se nessuno avesse mai reinventato la ruota, avremmo tutti guidato le nostre auto con pneumatici di legno.
Apprendista Dr. Wily,

6
Mi sento sempre come il tuo esempio del 10% quando aggiungo Boost a un progetto C ++. Ho sempre bisogno di meno del 10%, direttamente, ma ovviamente le funzioni di cui ho bisogno importano altri moduli che importano altri moduli che ...
Roman Starkov,

3
+1: proprio questa settimana ho reinventato la ruota (ad esempio sostituendo il plug-in jquery gonfio ma popolare che abbiamo usato da qualcosa che si adatta alle nostre esigenze ma modulare) e ha portato a enormi miglioramenti delle prestazioni. Inoltre, ci sono persone il cui compito è letteralmente reinventare la ruota: ad esempio Michelin, fanno ricerca e sviluppo per migliorare le gomme.
Wildpeaks

2
@Dr. Astutamente, quelle ruote non furono reinventate, furono rifattorizzate!

78

"Unit Test Everything."

Ho sentito dire spesso che tutto il codice dovrebbe avere unit test, un punto su cui non sono d'accordo. Quando si dispone di un test per un metodo, qualsiasi modifica all'output o alla struttura di quel metodo deve essere effettuata due volte (una volta nel codice, una volta nel test).

Pertanto, i test unitari dovrebbero essere, a mio avviso, proporzionali alla stabilità strutturale del codice. Se sto scrivendo un sistema a strati dal basso verso l'alto, il mio livello di accesso ai dati avrà test del wazoo; il mio livello di logica aziendale sarà testato abbastanza bene, il mio livello di presentazione avrà alcuni test e le mie opinioni non avranno quasi nessun test.


7
Sospetto che "Unit Test Everything" sia diventato un cliché, come la citazione di "ottimizzazione prematura". In genere sono d'accordo con le tue proporzioni e ho visto molti esempi di sviluppatori che stanno compiendo sforzi monumentali per deridere un oggetto a livello di applicazione, sforzi che potrebbero essere spesi meglio facendo test di accettazione.
Robert Harvey,

36
Se una modifica alla struttura di un metodo provoca una modifica nei test, è possibile che il test sia errato. I test unitari non devono verificare l'implementazione, ma solo il risultato.
Adam Lear

7
@Anna Lear: penso che stesse parlando di modifiche progettuali / strutturali (refactoring). Dal momento che il design non è abbastanza maturo, quando trovi il modo migliore per farlo, potresti dover modificare molti test nel modo. Concordo sul fatto che quando sei un tester più abile potresti notare più facilmente dove il test sarebbe una cattiva idea (per questo motivo e altri) ma se il design non è davvero maturo, molto probabilmente avrai ancora alcuni test nel modo.
n1ckp,

13
Penso che questo sia anche il motivo per cui l'idea "prima prova" non funziona. Per fare i test prima devi avere il design giusto. Ma avere il design giusto richiede di provare le cose e vedere come funzionano in modo da poterle migliorare. Quindi non puoi davvero fare i test prima di avere il design, e per ottenere il design giusto devi codificare e vedere come funziona. A meno che tu non abbia un architetto davvero super, non vedo davvero come funzionerà quell'idea.
n1ckp,

13
@ n1ck TDD non è in realtà un esercizio di test tanto quanto è un esercizio di progettazione. L'idea è di far evolvere il tuo progetto attraverso i test (poiché ciò espone rapidamente un'API ragionevole per le tue cose) piuttosto che adattare i test a un design esistente (che potrebbe essere cattivo / insufficiente). Quindi no, non devi avere il design giusto per fare prima i test.
Adam Lear

57

Programmare sempre su interfacce.

A volte ci sarà una sola implementazione. Se ritardiamo il processo di estrazione di un'interfaccia fino al momento in cui ne vediamo la necessità, spesso scopriremo che non è necessario.


4
D'accordo, si programma a un'interfaccia quando è necessaria un'interfaccia (ovvero un'API stabile su cui lavorare).
Robert Harvey,

45
Nella mia lettura questa regola non riguarda le interfacce come costrutti di linguaggio. Significa che non dovresti fare ipotesi sul funzionamento interno di una classe quando chiami i suoi metodi e dovresti fare affidamento solo sui contratti API.
Zsolt Török,

2
Ok, ecco una domanda interessante: sono principalmente uno sviluppatore .NET, quindi per me le mie interfacce sembrano IBusinessManager o IServiceContract. Per me questo è estremamente facile da navigare (e generalmente mantengo le mie interfacce in un altro spazio dei nomi [o anche in un altro progetto]). Quando ho usato Java, in realtà ho trovato questo confuso (generalmente le implementazioni di interfaccia che ho visto sono suffissate con .impl - e le interfacce non hanno delineazione). Quindi potrebbe essere un problema di standard di codice? Ovviamente le interfacce in Java fanno sembrare il codice ingombra: a prima vista sembrano esattamente le stesse delle normali classi.
Watson,

5
@Watson: un costo è che ogni volta che premo F3 ('passa alla dichiarazione') su una chiamata del metodo in Eclipse, salto all'interfaccia, non alla sola implementazione. Devo quindi controllare-T, freccia giù, tornare per arrivare all'implementazione. Blocca anche alcuni refactoring automatici: ad esempio, non è possibile incorporare un metodo attraverso una definizione di interfaccia.
Tom Anderson,

4
@Tom: Bene signore, sarei felice di coinvolgerti in quella guerra, Eclipse contro Intellij - tuttavia ho un codice morale eccezionale che mi impedisce di entrare in scontri fisici con qualcuno che ha un evidente handicap. BOOM. Non sto dicendo che Eclipse sia un male, sto dicendo che se i poteri dell'Asse lo avessero usato per costruire o progettare le loro macchine da guerra, la Seconda Guerra Mondiale sarebbe ora conosciuta come "due giorni di kerfuffle". Scherzi a parte, ho scoperto che manca un po 'di smalto che ottengo negli IDE standardizzati (Intellij / VS + ReSharper). Mi sono ritrovato a combatterlo in più di un'occasione - che è una di troppo.
Watson,

46

Non usare nulla di open source (o non Microsoft per te sviluppatori .NET)

Se Microsoft non lo ha sviluppato, non lo usiamo qui. Vuoi usare ORM - EF, vuoi usare IOC - Unity, vuoi loggarti - blocco applicativo di registrazione aziendale. Esistono così tante biblioteche migliori, eppure sono sempre bloccato a ordinare dal menu in dollari del mondo di sviluppo. Lo giuro ogni volta che sento le migliori pratiche di Microsoft, penso alle "Linee guida nutrizionali di McDonald". Certo, probabilmente li vivrai se li segui, ma sarai anche malnutrito e sovrappeso.

  • Nota che questa potrebbe non essere la tua migliore pratica, ma è una pratica comune seguita quasi ovunque ho lavorato.

13
Sembra orribile ... = (Probabilmente sono troppo dall'altra parte, comunque, evito M $ il più possibile.
Lizzan,

Non dovrebbe essere così. Una biblioteca dovrebbe essere scelta per il suo valore, non solo considerando chi l'ha creata. Ad esempio, adoro EF ma ho avuto una brutta esperienza con Enterprise Library e ho trovato strumenti migliori per la convalida e la registrazione, come FluentValidation, log4net ed Elmah.
Matteo Mosca,

4
Non verrai licenziato per aver acquistato IBM ^ wMicrosoft
Christopher Mahan il

17
Esiste anche la versione con immagine speculare, ovvero non usare mai nulla di Microsoft o non usare mai nulla per cui devi pagare.
Richard Gadsden,

5
Ho la fortuna di lavorare in un'organizzazione in cui questo non è un dogma ampiamente diffuso, ma nei luoghi in cui abbiamo adottato soluzioni commerciali, c'è sicuramente molto dolore. Il problema si presenta quando una parte della soluzione commerciale non funziona del tutto. Quando è open source, puoi consultare la fonte (la documentazione definitiva) e scoprire cosa non va. Con la fonte chiusa, devi pagare per il privilegio di accedere alla conoscenza del supporto tecnico che sa ancora meno del prodotto che fai. E questa è l'unica 'correzione' disponibile.
SingleNegationElimination

40

Orientamento agli oggetti

C'è il presupposto, solo perché il codice è "orientato agli oggetti", è magicamente buono. Quindi le persone continuano a spremere la funzionalità in classi e metodi, solo per essere orientati agli oggetti.


7
Non riesco a immaginare di costruire un sistema software di dimensioni significative senza trarre vantaggio dall'organizzazione fornita da Object Orientation.
Robert Harvey,

18
Roberto. Unix non è orientato agli oggetti e sicuramente si qualifica come un sistema software di dimensioni significative. Sembra anche essere molto popolare (pensa a Mac OSX, iPhone, telefoni Android, ecc.)
Christopher Mahan,

7
Quello che volevo dire è che penso che dovremmo usare la metodologia più appropriata. Ho visto persone usare metodi e classi in cui è ingombrante e non ha molto senso, solo perché "è orientato agli oggetti". Questo è culto delle merci.
LennyProgrammers,

8
Non esiste un proiettile d'argento. La programmazione funzionale (Haskell) ha abbastanza successo senza essere orientata agli oggetti. Alla fine della giornata, hai più strumenti ed è tuo compito scegliere il miglior assortimento per l'attività da svolgere.
Matthieu M.,

9
La cosa divertente è che oltre a usare classi, polimorfismo e simili, la maggior parte del codice orientato agli oggetti è in realtà un codice procedurale.
Oliver Weiler,

35

Tutto il codice dovrebbe essere commentato.

No, non dovrebbe essere. Qualche volta hai un codice evidente, ad esempio i setter non dovrebbero essere commentati, fino a quando non fanno qualcosa di speciale. Inoltre, perché dovrei commentare questo:

/** hey you, if didn't get, it's logger. */
private static Logger logger = LoggerFactory.getLogger(MyClass.class);

13
Tutto il codice dovrebbe essere comprensibile . I commenti sono uno strumento importante in questo, ma tutt'altro che l'unico.
Trevel,

Assolutamente, il codice dovrebbe essere comprensibile. Ma non esiste un unico motivo per scrivere un commento che non aggiunga nulla, ad esempio, al nome del metodo. Se scrivi, /** sets rank. */ void setRank(int rank) { this.rank = rank; }presumo che il commento sia stupido. Perché è scritto?
Vladimir Ivanov,

2
Documentazione generata. Ecco a cosa /** */serve il formato anziché il /* */commento sul formato. O per .NET sarebbe///
Berin Loritsch il

10
Usando }//end if, }//end for, }//end whilesono il miglior esempio di spreco commentando io abbia mai incontrato. L'ho visto molte volte in cui la parentesi graffa di apertura non è più di 2 righe sopra. Se ho bisogno di questi commenti, il tuo codice ha bisogno di essere rifattorizzato ... o devi fare un pony di $ 20 e acquistare un editor IDE / Text che evidenzi le parentesi graffe corrispondenti.
scunliffe,

7
Il codice dice "come". I commenti devono dire "perché".

32

Metodologie, in particolare mischia. Non riesco a mantenere una faccia seria quando sento gli adulti usare la frase "Scrum Master". Sono così stanco di sentire la protesta degli sviluppatori che alcuni aspetti della Metodologia X non funzionano per la loro azienda, solo per essere raccontati dal Guru So-and-So che la ragione per cui non funziona è che in realtà non sono dei veri professionisti di Metodologia X. "Scrum più forte, è necessario, mio ​​studente Padawan!"

Ci sono pepite di saggezza nelle metodologie agili --- molte di esse --- ma spesso sono immerse in così tanto letame che non posso combattere il mio riflesso del vomito. Prendi questo bit dalla pagina di mischia di Wikipedia :

Numerosi ruoli sono definiti in Scrum. Tutti i ruoli rientrano in due gruppi distinti - maiali e polli - in base alla natura del loro coinvolgimento nel processo di sviluppo.

Veramente? Maiali e galline, dici? Affascinante! Non vedo l'ora di presentare questo al mio capo ...


Interessante. Sono d'accordo in una certa misura. Con quest'ultima parte però: chiamali come vuoi, sono mnemonici, tutto qui.
Steven Evers,

12
+1 ... hai ragione, è difficile prenderlo sul serio. <grande voce in forte espansione> * I AM THE SCRUMMASTER * </voice>
GrandmasterB

2
E le parabole. Mi ricorda i sermoni della chiesa, o il tipo di aneddoti per cui i guru (e i comici) di auto-aiuto sono famosi per: "Prendi il mio amico Steve. Steve litigava costantemente con sua moglie Sheryl. Quei due ci andavano per ore, per il punto in cui il loro matrimonio era in serio pericolo. Poi, un giorno ... "Questi tipi di filati didattici non mi danno fastidio in altre sfere, ma odio vederli proliferare nelle scienze ingegneristiche.
evadeflow,

2
Che dire degli Scrum Ninja?
Berin Loritsch,

1
Non sono d'accordo con il confronto "Maiale e pollo" ... vola direttamente di fronte al Manifesto Agile. Vale a dire "Collaborazione del cliente sulla negoziazione del contratto". I clienti hanno il merito (se non di più) del successo del progetto come il team del progetto. Chiamare alcuni ruoli maiali e altri ruoli i polli crea una mentalità "noi contro loro" secondo cui l'IMHO è il più grande ostacolo ai progetti di successo.
Michael Brown,

25

Mappatura relazionale degli oggetti ... http://en.wikipedia.org/wiki/Object-relational_mapping

Non voglio mai essere sottratto ai miei dati, né voglio perdere quel preciso controllo e ottimizzazione. La mia esperienza con questi sistemi è stata estremamente scarsa ... Le query generate da questi livelli di astrazione sono persino peggiori di quelle che ho visto off-shoring.


19
L'ottimizzazione prematura è la radice di tutti i mali. Il codice lento è, nella vita reale, solo incredibilmente raramente un problema rispetto al codice non mantenibile. Utilizzare un ORM, quindi tagliare l'astrazione solo dove serve.
Fishtoaster,

28
Gli ORM sono uno strumento 80-20. Hanno lo scopo di gestire l'80% di CRUD che diventa così noioso da scrivere tutto quel codice idraulico senza fine dopo un po '. L'altro 20% può essere fatto in modi più "convenzionali" come l'uso di stored procedure e la scrittura di normali query SQL.
Robert Harvey,

18
@Fishtoaster: non intendi dire "Dovremmo dimenticare piccole efficienze, diciamo circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali. Eppure non dovremmo rinunciare alle nostre opportunità in quel 3% critico".
Robert Harvey,

5
@Robert Harcey: C'è un motivo per cui non ho usato un preventivo diretto. Penso che la maggior parte dei programmatori si concentri troppo sull'efficienza: è un problema che pochi di loro hanno davvero bisogno di risolvere. Certo, ci sono alcuni domini in cui è più importante di altri, ma la manutenibilità e l'estensibilità sono un problema ovunque. Un'altra citazione modificata: "Fallo funzionare, rendilo mantenibile, rendilo leggibile, rendilo estendibile, rendilo testabile e poi , se hai tempo e risulta che ne hai bisogno, rendilo veloce."
Fishtoaster,

12
@Craig: come non hai riconosciuto l'ironia nella tua affermazione? La necessità di un anno per imparare a ottenere buone prestazioni da un ORM è un eccellente argomento contro gli ORM, così come la necessità di "controllare" l'SQL prodotto e iniettare le procedure memorizzate. Se ne hai le conoscenze, hai le conoscenze per bypassare completamente l'ORM.
Nicholas Knight,

22

Scrivere i nomi delle funzioni come se fossero frasi inglesi:

Draw_Foo()
Write_Foo()
Create_Foo()

ecc. Potrebbe sembrare fantastico, ma è un problema quando stai imparando un'API. Quanto è più facile cercare un indice per "Tutto ciò che inizia con Foo"?

Foo_Draw()
Foo_Write()
Foo_Create()

eccetera.


2
Probabilmente è facile come scrivere Foo nell'elenco delle funzioni di TM.
Josh K,

68
Sembra che tu voglia davvero che sia Foo.Draw(), Foo.Write()e Foo.Create(), così che tu possa fare Foo.methods.sortoFoo.methods.grep([what I seek]).sort
Inaimathi,

7
Iniziare con "Ottieni" è un altro esempio.
JeffO,

1
Vengo dal mondo oggettivo e mi mancano molto i nomi dei metodi dettagliati e la notazione infissa quando faccio java (l'altra mia vita). Da quando il completamento del codice ha iniziato a funzionare, non ho riscontrato problemi di digitazione extra.

2
@ Scott Whitlock: Non che non aggiornate per alcuni sviluppatori .NET, IIRC, VS 2008 non ha fatto questo. Il 2010 lo fa, ed è fantastico.
Steven Evers,

22

MVC: trovo spesso che nascondere molti problemi di web design nell'approccio MVC si basa più sul rendere felice un framework (rotaie ecc.) Che sulla semplicità o sulla struttura. MVC è una delle preferite degli "astronauti dell'architettura" che sembrano apprezzare le impalcature eccessive rispetto alla semplicità. YMMV.

OO di classe - a mio avviso incoraggia strutture complesse di stato mutevole. gli unici casi convincenti che ho trovato per OO basato sulla classe nel corso degli anni sono gli esempi banali "forma-> rettangolo-> quadrato" che formano il capitolo 1 di qualsiasi libro OO


4
Ho fatto lo sviluppo web in ASP.NET e ASP.NET MVC e, sebbene MVC sembri impazzito, lo preferisco di gran lunga ad ASP.NET, per molte ragioni: semplicità, manutenibilità e controllo estremamente accurato sul markup. Ogni cosa ha il suo posto e, mentre tutto sembra un po 'ripetitivo, è una gioia da mantenere. È completamente personalizzabile, quindi se non ti piace un comportamento immediato, puoi cambiarlo.
Robert Harvey,

1
Per quanto riguarda OO, ci sono modi buoni e cattivi per farlo. L'ereditarietà è sopravvalutata e utilizzata con più parsimonia nel mondo reale di quanto la maggior parte dei libri vorrebbe farvi credere; esiste attualmente una tendenza verso uno stile di sviluppo più funzionale e immutabile, anche nel mondo OO.
Robert Harvey,

1
+1 per menzionare MVC. Mentre il concetto di MVC (che separa la logica del livello dati, la logica di presentazione e la logica di sfondo è una buona idea) separarli fisicamente in una complessa gerarchia di cartelle con un miscuglio di file contenenti frammenti di codice è stupido. Dò la colpa di tutti questi fenomeni al mancato supporto dello spazio dei nomi di PHP e agli sviluppatori neofiti che glorificano tecniche vecchie di decenni come "la cosa più recente". È semplice, crea uno spazio dei nomi per gli accessori del database, la GUI e la logica di sfondo (e gli spazi dei nomi secondari dove necessario).
Evan Plaice,

3
Per quanto riguarda OO, non vedrai davvero i suoi benefici fino a quando il tuo progetto non raggiungerà dimensioni in cui la complessità della gestione diventa importante. Seguire il principio di responsabilità unica ove possibile e se il codice è accessibile pubblicamente esposto (ad es. Per un .dll) nascondere l'implementazione interna di classi / metodi / proprietà ove possibile per rendere il codice più sicuro e semplificare l'API.
Evan Plaice,

1
Personalmente trovo l'esempio di forma-> rettangolo-> quadrato come uno degli argomenti più eleganti contro l' oop. per esempio, Square(10).Draw()è sufficiente Rectangle(10, 10).Draw(). quindi immagino che significhi quadrato è una sottoclasse di rettangolo. Ma mySquare.setWidthHeight(5,10)è una sciocchezza (IE, fallisce il principio di sostituzione di Liskov), un quadrato non può avere diverse altezze e larghezze, sebbene un rettangolo possa, quindi ciò implica che il rettangolo è una sottoclasse di quadrati. Questo è noto in altri contesti come il "problema Circle, Ellipse"
SingleNegationElimination

22

YAGNI

( Non ne avrai bisogno )

Questo approccio mi è costato ore e ore quando ho dovuto implementare funzionalità su una base di codice esistente, dove un'attenta pianificazione avrebbe incluso queste funzionalità in anticipo.

Le mie idee sono state spesso respinte a causa di YAGNI, e la maggior parte delle volte qualcuno ha dovuto pagare per quella decisione in seguito.

(Naturalmente si potrebbe sostenere che una base di codice ben progettata consentirebbe anche l'aggiunta di funzionalità in un secondo momento, ma la realtà è diversa)


15
Sono d'accordo con YAGNI, ma vedo a cosa stai arrivando. Il punto di YAGNI è quello di trattare con persone che vogliono pianificare tutto fin nei minimi dettagli. Nove volte su dieci, tuttavia, è usato come una scusa per sotto il codice ingegnere o saltare completamente la pianificazione.
Jason Baker,

12
P.Floyd, @Jason Baker: +1 Assolutamente giusto. Il vecchio detto si applica qui "mesi in laboratorio possono far risparmiare ore in biblioteca"
Steven Evers,

Una specifica spesso lascerà (e soprattutto dovrebbe) lasciare gran parte dell'attuazione e parte dell'interfaccia aperta. tutto ciò che non è direttamente nella specifica, ma necessario per implementare la specifica, sia che si tratti di una decisione di implementazione, di un'interfaccia visualizzabile dall'utente o di qualsiasi altra cosa, è anche un requisito indiretto della specifica. Se una funzione non è nelle specifiche e non è implicita nelle specifiche, non è necessaria. Come può mai essere fonte di confusione?
SingleNegationElimination

1
@TokenMacGuy l'aspetto cruciale è implicito dalla parte specifica . Ecco dove le opinioni differiscono molto.
Sean Patrick Floyd,

20

Per SQL

  1. Non usare i trigger
  2. Nascondi sempre le tabelle dietro le viste

In ordine:

  1. Sono una caratteristica che ha il suo posto. Hai più percorsi di aggiornamento per una tabella o richiedi il controllo al 100%?

  2. Solo perché? Vorrei che se stessi eseguendo il refactoring per mantenere un contratto, ma non quando ho letto che le persone cambiano il punto di vista per adattarsi a qualsiasi modifica del tavolo

Modificare:

Numero 3: Evitare * con EXISTS. Prova 1/0. Funziona. L'elenco delle colonne non viene valutato secondo lo standard SQL. Pagina 191


3
# 2 è una buona pratica?
Hogan,


1
@Hogan: una vista che rispecchia semplicemente una tabella di base non aggiunge sicurezza sull'utilizzo diretto della tabella di base. Se ti unisci a una tabella securityuser, o maschera alcune colonne, allora abbastanza giusto. SELEZIONA ogni colonna dalla tabella o dalla vista: nessuna differenza. Personalmente, utilizzo comunque i proc memorizzati.
gbn,

3
@Hogan: so qualcosa su SQL Server :-) stackoverflow.com/users/27535/gbn Quello che voglio dire è GRANT SELECT sulla tabella non è diverso da GRANT SELECT ON VIEW se la vista è SELECT * FROM TABLE
gbn

1
@gbn: sono d'accordo. Non c'è differenza lì. Penso che potremmo dire la stessa cosa. Immagino che il mio commento originale ("# 2 sia una buona pratica?") Si basasse più sulla mia esperienza personale che le viste (come i trigger) sono più spesso usate male che usate correttamente. Pertanto, una tale migliore pratica porterebbe solo a un abuso, non a un miglioramento. Se è considerata una buona pratica, hai ragione al 100%, è una cattiva.
Hogan,

20

Modelli di design per lo più. Sono sovrautilizzati e sottoutilizzati.


13
+1 Ancora non vedo come i Design Pattern siano soluzioni belle o eleganti. Sono soluzioni alternative alle carenze linguistiche, niente di più.
Oliver Weiler,

2
Basta vederlo come uno sforzo per sradicare l'odore del linguaggio usando la lingua stessa.
Filip Dupanović,

15

Il principio di responsabilità unica

("ogni classe dovrebbe avere una sola responsabilità; in altre parole, ogni classe dovrebbe avere una, e una sola, ragione per cambiare")

Non sono d'accordo. Penso che un metodo dovrebbe avere solo una ragione per cambiare, e tutti i metodi in una classe dovrebbero avere una relazione logica tra loro , ma la classe stessa potrebbe effettivamente fare diverse cose (correlate).

Nella mia esperienza, questo principio troppo spesso viene applicato in modo troppo zelante e si finisce con molte piccole classi con un metodo. Entrambi i negozi agili in cui ho lavorato lo hanno fatto.

Immagina se i creatori dell'API .Net avessero avuto questo tipo di mentalità: piuttosto che List.Sort (), List.Reverse (), List.Find () ecc., Avremmo le classi ListSorter, ListReverser e ListSearcher!

Piuttosto che litigare più contro l'SRP (che in sé non è terribile in teoria) , condividerò alcune delle mie esperienze aneddotiche a lungo termine:


In un posto in cui ho lavorato, ho scritto un risolutore di flusso massimo molto semplice che consisteva in cinque classi: un nodo, un grafico, un creatore di grafici, un risolutore di grafici e una classe per utilizzare il creatore di grafici / solutori per risolvere un problema del mondo reale. Nessuno era particolarmente complesso o lungo (il solutore era di gran lunga il più lungo con circa 150 righe). Tuttavia, è stato deciso che le classi avevano troppe "responsabilità", quindi i miei colleghi hanno iniziato a riformattare il codice. Al termine, le mie 5 classi erano state estese a 25 classi, le cui linee di codice totali erano più del triplo di quelle che erano in origine. Il flusso del codice non era più ovvio, né lo scopo dei nuovi test unitari; Ora ho avuto difficoltà a capire cosa facesse il mio codice.


Allo stesso posto, quasi ogni classe aveva un solo metodo (la sua unica "responsabilità"). Seguire il flusso all'interno del programma era quasi impossibile e la maggior parte dei test unitari consisteva nel verificare che questa classe chiamasse codice da un'altra classe , entrambi i cui scopi erano ugualmente un mistero per me. C'erano letteralmente centinaia di classi in cui avrebbero dovuto esserci (IMO) solo dozzine. Ogni classe ha fatto solo una "cosa" , ma anche con convenzioni di denominazione come "AdminUserCreationAttemptorFactory" , era difficile dire la relazione tra le classi.


In un altro posto (che aveva anche la mentalità class-have-have-only-one-method ), stavamo cercando di ottimizzare un metodo che impiegava il 95% del tempo durante una certa operazione. Dopo averlo (piuttosto stupidamente) ottimizzato un po ', ho rivolto la mia attenzione al perché veniva chiamato un bajillion volte. Veniva chiamato in un ciclo in una classe ... il cui metodo veniva chiamato in un ciclo in un'altra classe ... che veniva anche chiamato in un ciclo ...

Tutto sommato, c'erano 13 livelli di loop distribuiti su 13 classi (sul serio). Ciò che una classe stava effettivamente facendo era impossibile da determinare semplicemente osservandolo: dovevi tracciare un grafico mentale di quali metodi chiamava, quali metodi chiamavano quei metodi e così via. Se fosse stato tutto sommato in un unico metodo, sarebbe stato lungo solo circa 70 righe con il nostro metodo problematico annidato all'interno di cinque livelli immediatamente evidenti di loop.

La mia richiesta di trasformare queste 13 classi in una classe è stata respinta.


6
Sembra che qualcuno abbia ottenuto "Pattern Fever" o in questo caso "Principle Fever" in quel lavoro. La classe list non viola SRP. Tutte le sue funzioni hanno uno scopo, manipolando una collezione di oggetti. Avere solo una funzione in una classe mi sembra eccessivo. Il principio alla base di SRP è che un'unità di codice (che si tratti di metodo, classe o libreria) dovrebbe avere un'unica responsabilità che può essere dichiarata con successo.
Michael Brown,

3
Ho iniziato a vedere questo tipo di follia da parte di persone che trovano impossibile scrivere codice funzionale puro. Insegnare troppo che ogni problema nel mondo può essere risolto da un libro di schemi. Non abbastanza pensato al pragmatismo. Come te ho visto un codice OO basato sulla classe che è così orribile che seguirlo è completamente impossibile. Ed è enorme e gonfio.
quick_now

3
2 ° commento qui. Molti "principi" sono troppo applicati. Ci sono molte cose che sono buone idee, dove talvolta è appropriato fare esattamente il contrario. I bravi programmatori sanno quando infrangono le regole. Poiché le regole non sono "regole", sono dichiarazioni di "buona pratica il più delle volte tranne quando è un'idea davvero stupida".
quick_now

"Immagina se i creatori dell'API .Net avessero avuto questo tipo di mentalità: piuttosto che List.Sort (), List.Reverse (), List.Find () ecc., Avremmo le classi ListSorter, ListReverser e ListSearcher !". Questo è esattamente ciò che viene fatto in C ++ ed è meraviglioso . Gli algoritmi sono separati dalle strutture di dati, quindi se scrivo il mio contenitore, tutti gli algoritmi che funzionano con la libreria standard funzionano con il mio nuovo contenitore. Deve essere orribile in terra .Net, scrivere una nuova funzione di ordinamento per ogni nuovo contenitore che si desidera ordinare.
Mankarse,

14

Ora che hai menzionato Clean Code, sebbene contenga alcune buone idee, penso che la sua ossessione di trasformare tutti i metodi in sottometodi e quelli in sotto-metodi ecc. Sia stata portata troppo avanti. Invece di un paio di metodi a dieci righe, dovresti preferire venti linee (presumibilmente ben definite) a una linea. Ovviamente qualcuno pensa che sia pulito, ma a me sembra molto peggio della versione originale.

Inoltre, sostituendo semplici elementi elementari come

0 == memberArray.length

all'interno di una classe con una chiamata al metodo della classe come

isEmpty()

è un discutibile IMHO "miglioramento". Aggiunta: la differenza è che il primo controllo fa esattamente quello che dice: controlla se la lunghezza dell'array è 0. Ok, isEmpty()potrebbe anche controllare la lunghezza dell'array. Ma potrebbe anche essere implementato in questo modo:

return null != memberArray ? 0 == memberArray.length : true;

Cioè, include un controllo null implicito! Questo potrebbe essere un buon comportamento per un metodo pubblico - se l'array è nullo, allora qualcosa è certamente vuoto - ma quando parliamo di interni di classe, non va bene. Mentre l'incapsulamento verso l'esterno è un must, gli interni della classe devono sapere esattamente cosa sta succedendo all'interno della classe. Non è possibile incapsulare la classe da se stessa . Esplicito è meglio che implicito.


Ciò non significa che rompere i metodi lunghi o comportare confronti logici non vada bene; certo che lo è, ma fino a che punto farlo - dov'è il punto debole - è ovviamente una questione di gusti. Abbattere un metodo lungo si traduce in più metodi e ciò non viene fornito gratuitamente. Devi saltare il codice sorgente per vedere cosa sta realmente succedendo, quando puoi vederlo a colpo d'occhio se tutte quelle cose fossero in un unico metodo.

Direi addirittura che in alcuni casi un metodo a 1 riga è troppo breve per meritare di essere un metodo.


6
Raramente vedo questo come un problema. Soprattutto perché di solito vedo troppo in un singolo metodo, non troppo poco. Tuttavia, secondo alcuni studi, una complessità dei metodi molto bassa ha anche un tasso di bug leggermente superiore rispetto a una complessità moderatamente bassa. enerjy.com/blog/?p=198
MIA

Sì, questo è sicuramente un problema solo nel codice pulito. Nella vita reale i metodi tendono ad essere troppo lunghi, come hai detto. Ma è interessante vedere quella curva! In effetti, le cose dovrebbero essere rese il più semplice possibile, ma non più semplice.
Joonas Pulakka,

1
Trovo il tuo secondo esempio eminentemente più leggibile, e quel modulo (o qualcosa di simile, come una proprietà Length sulla classe stessa) è un must se lo rendi pubblico.
Robert Harvey,

@Robert Harvey: Il secondo esempio è un ottimo metodo pubblico, ma chiamarlo dall'interno della classe stessa è discutibile, perché non sai esattamente cosa fa prima di vedere come è implementato. Potrebbe verificare la presenza di null, ad esempio. Vedi la mia aggiunta sopra.
Joonas Pulakka,

@Joonas: abbastanza giusto.
Robert Harvey,

13

"Sii liberale con i commenti"

I commenti sono sicuramente una buona cosa, ma troppi sono altrettanto cattivi se non peggio che non sufficienti. Perché? Bene, le persone tendono a mettere a punto i commenti se ne vedono troppi inutili. Non sto dicendo che puoi avere un codice perfettamente autocompattante, ma è preferibile un codice che necessita di commenti per una spiegazione.


1
il codice di auto-documentazione è decisamente carino. Tuttavia, mi piace avere commenti a fianco qualcosa come semplici calcoli (per esprimere quale sia il tipo di ritorno o il valore restituito). Tuttavia, se i tuoi commenti hanno bisogno di più parole del codice stesso, probabilmente è il momento di riscrivere il codice.
sova,

6
Devo essere d'accordo con il modo in cui la Sova ha inserito questo. Il codice pulito è preferibile ai commenti.
riwalk

4
Hai ancora bisogno del "perché" è lì dentro!

Preferirei avere commenti che spieghino il perché. Significa che devo pensare meno nell'ingegnerizzazione inversa dell'intento di codice quando vengo a vederlo.
quick_now

12

GoTo Considerato dannoso

Se stai implementando una macchina a stati, un'istruzione GOTO può avere più senso (leggibilità e codice efficiente) di un approccio di "programmazione strutturata". Alcuni colleghi hanno davvero preoccupato quando il primo pezzo di codice che ho scritto in un nuovo lavoro includeva non solo una ma diverse dichiarazioni di goto. Fortunatamente erano abbastanza intelligenti da rendersi conto che in realtà era la soluzione migliore in questo caso particolare.

Qualsiasi "best practice" che non consenta eccezioni sensate e documentate alle sue regole è semplicemente spaventosa.


16
Vado avanti per nove anni a programmare senza una singola dichiarazione goto (compresi diversi computer statali, come hai menzionato). Espandi la tua mente a nuove idee.
riwalk

3
@Mathieu M. - concordato - non è sensato mescolare GOTO con dichiarazioni di controllo strutturate. (Questo era puro C e non era un problema.
MZB

1
@ Stargazer2 - con un semplice FSM, dipende se mettere lo stato in una variabile e usarlo come indice per chiamare una procedura (non è lo stesso di un GOTO calcolato?) Fornisce un codice più chiaro / veloce rispetto all'utilizzo del contatore del programma come stato FSM. Non sto sostenendo questo come la migliore soluzione nella maggior parte dei casi, solo la migliore soluzione in alcune circostanze. Espandi la tua mente ad approcci alternativi.
MZB,

5
@MZB, non saresti d'accordo sul fatto che una chiamata di funzione sia anche solo un GOTO calcolato? Lo stesso vale per / while / if / else / switch build, tra gli altri. I designer linguistici eliminano le modifiche dirette al contatore del programma per un motivo. Non usare goto.
riwalk

3
L'implementazione diretta di una macchina a stati è probabilmente un antipattern. Esistono molti modi per avere una macchina a stati senza esprimere letteralmente gli stati e le transizioni. per esempio,import re
SingleNegationElimination

12

I sacrifici che facciamo per rendere testabile il codice

Salto attraverso molti cerchi per rendere il mio codice testabile, ma non faccio finta che non lo farei se avessi la scelta. Tuttavia, sento spesso persone che spingono l'idea che si tratti di "buone pratiche". Queste pratiche includono (scritto nella lingua di .Net, ma si applica anche ad altre lingue) :

  • Creazione di un'interfaccia per ogni classe. Questo raddoppia il numero di classi (file) da gestire e duplica il codice. Sì, la programmazione dell'interfaccia è buona, ma è a questo che servono gli specificatori pubblici / privati.
  • Ogni classe non istanziata all'avvio richiede una factory. Chiaramente, new MyClass()è molto più semplice che scrivere una fabbrica, ma ora il metodo che lo crea non può essere testato da solo. Se non fosse per questo, farei solo 1/20 del numero di classi di fabbrica che faccio ora.
  • Rendi pubblica ogni classe, il che vanifica lo scopo di avere specificatori di accesso sulle classi. Tuttavia, le classi non pubbliche non sono accessibili (e quindi testate) da altri progetti, quindi l'unica altra opzione è spostare tutto il codice di test nello stesso progetto (e quindi rilasciarlo con il prodotto finale).
  • Iniezione di dipendenza. Devo chiaramente dare a ogni altra classe che uso un campo e un parametro di costruzione è significativamente più lavoro che semplicemente crearli quando ne ho bisogno; ma poi non posso più testare questa classe in isolamento.
  • Il principio della responsabilità singola, che mi ha causato così tanti mal di testa, l'ho spostato nella sua risposta .

Quindi cosa potremmo fare per risolvere questo problema? Avremmo bisogno di un drastico cambiamento nell'architettura del linguaggio:

  • Avremmo bisogno della capacità di deridere le lezioni
  • Avremmo bisogno della capacità di testare metodi privati ​​di classi interne, da un altro progetto (questo può sembrare una vulnerabilità di sicurezza, ma non vedo alcun problema se il testato è costretto a nominare le sue classi tester) .
  • L'iniezione di dipendenza (o la posizione del servizio), nonché qualcosa di equivalente al nostro modello di fabbrica esistente, dovrebbe essere una parte fondamentale del linguaggio.

In breve, abbiamo bisogno di un linguaggio progettato da zero con in mente la testabilità .


Immagino tu non abbia mai sentito parlare di TypeMock ? Permette classi beffardo, privati, statica (fabbrica), qualsiasi cosa.
Allon Guralnek,

@Allon: l'ho fatto, ma è tutt'altro che gratuito , rendendolo non un'opzione per la maggior parte delle persone.
BlueRaja - Danny Pflughoeft,

Se devi scrivere molte classi di fabbrica, stai facendo qualcosa di sbagliato. Le librerie Smart DI (ad es. Autofac per C #) possono utilizzare Func <T>, Lazy <T>, Delegati ecc. Per le fabbriche, senza scrivere tu stesso alcuna piastra di caldaia.
gix,

10

Separazione delle applicazioni in livelli; Livello dati, livello aziendale, livello dell'interfaccia utente

Il motivo principale per cui non mi piace questo è che la maggior parte dei luoghi che seguono questo metodo usano framework molto fragili per farlo. IE UI Layer è codificato a mano per gestire gli oggetti del livello aziendale, gli oggetti del livello aziendale sono codificati a mano per gestire le regole aziendali e il database, il database è SQL ed è già abbastanza fragile e gestito dal gruppo "DBA" a cui non piace il cambiamento.

Perché è così male? La richiesta di miglioramento più comune è probabilmente "Ho bisogno di un campo sullo schermo X che ha Y." Scoppio! Hai solo una nuova funzionalità che interessa ogni singolo livello e, se separi i livelli con programmatori diversi, è diventato un grosso problema che coinvolge più persone e gruppi, per un cambiamento molto semplice.

Inoltre, non so quante volte ho litigato con argomenti del genere. "Il campo del nome è limitato a una lunghezza massima di 30, si tratta di un livello dell'interfaccia utente, un livello aziendale o un problema del livello dati?" E ci sono cento argomenti e nessuna risposta giusta. La risposta è la stessa, influisce su tutti i livelli, non si vuole rendere stupida l'interfaccia utente e passare attraverso tutti i livelli, e fallire nel database, solo così l'utente scopre che la sua voce è troppo lunga. Se lo cambi, influisce su tutti i livelli, ecc.

Anche gli "strati" tendono a perdere; Se uno strato è fisicamente separato dai confini di processo / macchina (IE Web UI e logica di backend aziendale), le regole vengono duplicate per far funzionare tutto ragionevolmente bene. Vale a dire che alcune logiche aziendali finiscono nell'interfaccia utente, anche se si tratta di una "regola aziendale", poiché l'utente ha bisogno che l'interfaccia utente sia reattiva.

Se il framework utilizzato o l'architettura utilizzata è resistente a piccole modifiche e perdite, ovvero basato su metadati e regolato dinamicamente su tutti i livelli, può essere meno doloroso. Ma la maggior parte dei framework è una vera seccatura, che richiede modifiche dell'interfaccia utente, modifiche del livello aziendale e modifiche al database, per ogni piccola modifica, e che causa più lavoro e meno aiuto di quanto la tecnica dovrebbe produrre.

Probabilmente mi sbatterò per questo, ma eccolo :)


+1, suona come il mio ultimo posto di lavoro nei minimi dettagli! In linea di principio rispetto le applicazioni a più livelli, tuttavia troppe persone lo trattano come un proiettile d'argento quando non ha senso. La maggior parte dei software aziendali ha una quantità incredibilmente bassa di logica aziendale e ciò che ha è relativamente semplice. Ciò può rendere la logica di business a strati un incubo di codice boilerplate. Molte volte le linee possono essere sfocate tra l'accesso ai dati e la logica aziendale perché la query è la logica aziendale.
maple_shaft

... inoltre, la maggior parte dei negozi non riesce assolutamente a riconoscere la logica dell'interfaccia utente o la logica di presentazione. Poiché non comprendono solo la scarsa logica aziendale in una tipica applicazione CRUD, si sentono come se dovessero fare qualcosa di sbagliato quando la maggior parte della loro logica risiede nel livello di presentazione come logica di presentazione. Viene erroneamente identificato come logica aziendale e quindi le persone lo spingono sul server per l'ennesima chiamata al server. Un thin client può e deve avere una logica di presentazione, ad es. (Nascondi textField2 se l'opzione 1 è selezionata in dropDown3).
maple_shaft


7

User Stories / Use Cases / Personas

 

Comprendo la necessità di questi quando programmate per un settore che non conoscete, ma penso che quando sono implementati in piena forza diventano troppo corporativi e diventano una perdita di tempo.


7

80 limiti char / line sono stupidi

Capisco che alcuni compromessi devono essere fatti per adattarsi al ritmo del corridore più lento sul lato della GUI (limitazioni della risoluzione dello schermo, ecc.) Ma perché questa regola si applica alla formattazione del codice?

Vedi ... C'era questa piccola invenzione chiamata barra di scorrimento orizzontale creata per gestire lo spazio dello schermo virtuale al di fuori del limite di pixel più a destra. Perché gli sviluppatori, che sono riusciti a creare grandi strumenti per migliorare la produttività come l'evidenziazione della sintassi e il completamento automatico, non lo usano?

Certo, ci sono editor CLI usati religiosamente dai dinosauri * nix che seguono le vecchie e stanche limitazioni dei loro terminali VT220 ma perché tutti noi siamo tenuti allo stesso standard?

Dico, avvita il limite di 80 caratteri. Se i dinosauri sono abbastanza epici da hackerare su emacs / vim tutto il giorno, perché non dovrebbe essere in grado di creare un'estensione che avvolge automaticamente le linee o offre funzionalità di scorrimento orizzontale ai loro IDE CLI?

I monitor da 1920x1080 pixel alla fine diventeranno la norma e gli sviluppatori di tutto il mondo vivono ancora con le stesse limitazioni senza influenzare il motivo per cui lo fanno tranne che è quello che gli anziani hanno detto di fare quando hanno appena iniziato a programmare.

80 limiti di caratteri non sono una buona pratica ma una pratica di nicchia per una minoranza di programmatori e dovrebbero essere trattati come tali.

Modificare:

È comprensibile che a molti sviluppatori non piaccia la barra di scorrimento orizzontale perché richiede un gesto del mouse, quindi ... Perché non aumentare il limite di larghezza della colonna a un numero più alto (di 80) per quelli di noi che usano i display moderni.

Quando i monitor di computer 800x600 sono diventati la norma per la maggior parte degli utenti, gli sviluppatori Web hanno aumentato la larghezza del loro sito Web per soddisfare la maggior parte ... Perché gli sviluppatori non possono fare lo stesso.


1
@Orbling La bella logica GWB con ___ è un angolo malvagio. Quindi detesti hScroll, hai qualche motivo valido per cui col-width dovrebbe essere limitata a 80 caratteri? Perché non 160 o 256? Penso che tutti possiamo presumere che la maggior parte degli sviluppatori abbia ritirato i propri terminali VT220 e li abbia sostituiti con puTTY in modo da poter estendere la larghezza in modo programmatico comunque.
Evan Plaice,

4
Preferisco attenerci al limite di 80 caratteri. Non appena mi dai più spazio orizzontale, proverò ad aprire altri documenti fianco a fianco con il resto. Odierei dover scorrere in quattro modi. Inoltre, ho notato spesso che sono costretto a scrivere codice più leggibile con il cap di 80 caratteri.
Filip Dupanović,

2
come lo stamperesti?

5
Siamo spiacenti, non sono d'accordo su questo. Odio davvero le lunghe lunghe file: richiede più movimento degli occhi, richiede gesti del mouse per scorrere attraverso, è più difficile vedere cose leggermente piccole e pericolose lungo la fine di una linea. In circa il 99% dei casi ci sono modi puliti per far funzionare le cose su più (più brevi) righe che sono più chiare e più facili da leggere. 80 caratteri potrebbero essere arbitrari e "perché era così nei giorni delle carte perforate" ma è ancora un quadro ragionevole per lavorare all'interno - il più delle volte - per i motivi sopra.
quick_now

3
Rientro di 2 spazi. E usa un editor con un tracker di rientro automatico. L'ho fatto in questo modo per anni, un grosso problema. (Emacs con le giuste modalità aiuta qui.)
quick_now

5

Misura, misura, misura

Così bene, misura via, ma per isolare i bug delle prestazioni, la misurazione funziona così come la successiva eliminazione. Ecco il metodo che uso.

Ho cercato di rintracciare la fonte della "saggezza" misura-misura. Qualcuno con una soapbox abbastanza alta l'ha detto, e ora viaggia.


5

Il mio insegnante mi chiede di iniziare tutti i miei identificatori (escluse le costanti) con lettere minuscole, ad es myVariable.

So che sembra una cosa minore, ma molti linguaggi di programmazione richiedono che le variabili inizino con lettere maiuscole. Apprezzo la coerenza, quindi è mia abitudine iniziare tutto con lettere maiuscole.


9
Avevo un insegnante che richiedeva camelCase perché insisteva che era quello che le persone usano nel mondo reale ... Allo stesso tempo stavo programmando in due diversi gruppi nel mio lavoro - entrambi i gruppi hanno insistito su under_scores. Ciò che conta è ciò che utilizza il tuo gruppo. Avrebbe potuto definirsi il programmatore principale e tutto sarebbe andato bene nel mio libro - seguiamo le sue convenzioni - ma dava sempre la sua opinione come "il modo in cui le cose vengono fatte nel mondo reale" come se non ci fossero altri validi modo.
xnine,

@xnine Non ho ancora abbastanza rappresentanti su questo sito per valutare il tuo commento, quindi risponderò con questo commento di approvazione.
Max.

5
Il caso Camel (prima lettera minuscola) è una convenzione piuttosto comune, così come il caso Pascal (prima lettera di ogni parola maiuscola). Nella maggior parte delle lingue, camelCase viene utilizzato su variabili private / interne in cui PascalCase viene utilizzato su classi, metodi, proprietà, spazi dei nomi, variabili pubbliche. Non è una cattiva pratica abituarsi a essere pronti solo per progetti che potrebbero utilizzare un diverso schema di denominazione.
Evan Plaice,

2
Solo un FYI. Alcune lingue deducono significato dal fatto che la prima lettera di una variabile sia maiuscola o meno. In una di queste lingue, se la prima lettera è maiuscola, la variabile viene trattata come una costante: qualsiasi tentativo di modificarla genererà un errore.
Berin Loritsch,

1
In Go , i metodi e i membri pubblici nelle classi iniziano con una lettera maiuscola; quelli privati ​​con una lettera minuscola.
Jonathan Leffler,

5

Usa Singletons

Quando dovresti avere solo un'istanza di qualcosa. Non posso essere più in disaccordo . Non utilizzare mai un singleton e allocarlo una volta sola e passare il puntatore / oggetto / riferimento secondo necessità. Non c'è assolutamente alcun motivo per non farlo.


2
Questo è un sacco di aspetti negativi che mi ha lasciato piuttosto confuso per quanto riguarda la tua attuale posizione sui singoli.
Paul Butcher,

1
@Paul Butcher: odio i single e non dovrebbe mai essere usato

1
@rwong: Personalmente non credo che qualsiasi motivo sia legittimo. Scrivilo come una lezione normale. Davvero, non c'è motivo di usare un singleton diverso dalla pigrizia e per promuovere cattive abitudini o design.

6
Chi dice che usare Singeltons sia la migliore pratica?
Phil Mander,

2
I singoli hanno il loro posto, soprattutto nei casi in cui una struttura operativa viene allocata e riempita all'avvio, quindi viene sostanzialmente letta solo durante il tempo di esecuzione del programma. In tal caso, tuttavia, diventa solo una cache sull'altro lato di un puntatore.
Tim Post

5

Utilizzo di int senza segno come iteratore

Quando impareranno che usare int firmato è molto più sicuro e meno soggetto a bug. Perché è così importante che l'indice di array possa essere solo un numero positivo, che tutti sono felici di trascurare il fatto che 4 - 5 è 4294967295?


Ok, ora sono curioso, perché dici questo? Mi sento un po 'stupido: puoi fornire alcuni esempi di codice per eseguire il backup delle tue dichiarazioni?
Paul Nathan,

4
@Paul Nathan: per quanto riguarda il problema, ecco un esempio: for (unsigned int i = 0; i <10; i ++) {int crash_here = my_array [max (i-1,0)];}
AareP

@AareP: A dire il vero - presumo tu stia facendo riferimento al fatto che quando un int senza segno 0viene decrementato 1, alla fine si ottiene il valore positivo massimo che un int senza segno può memorizzare?
Adam Paynter,

1
@Adam Paynter: si. Questo potrebbe sembrare normale per i programmatori c ++, ma ammettiamolo, "unsigned int" è una cattiva "implementazione" di numeri solo positivi.
AareP,

Non è una buona idea su macchine embedded di piccole dimensioni: spesso inserimenti non firmati generano codice più piccolo e più veloce. Dipende dal compilatore e dal processore.
quick_now

4

I metodi non dovrebbero essere più lunghi di una singola schermata

Concordo pienamente con il principio della responsabilità singola, ma perché le persone lo percepiscono come "una funzione / metodo non può avere più di una singola responsabilità al più alto livello di granularità logica"?

L'idea è semplice Una funzione / metodo dovrebbe svolgere un compito. Se parte di quella funzione / metodo può essere utilizzata altrove, tagliarla nella propria funzione / metodo. Se potrebbe essere utilizzato altrove nel progetto, spostarlo nella propria classe o in una classe di utilità e renderlo accessibile internamente.

Avere una classe che contiene 27 metodi helper che vengono chiamati una sola volta nel codice è stupido, uno spreco di spazio, un inutile aumento della complessità e un enorme dispendio di tempo. Sembra più una buona regola per le persone che vogliono apparire impegnate nel refactoring del codice ma non producono molto.

Ecco la mia regola ...

Scrivi funzioni / metodi per realizzare qualcosa

Se ti trovi in ​​procinto di copiare / incollare del codice, chiediti se sarebbe meglio creare una funzione / metodo per quel codice. Se una funzione / metodo viene chiamata una sola volta in un'altra funzione / metodo, c'è davvero un punto nel farlo in primo luogo (verrà chiamata più spesso in futuro). È utile aggiungere più salti in / out di funzioni / metodi durante il debug (vale a dire, il salto aggiunto rende il debug più facile o più difficile)?

Concordo pienamente sul fatto che funzioni / metodi superiori a 200 righe debbano essere esaminati, ma alcune funzioni svolgono solo un compito in altrettante righe e non contengono parti utili che possono essere astratte / utilizzate sul resto del progetto.

Lo guardo da una prospettiva di sviluppo API ... Se un nuovo utente dovesse guardare il diagramma di classe del tuo codice, quante parti di quel diagramma avrebbero senso all'interno del più grande progetto e quante esisterebbero solo come aiutanti di altre parti interne al progetto.

Se dovessi scegliere tra due programmatori: il primo ha la tendenza a scrivere funzioni / metodi che provano a fare troppo; il secondo rompe ogni parte di ogni funzione / metodo al massimo livello di granularità; Vorrei scegliere le prime mani verso il basso. Il primo otterrebbe di più (ovvero scrivere più carne dell'applicazione), il suo codice sarebbe più facile da eseguire il debug (a causa di un minor numero di salti in / out di funzioni / metodi durante il debug), e perderebbe meno tempo a impegnarsi nel perfezionamento di come il codice sembra vs perfezionare il modo in cui funziona il codice.

Limitare le astrazioni non necessarie e non inquinare il completamento automatico.


Questo. Una volta ho riformulato alcune funzioni lunghe in diverse, solo per rendermi conto che quasi tutte avevano bisogno di quasi tutti i parametri del codice originale. La gestione dei parametri è stata talmente dolorosa che è stato più semplice tornare al vecchio codice.
10

3
Penso che un argomento contrario sia che il refactoring di parti di un metodo di grandi dimensioni in chiamate separate può rendere più semplice la lettura del metodo più grande. Anche se il metodo viene chiamato solo una volta.
Jeremy Heiler,

1
@Jeremy Come? In che modo, astrarre una sezione di codice e inserirla nel suo metodo rende la lettura più semplice del semplice posizionamento di un commento di una riga nella parte superiore di quel blocco di codice che descrive cosa fa? Supponendo che quel blocco di codice sia usato solo una volta in quella sezione di codice. È davvero così difficile per la maggior parte dei programmatori decomporre le parti funzionanti del codice mentre lo leggono e / o inserire alcuni commenti di una riga per ricordare loro cosa fa se non possono?
Evan Plaice,

4
@Evan: Mettere pezzi di codice in funzioni dà loro un nome efficace , si spera bene spiegando cosa fa quel pezzo di codice. Ora, ovunque venga chiamato quel pezzo di codice, puoi vedere il nome che spiega cosa fa il codice , invece di dover analizzare e comprendere l'algoritmo stesso. Se fatto bene, questo può facilitare la lettura e la comprensione del codice tremendamente.
sabato

1
+1 e darei di più se potessi. Non c'è nulla di sbagliato in un grumo di codice C che contiene 1000 righe in una singola funzione (ad esempio un parser con un enorme switch ()) FORNITO che l'intento è chiaro e semplice. Distruggere tutti i piccoli pezzi e chiamarli rende la cosa più difficile da capire. Naturalmente ci sono limiti anche a questo ... il giudizio ragionevole è tutto.
quick_now
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.