Perché non dovrei usare la "notazione ungherese"?


122

So a cosa si riferisce l'ungherese: fornire informazioni su una variabile, un parametro o un tipo come prefisso al suo nome. Tutti sembrano essere rabbiosamente contrari, anche se in alcuni casi sembra essere una buona idea. Se sento che vengono fornite informazioni utili, perché non dovrei metterle proprio lì dove sono disponibili?

Vedi anche: Le persone usano le convenzioni di denominazione ungheresi nel mondo reale?


Risposte:


174

La maggior parte delle persone usa la notazione ungherese in modo sbagliato e ottiene risultati sbagliati.

Leggi questo eccellente articolo di Joel Spolsky: Far sembrare sbagliato il codice sbagliato .

In breve, la notazione ungherese in cui anteponi i nomi delle variabili con la loro type(stringa) (sistemi ungheresi) è cattiva perché è inutile.

Notazione ungherese come era intesa dal suo autore, dove anteponi al nome della variabile il suo kind(usando l'esempio di Joel: stringa sicura o stringa non sicura), le cosiddette app ungheresi hanno i suoi usi ed è ancora preziosa.


5
Buon collegamento, un buon riassunto di cosa c'è dietro il collegamento e nessun fanatismo. Eccellente.
Dustman

12
Nota che l'esempio di Joels è in VBScript, un linguaggio che a lungo non aveva classi definite dall'utente. In un linguaggio OO dovresti semplicemente creare un tipo HtmlEncodedString e fare in modo che il metodo Write accetti solo quello. Le "app ungheresi" sono utili solo nelle lingue senza tipi definiti dall'utente.
JacquesB

4
Microsoft è nota per il suo passato uso improprio della notazione ungherese. Anteporre le informazioni sul tipo agli identificatori non solo è inutile, ma può effettivamente causare danni. Primo, la leggibilità è meno fluente. In secondo luogo, nelle lingue che supportano il polimorfismo o la digitazione a papera vengono trasmesse le informazioni sbagliate.
Wilhelmtell

9
Mi piace ancora usare la notazione ungherese se sto sviluppando direttamente in C con un IDE precedente ... in questo modo so che non ci sono problemi di casting del tipo.
Beep beep

3
@Krumia: questo sarebbe tipicamente evitato avendo in primo luogo nomi descrittivi delle variabili. Ma se vuoi essere sicuro, sarebbe molto più sicuro creare tipi distinti (es. Strutture) per lunghezze, pesi ecc. E utilizzare l'overloading degli operatori per garantire che siano possibili solo operazioni valide.
JacquesB

277

vUsando adjUngherese nnotation vmakes nreading ncode adjdifficult.


101
Bella analogia, anche se leggermente ingiusta. Confronta: vUsing adjUngherese nNotation vMakes nReading nCode adjDifficult.
Chris Noe,

27
In quella frase, sia Using che Reading sono gerundi. Ma capisco il punto che stavi dicendo ...
scimpanzé

28
@chimp: questo rende le cose ancora più ovvie. ora che hai riscontrato un errore nel tipo hai intenzione di rinominare tutti i riferimenti o di lasciarli così come sono, fornendo informazioni sbagliate? perdi in entrambi i casi. ma ovviamente questo è il modo SBAGLIATO di applicare la notazione ungherese.
Wilhelmtell

1
@ Chris Noe: per alcuni stili di lettura (analizza il prefisso e il suffisso con uno sguardo al centro), il tuo esempio non fa che peggiorare le cose. Vedo "vUsing" e sento "voosing" nella mia testa.
Bob Cross,

3
@ Jon: se hai un nome di variabile che non rivela completamente ciò che rappresenta, allora con tutti i mezzi l'obiettivo dovrebbe essere quello di rinominarlo in qualcosa di più descrittivo (e la notazione ungherese non è un miglioramento, proprio, molto nel migliore dei casi è risolvere il sintomo, non risolvere il problema).
hlovdal

104

Joel ha torto, ed ecco perché.

Quelle informazioni sull'applicazione di cui sta parlando dovrebbero essere codificate nel sistema di tipi . Non dovresti dipendere dall'inversione dei nomi delle variabili per assicurarti di non passare dati non sicuri a funzioni che richiedono dati sicuri. Dovresti renderlo un errore di tipo, in modo che sia impossibile farlo. Qualsiasi dato non sicuro dovrebbe avere un tipo contrassegnato come non sicuro, in modo che semplicemente non possa essere passato a una funzione sicura. Per convertire da non sicuro a sicuro dovrebbe richiedere l'elaborazione con una sorta di funzione di disinfezione.

Molte delle cose di cui Joel parla come "tipi" non sono tipi; sono, infatti, tipi.

Ciò che manca alla maggior parte delle lingue, tuttavia, è un sistema di tipi sufficientemente espressivo per applicare questo tipo di distinzioni. Ad esempio, se C avesse una sorta di "strong typedef" (dove il nome typedef aveva tutte le operazioni del tipo di base, ma non era convertibile ad esso) allora molti di questi problemi scomparirebbero. Ad esempio, se si potesse dire, strong typedef std::string unsafe_string;per introdurre un nuovo tipo unsafe_stringche non può essere convertito in std :: string (e quindi potrebbe partecipare alla risoluzione dell'overload, ecc. Ecc.), Allora non avremmo bisogno di prefissi stupidi.

Quindi, l'affermazione centrale che l'ungherese è per cose che non sono tipi è sbagliata. Viene utilizzato per le informazioni sul tipo. Informazioni di tipo più ricche rispetto alle tradizionali informazioni di tipo C, certamente; sono informazioni sul tipo che codificano una sorta di dettaglio semantico per indicare lo scopo degli oggetti. Ma sono ancora informazioni sul tipo e la soluzione corretta è sempre stata codificarle nel sistema di tipi. Codificarlo nel sistema di tipi è di gran lunga il modo migliore per ottenere una corretta convalida e applicazione delle regole. I nomi delle variabili semplicemente non tagliano la senape.

In altre parole, l'obiettivo non dovrebbe essere quello di "far sembrare sbagliato il codice sbagliato allo sviluppatore". Dovrebbe essere "fare in modo che il codice sbagliato sembri sbagliato per il compilatore ".


30
L'intento della variabile dovrebbe essere codificato all'interno del tipo della variabile, non lasciato a qualcosa di così fragile come un fottuto schema di denominazione.
DrPizza

3
Mi piacerebbe che fosse anche il compito del compilatore / interprete, ma ciò comporterebbe un enorme sovraccarico per i linguaggi dinamici (Python, Ruby, PHP o Javascript).
troppo php

22
"Ciò che manca alla maggior parte delle lingue, tuttavia, è un sistema di tipi sufficientemente espressivo per applicare questo tipo di distinzioni" E qui sta il problema. AppsHungarian è un metodo pragmatico per evidenziare i problemi quando si utilizzano questi linguaggi in modo ovvio per i programmatori che visualizzano il codice, piuttosto che esaminare le segnalazioni di bug.
Neil Trodden,

6
@DrPizza: credo che tu abbia perso uno dei punti molto importanti che Joel sta facendo mentre sostiene le app ungheresi: questa notazione è solo un compromesso molto pragmatico . Rendere il compilatore in grado di vedere "codice sbagliato" è un grande obiettivo, ma ne vale sempre la pena?
Yarik

4
@DrPizza: Joel is wronge What most languages lack, however, is a type system that's expressive enough to enforce these kind of distinctions.così, dal momento che la maggior parte delle lingue non manca la sufficiente espressività per far rispettare questo tipo di distinzioni, Joel è giusto. Destra?
sampathsris

46

Penso che ingombra enormemente il codice sorgente.

Inoltre non ti guadagna molto in un linguaggio fortemente digitato. Se esegui una qualsiasi forma di tipo mismatch tomfoolery, il compilatore te lo dirà.


Wow. 90 ripetizioni in 15 minuti. Ottima scelta.
Dustman

2
Se lo usi per il tipo, allora sì, è inutile. È utile fornire altre informazioni.
Lou Franco

12
@Lou, esattamente - personalmente, memorizzo una cronologia delle revisioni nei miei nomi di variabile: string firstName_wasName_wasNameID_wasSweetCupinCakes
Shog9

@nsander: prova a utilizzare il compilatore per verificare se hai utilizzato le stesse unità di misura quando entrambi i tipi di variabili sono interi.
Igor Levicki

1
@ Shog9: Penso che tu non abbia capito la notazione ungherese di Apps. Si tratta più di sFirstName vs unFirstName (sicuro vs non sicuro, non sanificato), in questo modo ne sai qualcosa di più. Tuttavia penso che nei linguaggi statici sia meglio sottotipo String per rendere UnsafeString e SafeString e consentire solo l'output di SafeString. La convenzione va bene, ma (più spesso) l'applicazione della compilation è migliore.
kgadek

28

La notazione ungherese ha senso solo nelle lingue senza tipi definiti dall'utente . In un moderno linguaggio funzionale o OO, codifichereste le informazioni sul "tipo" di valore nel tipo di dati o nella classe piuttosto che nel nome della variabile.

Diverse risposte fanno riferimento all'articolo di Joels . Si noti tuttavia che il suo esempio è in VBScript, che non supportava le classi definite dall'utente (almeno per molto tempo). In una lingua con tipi definiti dall'utente si risolverà lo stesso problema creando un tipo HtmlEncodedString e quindi lasciare che il metodo Write accetti solo quello. In un linguaggio tipizzato staticamente, il compilatore rileverà eventuali errori di codifica, in un linguaggio tipizzato dinamicamente otterresti un'eccezione di runtime - ma in ogni caso sei protetto dalla scrittura di stringhe non codificate. Le notazioni ungheresi trasformano semplicemente il programmatore in un controllore umano del tipo, con questo tipo di lavoro che è tipicamente gestito meglio dal software.

Joel distingue tra "sistemi ungheresi" e "app ungheresi", dove "sistemi ungheresi" codifica i tipi incorporati come int, float e così via, e "app ungheresi" codifica "tipi", che sono meta-informazioni di livello superiore sulle variabili al di là del tipo di macchina, In un linguaggio funzionale moderno o OO puoi creare tipi definiti dall'utente, quindi non c'è distinzione tra tipo e "tipo" in questo senso - entrambi possono essere rappresentati dal sistema di tipi - e "app" l'ungherese è ridondante quanto l'ungherese dei "sistemi".

Quindi, per rispondere alla tua domanda: i sistemi ungheresi sarebbero utili solo in un linguaggio non sicuro e debolmente tipizzato dove, ad esempio, l'assegnazione di un valore float a una variabile int manderà in crash il sistema. La notazione ungherese è stata specificamente inventata negli anni Sessanta per essere utilizzata in BCPL , un linguaggio di livello piuttosto basso che non effettuava alcun controllo del tipo. Non penso che nessun linguaggio in uso generale oggi abbia questo problema, ma la notazione è vissuta come una sorta di programmazione cult del carico .

Le app ungheresi avranno senso se lavori con un linguaggio senza tipi definiti dall'utente, come VBScript legacy o le prime versioni di VB. Forse anche le prime versioni di Perl e PHP. Di nuovo, usarlo in un linguaggio moderno è puro culto del carico.

In qualsiasi altra lingua, l'ungherese è semplicemente brutto, ridondante e fragile. Ripete informazioni già note dal sistema di tipi e non dovresti ripetere te stesso . Utilizza un nome descrittivo per la variabile che descrive lo scopo di questa specifica istanza del tipo. Usa il sistema di tipi per codificare invarianti e meta informazioni su "tipi" o "classi" di variabili, ad es. tipi.

Il punto generale dell'articolo di Joels - far sembrare sbagliato il codice sbagliato - è un ottimo principio. Tuttavia, una protezione ancora migliore contro i bug è, quando possibile, avere un codice errato da rilevare automaticamente dal compilatore.


Le lingue con tipi definiti dall'utente non rendono sempre pratico l'uso di tipi invece di "tipi". Considera i prefissi "c", "d", "ix" di Joel's Apps Hungarian. Usi tipi interi personalizzati per quelli, in tutte le lingue moderne? Non credo proprio. Perché i linguaggi moderni non hanno ancora tipi interi personalizzati incorporati per indici, conteggi e differenze tra due numeri. Finché utilizzeremo ancora int vaniglia, Apps ungherese sarà non ridondante e utile.
Enigma di Eldritch

27

Uso sempre la notazione ungherese per tutti i miei progetti. Lo trovo davvero utile quando ho a che fare con centinaia di nomi di identificatori diversi.

Ad esempio, quando chiamo una funzione che richiede una stringa posso digitare 's' e premere control-space e il mio IDE mi mostrerà esattamente i nomi delle variabili con prefisso 's'.

Un altro vantaggio, quando prefisso u per unsigned e i per signed ints, vedo immediatamente dove sto mescolando firmato e non firmato in modi potenzialmente pericolosi.

Non riesco a ricordare il numero di volte in cui in un'enorme base di codice da 75000 righe, i bug sono stati causati (da me e anche da altri) a causa della denominazione delle variabili locali allo stesso modo delle variabili membri esistenti di quella classe. Da allora, ho sempre aggiunto ai membri il prefisso "m_"

È una questione di gusto ed esperienza. Non picchiarlo finché non lo hai provato.


1
La codifica della segnatura in nomi di variabili è ottima quando il pezzo di codice ha a che fare con la firma. Usarlo come scusa per far rispettare la convenzione per tutte le variabili è solo domatismo IMHO.
Plumenator

Tuttavia, hai un buon punto con le variabili membro. Ma in linguaggi come Python dove sei costretto a qualificare i membri con il sé / questo oggetto è discutibile.
Plumenator

È solo un trucco per aiutare la produttività. Proprio come il completamento automatico IDE. Non c'è niente di fondamentalmente malvagio in questo. Credo che ai programmatori esperti debba essere consentito di usare il proprio stile. Costringere qualcuno a scegliere un certo stile è un male. Ora lavoro come sviluppatore singolo, ma non imporrei uno stile a nessuno con cui ho lavorato a meno che non mancasse di uno stile coerente in primo luogo.
rep_movsd

Quindi stai usando la convenzione di denominazione per filtrare le variabili, eh? Devo ammettere che è abbastanza intelligente . :-) Tuttavia, per come sono cablato, il punto di ancoraggio (o il criterio del filtro, se vuoi) è sempre la semantica per me. Raramente il tipo (a meno che non sia la semantica). Spero che abbia senso. TL; DR: Continuerei a nominare le variabili in base a ciò che rappresentano rispetto a come sono rappresentate.
Plumenator

1
Allora ho votato al rialzo perché ero a favore dell'ungherese. Ora me ne pento e non tornerei mai a inserire un prefisso in una variabile ..
nawfal

22

Stai dimenticando il motivo numero uno per includere queste informazioni. Non ha niente a che fare con te, il programmatore. Ha tutto a che fare con la persona che scende per la strada 2 o 3 anni dopo aver lasciato l'azienda che deve leggere quella roba.

Sì, un IDE identificherà rapidamente i tipi per te. Tuttavia, quando stai leggendo alcuni lunghi lotti di codice di "regole aziendali", è bello non dover fermarsi su ciascuna variabile per scoprire di che tipo è. Quando vedo cose come strUserID, intProduct o guiProductID, rende molto più semplice il tempo di " accelerazione ".

Sono d'accordo sul fatto che MS si sia spinto troppo oltre con alcune delle loro convenzioni di denominazione - lo classifico nella pila "troppo di una cosa buona".

Le convenzioni di denominazione sono buone cose, a patto di rispettarle. Ho esaminato abbastanza codice vecchio che mi ha fatto tornare costantemente a guardare le definizioni per così tante variabili con nomi simili che ho premuto "camel case" (come era stato chiamato in un lavoro precedente). In questo momento ho un lavoro che ha molte migliaia di righe di codice ASP classico completamente non commentato con VBScript ed è un incubo cercare di capire le cose.


Come utente VIM (no IDE, no highlighting, no hover-tell-you-what-type) non capisco affatto questo argomento. Capisco naturalmente che una variabile chiamata nome è una stringa e una variabile chiamata i o count è un int. Uno ha davvero bisogno di sName e iCount? Come aiuta davvero? Direi che il tuo esempio di ID prodotto è un caso speciale, e forse lì andrebbe bene. Ma anche in questo caso, essere coerenti e rappresentare gli ID prodotto con int o stringhe ovunque sarebbe una soluzione molto migliore, no? L'intera questione dei nomi sembra una scappatoia.
MrFox

6
È per coerenza. Sì, "nome" implica intrinsecamente una stringa. Ma cosa presumeresti che sia "userid"? UN GUID? Corda? Numero intero? Anche qualcosa come "acctno" potrebbe avere un valore di 42 o "23X". La documentazione è abbastanza scarsa nella maggior parte del codice. Questo standard aiuta un po 'il programmatore di manutenzione.
David

1
@David Sono assolutamente d'accordo con la tua risposta: conoscere a colpo d'occhio l'intento della variabile è il motivo per cui preferisco anche il prefisso, soprattutto in un linguaggio dinamico come JS.
Daniel Sokolowski

10

Contrastare caratteri criptici all'inizio di ogni nome di variabile non è necessario e mostra che il nome della variabile di per sé non è sufficientemente descrittivo. La maggior parte delle lingue richiede comunque il tipo di variabile al momento della dichiarazione, in modo che le informazioni siano già disponibili.

C'è anche la situazione in cui, durante la manutenzione, è necessario cambiare un tipo di variabile. Esempio: se una variabile dichiarata come "uint_16 u16foo" deve diventare una senza segno a 64 bit, accadrà una delle due cose:

  1. Passerai attraverso e cambierai il nome di ogni variabile (assicurandoti di non utilizzare variabili non correlate con lo stesso nome), o
  2. Basta cambiare il tipo e non cambiare il nome, il che causerà solo confusione.

9

Joel Spolsky ha scritto un buon post sul blog su questo. http://www.joelonsoftware.com/articles/Wrong.html Fondamentalmente si tratta di non rendere il tuo codice più difficile da leggere quando un IDE decente ti dirà che vuoi digitare la variabile è se non ricordi. Inoltre, se rendi il tuo codice abbastanza suddiviso in compartimenti, non devi ricordare quale variabile è stata dichiarata come tre pagine in su.


9

L'ambito non è più importante del tipo di questi tempi, ad es

* l for local
* a for argument
* m for member
* g for global
* etc

Con le moderne tecniche di refactoring del vecchio codice, la ricerca e la sostituzione di un simbolo perché ne hai cambiato il tipo è noioso, il compilatore rileverà i cambiamenti di tipo, ma spesso non rileverà un uso errato dell'ambito, convenzioni di denominazione ragionevoli aiutano qui.


Inoltre, il codice probabilmente non dovrebbe dipendere così tanto dall'ambito. :-)
Plumenator

8

Non c'è motivo per cui non dovresti fare un uso corretto della notazione ungherese. La sua impopolarità è dovuta a una lunga reazione contro l' uso improprio della notazione ungherese, specialmente nelle API di Windows.

Ai vecchi tempi, prima che esistesse qualcosa di simile a un IDE per DOS (le probabilità sono che non avessi abbastanza memoria libera per eseguire il compilatore sotto Windows, quindi il tuo sviluppo era fatto in DOS), non hai ricevuto alcun aiuto da passando il mouse su un nome di variabile. (Supponendo che tu avessi un mouse.) Quello che dovevi affrontare erano le funzioni di callback degli eventi in cui tutto ti veniva passato come int a 16 bit (WORD) o int a 32 bit (LONG WORD). Quindi era necessario eseguire il cast di tali parametri sui tipi appropriati per il tipo di evento specificato. In effetti, gran parte dell'API era praticamente priva di tipo.

Il risultato, un'API con nomi di parametri come questi:

LRESULT CALLBACK WindowProc(HWND hwnd,
                            UINT uMsg,
                            WPARAM wParam,
                            LPARAM lParam);

Nota che i nomi wParam e lParam, sebbene piuttosto orribili, non sono davvero peggio che nominarli param1 e param2.

A peggiorare le cose, Windows 3.0 / 3.1 aveva due tipi di puntatori, vicino e lontano. Quindi, ad esempio, il valore restituito dalla funzione di gestione della memoria LocalLock era un PVOID, ma il valore restituito da GlobalLock era un LPVOID (con la "L" a lungo). Quella notazione terribile poi si esteso in modo che un l ong p ointer stringa è stata preceduta lp , per distinguerla da una stringa che era stato semplicemente malloc'd.

Non sorprende che ci sia stata una reazione contro questo genere di cose.


6

La notazione ungherese può essere utile nelle lingue senza il controllo del tipo in fase di compilazione, poiché consentirebbe allo sviluppatore di ricordare rapidamente a se stesso come viene utilizzata la particolare variabile. Non fa nulla per le prestazioni o il comportamento. Dovrebbe migliorare la leggibilità del codice ed è principalmente una questione di gusto e stile di codifica. Proprio per questo motivo è criticato da molti sviluppatori: non tutti hanno lo stesso cablaggio nel cervello.

Per i linguaggi di controllo del tipo in fase di compilazione è per lo più inutile: scorrere verso l'alto di poche righe dovrebbe rivelare la dichiarazione e quindi digitare. Se le variabili globali o il blocco di codice si estende per più di una schermata, hai gravi problemi di progettazione e riusabilità. Quindi una delle critiche è che la notazione ungherese consente agli sviluppatori di avere un cattivo design e di farla franca facilmente. Questo è probabilmente uno dei motivi per odiare.

D'altra parte, ci possono essere casi in cui anche i linguaggi di controllo del tipo in fase di compilazione trarrebbero vantaggio dalla notazione ungherese - puntatori vuoti o HANDLE nell'API win32. Ciò offusca il tipo di dati effettivo e potrebbe essere opportuno utilizzare la notazione ungherese lì. Tuttavia, se si può conoscere il tipo di dati in fase di compilazione, perché non utilizzare il tipo di dati appropriato.

In generale, non ci sono validi motivi per non utilizzare la notazione ungherese. È una questione di like, politiche e stile di codifica.


6

Come programmatore Python, la notazione ungherese cade a pezzi abbastanza velocemente. In Python, non mi interessa se qualcosa è una stringa - mi interessa se può agire come una stringa (cioè se ha un ___str___()metodo che restituisce una stringa).

Ad esempio, supponiamo di avere foo come numero intero, 12

foo = 12

La notazione ungherese ci dice che dovremmo chiamarlo iFoo o qualcosa del genere, per denotare che è un numero intero, in modo che in seguito sappiamo di cosa si tratta. Tranne che in Python, non funziona, o meglio, non ha senso. In Python, decido quale tipo voglio quando lo uso. Voglio una stringa? bene se faccio qualcosa del genere:

print "The current value of foo is %s" % foo

Nota la %sstringa -. Foo non è una stringa, ma l' %operatore chiamerà foo.___str___()e utilizzerà il risultato (supponendo che esista). fooè ancora un numero intero, ma lo trattiamo come una stringa se vogliamo una stringa. Se vogliamo un galleggiante, lo trattiamo come un galleggiante. In linguaggi tipizzati dinamicamente come Python, la notazione ungherese è inutile, perché non importa di che tipo sia qualcosa finché non lo usi, e se hai bisogno di un tipo specifico, assicurati di trasmetterlo a quel tipo (ad esempio float(foo)) quando lo fai usalo.

Nota che i linguaggi dinamici come PHP non hanno questo vantaggio: PHP cerca di fare "la cosa giusta" in background sulla base di un oscuro insieme di regole che quasi nessuno ha memorizzato, il che spesso si traduce in disastri catastrofici inaspettatamente. In questo caso, una sorta di meccanismo di denominazione, come $files_counto $file_name, può essere utile.

A mio avviso, la notazione ungherese è come le sanguisughe. Forse in passato erano utili, o almeno sembravano utili, ma al giorno d'oggi è solo un sacco di battitura in più per non molti benefici.


È interessante notare che il tuo esempio con .str () in Python non è il risultato della dinamica del linguaggio. Java, decisamente non un linguaggio dinamico, fa la stessa cosa.
Dustman

Anche C # fa la stessa cosa, ogni classe nella lingua implementa in .ToString()modo che tutto possa essere stampato
Electric Coffee

5

L'IDE dovrebbe fornire queste informazioni utili. L'ungherese avrebbe potuto avere una sorta (non molto, ma una sorta) di senso quando gli IDE erano molto meno avanzati.


4
Poi di nuovo, non dovresti fare affidamento sull'IDE che ti dice di più. Dopotutto, il codice può essere visualizzato al di fuori dell'IDE ...
TraumaPony,

5

Apps Ungherese per me è greco, in senso positivo

Come ingegnere, non come programmatore, ho subito preso visione dell'articolo di Joel sui meriti di Apps Hungarian: "Far sembrare sbagliato il codice sbagliato" . Mi piacciono le app ungheresi perché imitano il modo in cui l'ingegneria, la scienza e la matematica rappresentano equazioni e formule utilizzando simboli sotto e super script (come lettere greche, operatori matematici, ecc.). Prendiamo un esempio particolare della legge di gravità universale di Newton : prima nella notazione matematica standard e poi nello pseudo codice ungherese di Apps:

Legge di gravità universale di Newton per Terra e Marte

frcGravityEarthMars = G * massEarth * massMars / norm(posEarth - posMars)

Nella notazione matematica, i simboli più importanti sono quelli che rappresentano il tipo di informazione memorizzata nella variabile: forza, massa, vettore di posizione, ecc. I pedici giocano il secondo violino per chiarire: posizione di cosa? Questo è esattamente ciò che sta facendo Apps Hungarian; ti dice prima il tipo di cosa memorizzata nella variabile e poi entra nello specifico: il codice più vicino può arrivare alla notazione matematica.

Chiaramente una digitazione forte può risolvere l'esempio di stringa sicura o non sicura dal saggio di Joel, ma non definiresti tipi separati per i vettori di posizione e di velocità; entrambi sono doppi array di dimensione tre e tutto ciò che è probabile che tu faccia con uno potrebbe applicarsi all'altro. Inoltre, ha perfettamente senso concatenare posizione e velocità (per creare un vettore di stato) o prendere il loro prodotto scalare, ma probabilmente non aggiungerli. In che modo la digitazione consentirebbe i primi due e proibirebbe il secondo, e in che modo un tale sistema si estenderebbe a ogni possibile operazione che potresti voler proteggere? A meno che tu non sia disposto a codificare tutta la matematica e la fisica nel tuo sistema di battitura.

Inoltre, molta ingegneria viene eseguita in linguaggi di alto livello debolmente tipizzati come Matlab o vecchi come Fortran 77 o Ada.

Quindi, se hai un linguaggio stravagante e IDE e app ungherese non ti aiutano, dimenticalo - a quanto pare molte persone lo hanno fatto. Ma per me, peggio di un programmatore alle prime armi che lavora in linguaggi tipizzati in modo debole o dinamico, posso scrivere codice migliore più velocemente con le app ungheresi che senza.


4

È incredibilmente ridondante e inutile sono gli IDE più moderni, dove fanno un buon lavoro nel rendere evidente il tipo.

Inoltre, per me, è solo fastidioso vedere intI, strUserName, ecc. :)


3
Come ha detto TraumaPony a Paul Batum, non tutti vedono il codice nell'IDE.
Chris Charabaruk,

4

Se sento che vengono fornite informazioni utili, perché non dovrei metterle proprio lì dove sono disponibili?

Allora a chi importa cosa pensano gli altri? Se lo trovi utile, usa la notazione.


Perché solo uno di me e un miliardo di altre persone potrebbero mantenere il mio codice in seguito. Dato che tutte quelle persone fanno parte del team (ma ancora non lo sanno), mi piacerebbe avere qualche idea se mi superassero.
Dustman

4

Im la mia esperienza, è brutta perché:

1 - quindi interrompi tutto il codice se devi cambiare il tipo di una variabile (cioè se devi estendere un intero a 32 bit a un intero a 64 bit);

2 - questa è un'informazione inutile poiché il tipo è già nella dichiarazione o si utilizza un linguaggio dinamico in cui il tipo effettivo non dovrebbe essere così importante in primo luogo.

Inoltre, con un linguaggio che accetta la programmazione generica (cioè funzioni in cui il tipo di alcune variabili non è determinato quando scrivi la funzione) o con un sistema di digitazione dinamico (cioè quando il tipo non è nemmeno determinato in fase di compilazione), come chiameresti il ​​tuo variabili? E la maggior parte delle lingue moderne supporta l'una o l'altra, anche se in forma ristretta.


4

In Making Wrong Code Look Wrong di Joel Spolsky spiega che ciò che tutti pensano come notazione ungherese (che chiama ungherese di sistema) non è ciò che doveva essere realmente (ciò che chiama app ungheresi). Scorri verso il basso fino all'intestazione I'm Hungary per vedere questa discussione.

Fondamentalmente, i sistemi ungheresi sono inutili. Ti dice solo la stessa cosa che ti diranno il tuo compilatore e / o IDE.

Apps Hungarian ti dice cosa dovrebbe significare la variabile e può effettivamente essere utile.


4

Ho sempre pensato che uno o due prefissi al posto giusto non avrebbero fatto male. Penso che se posso impartire qualcosa di utile, come "Ehi questa è un'interfaccia, non contare su un comportamento specifico" proprio lì, come in IEnumerable, dovrei farlo. Il commento può ingombrare le cose molto più di un semplice simbolo di uno o due caratteri.


1
Non ho mai avuto l'ISomethingable. Se è un -able, ciò implica comunque l'interfaccia. (Almeno in java)
tunaranch

4

È una convenzione utile per denominare i controlli in un form (btnOK, txtLastName ecc.), Se l'elenco dei controlli viene visualizzato in un elenco a discesa in ordine alfabetico nel tuo IDE.


4

Io tendo ad usare ungherese notazione con i controlli server ASP.NET solo , altrimenti mi trovo troppo difficile capire quali controlli sono ciò che sulla forma.

Prendi questo snippet di codice:

<asp:Label ID="lblFirstName" runat="server" Text="First Name" />
<asp:TextBox ID="txtFirstName" runat="server" />
<asp:RequiredFieldValidator ID="rfvFirstName" runat="server" ... />

Se qualcuno può mostrare un modo migliore per avere quella serie di nomi di controllo senza ungherese, sarei tentato di passare ad esso.


4

L'articolo di Joel è fantastico, ma sembra omettere un punto importante:

L'ungherese rende una particolare "idea" (tipo + nome identificativo) univoca, o quasi univoca, in tutta la base del codice, anche una base del codice molto grande.

È enorme per la manutenzione del codice. Significa che puoi usare una buona vecchia ricerca di testo su una sola riga (grep, findstr, 'trova in tutti i file') per trovare OGNI menzione di quella 'idea'.

Perché è così importante quando abbiamo IDE che sanno come leggere il codice? Perché non sono ancora molto bravi. Questo è difficile da vedere in un codebase piccolo, ma ovvio in uno grande - quando l '"idea" potrebbe essere menzionata nei commenti, nei file XML, negli script Perl e anche in luoghi al di fuori del controllo del codice sorgente (documenti, wiki, database di bug).

Devi stare un po 'attento anche qui - ad esempio, l'incollaggio di token nelle macro C / C ++ può nascondere menzioni dell'identificatore. Tali casi possono essere affrontati utilizzando le convenzioni di codifica, e comunque tendono a interessare solo una minoranza degli identificatori nella codebase.

PS Fino al punto di usare il sistema di caratteri contro l'ungherese: è meglio usare entrambi. Hai solo bisogno di codice sbagliato per sembrare sbagliato se il compilatore non lo cattura per te. Ci sono molti casi in cui è impossibile fare in modo che il compilatore lo rilevi. Ma dove è possibile - sì, per favore fallo invece!

Quando si considera la fattibilità, tuttavia, considerare gli effetti negativi della divisione dei tipi. ad esempio in C #, il wrapping di 'int' con un tipo non incorporato ha enormi conseguenze. Quindi ha senso in alcune situazioni, ma non in tutte.


4

Sfatare i vantaggi della notazione ungherese

  • Fornisce un modo per distinguere le variabili.

Se il tipo è tutto ciò che distingue un valore da un altro, allora può essere solo per la conversione di un tipo in un altro. Se hai lo stesso valore che viene convertito tra i tipi, è probabile che dovresti farlo in una funzione dedicata alla conversione. (Ho visto gli avanzi di VB6 ungheresi utilizzare stringhe su tutti i parametri del metodo semplicemente perché non sono riusciti a capire come deserializzare un oggetto JSON o comprendere correttamente come dichiarare o utilizzare tipi nullable. ) Se si hanno due variabili distinte solo dal Prefisso ungherese, e non sono una conversione dall'uno all'altro, quindi è necessario elaborare la tua intenzione con loro.

  • Rende il codice più leggibile.

Ho scoperto che la notazione ungherese rende le persone pigre con i loro nomi di variabili. Hanno qualcosa per distinguerlo e non sentono il bisogno di elaborare il suo scopo. Questo è ciò che troverai tipicamente nel codice notificato ungherese rispetto al moderno: sSQL contro groupSelectSql ( o di solito nessun sSQL perché dovrebbero usare l'ORM che è stato inserito dagli sviluppatori precedenti. ), SValue contro formCollectionValue ( o di solito nemmeno sValue, perché si trovano in MVC e dovrebbero utilizzare le sue funzionalità di associazione di modelli ), sType vs. publishSource, ecc.

Non può essere leggibilità. Vedo più sTemp1, sTemp2 ... sTempN da qualsiasi VB6 ungherese rimasto di chiunque altro messo insieme.

  • Previene gli errori.

Ciò sarebbe in virtù del numero 2, che è falso.


3

Nelle parole del maestro:

http://www.joelonsoftware.com/articles/Wrong.html

Una lettura interessante, come al solito.

estratti:

"Qualcuno, da qualche parte, ha letto l'articolo di Simonyi, dove ha usato la parola" tipo ", e ha pensato che si riferisse al tipo, come classe, come in un sistema di tipi, come il controllo del tipo che fa il compilatore. Non lo fece. Spiegò molto attentamente esattamente quello che intendeva con la parola "tipo", ma non ha aiutato. Il danno è stato fatto. "

"Ma c'è ancora un enorme valore per Apps Hungarian, in quanto aumenta la collocazione nel codice, il che rende il codice più facile da leggere, scrivere, eseguire il debug e mantenere e, soprattutto, fa sembrare sbagliato il codice sbagliato."

Assicurati di avere un po 'di tempo prima di leggere Joel On Software. :)


Non c'è tempo ora che ho Stackoverflow. Penso che la mera associazione di Spolsky al progetto debba farlo. :)
Dustman

3

Diverse ragioni:

  • Qualsiasi IDE moderno ti darà il tipo di variabile semplicemente passando il mouse sopra la variabile.
  • La maggior parte dei nomi dei tipi sono molto lunghi (si pensi a HttpClientRequestProvider ) per essere ragionevolmente usati come prefisso.
  • Le informazioni sul tipo non portano le informazioni corrette , si limitano a parafrasare la dichiarazione della variabile, invece di delineare lo scopo della variabile (si pensi a myInteger vs. pageSize ).

2

Non credo che tutti siano rabbiosamente contrari. Nelle lingue senza tipi statici, è piuttosto utile. Lo preferisco decisamente quando viene utilizzato per fornire informazioni che non sono già presenti nel tipo. Come in C, char * szName dice che la variabile farà riferimento a una stringa terminata da null - che non è implicito in char * - ovviamente, anche un typedef sarebbe d'aiuto.

Joel ha pubblicato un ottimo articolo sull'uso dell'ungherese per sapere se una variabile era codificata HTML o meno:

http://www.joelonsoftware.com/articles/Wrong.html

Ad ogni modo, tendo a non amare l'ungherese quando viene utilizzato per impartire informazioni che già conosco.


Penso che la prima frase potrebbe smentire le risposte su questa pagina.
Dustman

@Dustman Beh, non sai già che le stringhe C sono terminate con null? Vedo come sarebbe utile quando la stringa potrebbe non esserlo, ma è raro e quindi penso che l'uso della convenzione dovrebbe essere limitato a quei casi.
Plumenator

Non tutti i caratteri * sono una stringa c con terminazione nulla. Lo scopo dell'ungherese è usarlo per ogni variabile, anche quelle che rientrano nel caso comune. In definitiva, mi sento come te - e quindi non lo uso in C.
Lou Franco


2

Ho iniziato a scrivere codice più o meno all'incirca nel periodo in cui è stata inventata la notazione ungherese e la prima volta che sono stato costretto a usarla su un progetto l'ho odiata.

Dopo un po 'mi sono reso conto che quando è stato fatto correttamente ha effettivamente aiutato e in questi giorni lo adoro.

Ma come tutte le cose buone, deve essere appresa e compresa e per farlo correttamente richiede tempo.


1

La notazione ungherese è stata abusata, in particolare da Microsoft, portando a prefissi più lunghi del nome della variabile e mostrandola è piuttosto rigida, in particolare quando si cambiano i tipi (il famigerato lparam / wparam, di diverso tipo / dimensione in Win16, identico in Win32 ).

Pertanto, sia a causa di questo abuso, sia per il suo utilizzo da parte di M $, è stato ritenuto inutile.

Al mio lavoro, codifichiamo in Java, ma il fondatore proviene dal mondo MFC, quindi usa uno stile di codice simile (parentesi graffe allineate, mi piace !, maiuscole ai nomi dei metodi, ci sono abituato, prefisso come m_ ai membri della classe (campi ), s_ a membri statici, ecc.).

E hanno detto che tutte le variabili dovrebbero avere un prefisso che ne mostra il tipo (es. Un BufferedReader si chiama brData). Che si è rivelata una cattiva idea, poiché i tipi possono cambiare ma i nomi non seguono, oppure i programmatori non sono coerenti nell'uso di questi prefissi (vedo anche un buffer, il proxy, ecc.!).

Personalmente, ho scelto alcuni prefissi che trovo utili, il più importante è b per prefissare variabili booleane, in quanto sono gli unici in cui consento la sintassi like if (bVar)(nessun utilizzo dell'autocast di alcuni valori su true o false). Quando ho codificato in C, ho usato un prefisso per le variabili allocate con malloc, come promemoria dovrebbe essere liberato in seguito. Eccetera.

Quindi, fondamentalmente, non rifiuto questa notazione nel suo insieme, ma ho preso ciò che sembra adatto alle mie esigenze.
E, naturalmente, quando contribuisco a qualche progetto (lavoro, open source), uso semplicemente le convenzioni in atto!

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.