
După cum se spune, dacă nu vă este rușine cu vechiul cod, atunci nu creșteți ca programator - și sunt de acord cu această opinie. Am început să programez pentru distracție acum peste 40 de ani și profesional acum 30 de ani, așa că am multe greșeli. o mulțime de. Ca profesor de informatică, îmi învăț elevii să învețe din greșelile lor, ale mele și ale altora. Cred că este timpul să vorbesc despre greșelile mele pentru a nu-mi pierde modestia. Sper că vor fi de folos cuiva.
Locul al treilea - compilatorul Microsoft C
Profesorul meu de școală credea că Romeo și Julieta nu pot fi considerate o tragedie pentru că personajele nu aveau nicio vină tragică - pur și simplu s-au comportat prost, așa cum ar trebui adolescenții. Nu eram de acord cu el atunci, dar acum văd un sâmbure de raționalitate în opinia lui, mai ales în legătură cu programarea.
Când mi-am terminat al doilea an la MIT, eram tânăr și fără experiență, atât în viață, cât și în programare. Vara, am făcut stagiar la Microsoft, în echipa de compilatori C. La început, am făcut lucruri de rutină, cum ar fi suport pentru profilare, iar apoi mi s-a încredințat să lucrez la cea mai distractivă parte a compilatorului (cum credeam) - optimizarea backend-ului. În special, a trebuit să îmbunătățesc codul x86 pentru declarațiile de ramuri.
Hotărât să scriu codul optim de mașină pentru fiecare caz posibil, m-am aruncat în piscină. Dacă densitatea de distribuție a valorilor era mare, le-am introdus . Dacă aveau un divizor comun, l-am folosit pentru a strânge masa (dar numai dacă împărțirea se putea face folosind ). Când toate valorile erau puteri de două, am făcut o altă optimizare. Dacă un set de valori nu mi-a îndeplinit condițiile, l-am împărțit în mai multe cazuri optimizabile și am folosit codul deja optimizat.
A fost un coșmar. Mulți ani mai târziu, mi s-a spus că programatorul care a moștenit codul meu mă ura.

Lecții învățate
După cum scriu David Patterson și John Hennessy în Computer Architecture and Computer Systems Design, unul dintre principiile principale ale arhitecturii și designului este de a face lucrurile să funcționeze cât mai repede posibil.
Accelerarea cazurilor obișnuite va îmbunătăți performanța mai eficient decât optimizarea cazurilor rare. În mod ironic, cazurile comune sunt adesea mai simple decât cele rare. Acest sfat logic presupune că știți care caz este considerat obișnuit - și acest lucru este posibil doar printr-un proces de testare și măsurare atentă.
În apărarea mea, am încercat să-mi dau seama cum arată declarațiile de ramuri în practică (cum ar fi câte ramuri erau și cum erau distribuite constantele), dar în 1988 aceste informații nu erau disponibile. Cu toate acestea, nu ar fi trebuit să adaug cazuri speciale atunci când compilatorul actual nu a putut genera cod optim pentru exemplul artificial cu care am venit.
Trebuia să sun un dezvoltator cu experiență și, împreună cu el, să mă gândesc care sunt cazurile obișnuite și să mă ocup de ele în mod specific. Aș scrie mai puțin cod, dar asta e un lucru bun. După cum a scris fondatorul Stack Overflow, Jeff Atwood, cel mai mare dușman al unui programator este programatorul însuși:
Știu că ai cele mai bune intenții, la fel ca noi toți. Creăm programe și ne place să scriem cod. Așa suntem făcuți. Credem că orice problemă poate fi rezolvată cu bandă adezivă, o cârjă de casă și un vârf de cod. Oricât de mult îi dă pe programatori să recunoască, cel mai bun cod este codul care nu există. Fiecare linie nouă are nevoie de depanare și suport, trebuie înțeleasă. Când adăugați cod nou, ar trebui să faceți acest lucru cu reticență și dezgust, deoarece toate celelalte opțiuni au fost epuizate. Mulți programatori scriu prea mult cod, făcându-l inamicul nostru.
Dacă aș fi scris un cod mai simplu care acoperă cazuri obișnuite, ar fi fost mult mai ușor de actualizat dacă era necesar. Am lăsat în urmă o mizerie cu care nimeni nu voia să se ocupe.

Locul al doilea: publicitate pe rețelele de socializare
Când lucram la Google pe reclame pe rețelele sociale (vă amintiți Myspace?), am scris ceva de genul acesta în C++:
for (int i = 0; i < user->interests->length(); i++) {
for (int j = 0; j < user->interests(i)->keywords.length(); j++) {
keywords->add(user->interests(i)->keywords(i)) {
}
}Programatorii pot vedea imediat eroarea: ultimul argument ar trebui să fie j, nu i. Testarea unitară nu a dezvăluit eroarea și nici recenzentul meu. Lansarea a fost efectuată și, într-o noapte, codul meu a mers pe server și a prăbușit toate computerele din centrul de date.
Nu sa întâmplat nimic rău. Nimic nu s-a stricat pentru nimeni, deoarece înainte de lansarea globală codul a fost testat într-un singur centru de date. Cu excepția cazului în care inginerii SRE au încetat să joace biliard pentru o vreme și au făcut un mic rollback. A doua zi dimineață am primit un e-mail cu un dump de blocare, am corectat codul și am adăugat teste unitare care ar detecta eroarea. Din moment ce am urmat protocolul - altfel codul meu pur și simplu nu ar rula - nu au existat alte probleme.

Lecții învățate
Mulți sunt siguri că o astfel de greșeală majoră va costa cu siguranță concedierea vinovatului, dar nu este așa: în primul rând, toți programatorii greșesc și, în al doilea rând, rareori fac aceeași greșeală de două ori.
De fapt, am un prieten programator care a fost un inginer genial și a fost concediat pentru că a făcut o singură greșeală. După aceea, a fost angajat la Google (și în curând promovat) - a vorbit sincer despre greșeala pe care a făcut-o într-un interviu și nu a fost considerată fatală.
Asta e ceea ce despre Thomas Watson, legendarul șef al IBM:
A fost anunțată un ordin guvernamental în valoare de aproximativ un milion de dolari. IBM Corporation - sau mai degrabă, Thomas Watson Sr. personal - a vrut cu adevărat să-l obțină. Din păcate, reprezentantul de vânzări nu a putut face acest lucru, iar IBM a pierdut oferta. A doua zi, acest angajat a intrat în biroul domnului Watson și a pus un plic pe birou. Domnul Watson nici nu s-a obosit să se uite la asta – aștepta un angajat și știa că este o scrisoare de demisie.
Watson a întrebat ce a mers prost.
Reprezentantul de vânzări a vorbit în detaliu despre evoluția licitației. El a numit greșelile făcute care ar fi putut fi evitate. În cele din urmă, a spus: „Dle Watson, vă mulțumesc că m-ați lăsat să explic. Știu cât de mult aveam nevoie de această comandă. Știu cât de important a fost”, și s-a pregătit să plece.
Watson s-a apropiat de el la ușă, l-a privit în ochi și i-a întors plicul cu cuvintele: „Cum pot să te las să pleci? Tocmai am investit un milion de dolari în educația ta.
Am un tricou pe care scrie: „Dacă înveți cu adevărat din greșeli, atunci sunt deja un maestru.” De fapt, când vine vorba de erori, sunt doctor în științe.
Primul loc: API-ul App Inventor
Erorile cu adevărat îngrozitoare afectează un număr mare de utilizatori, devin de cunoștință publică, durează mult timp pentru a fi corectate și sunt făcute de cei care nu ar fi putut să le facă. Cea mai mare greșeală a mea se potrivește tuturor acestor criterii.
Cu cât mai rău, cu atât mai bine
Citesc despre această abordare în anii nouăzeci ca student absolvent și îmi place atât de mult încât o întreb studenților mei. Dacă nu-ți amintești bine, împrospătează-ți memoria, e mic. Acest eseu contrastează dorința de a „a face bine” și abordarea „mai rău este mai bine” în multe feluri, inclusiv simplitatea.
Cum ar trebui să fie: designul ar trebui să fie simplu în implementare și interfață. Simplitatea interfeței este mai importantă decât simplitatea implementării.
Cu cât mai rău, cu atât mai bine: designul ar trebui să fie simplu în implementare și interfață. Simplitatea implementării este mai importantă decât simplitatea interfeței.
Să uităm de asta pentru un minut. Din păcate, am uitat de el de mulți ani.
Inventator de aplicații
În timp ce lucram la Google, am făcut parte din echipă , un mediu de dezvoltare online de tip drag-and-drop pentru începători Android-dezvoltatori. Era anul 2009 și ne grăbeam să lansăm versiunea alfa la timp, astfel încât să putem organiza ateliere pentru profesori în timpul verii, care ar putea apoi să utilizeze mediul în sălile lor de clasă în toamnă. M-am oferit voluntar să implementez sprite-uri, nostalgic pentru perioada în care scriam jocuri pe TI-99/4. Pentru cei care nu sunt familiarizați, un sprite este un obiect grafic bidimensional care se poate mișca și interacționa cu alte elemente software. Exemple de sprite-uri includ nave spațiale, asteroizi, mingi și palete.
Am implementat App Inventor orientat pe obiecte în Java, așa că există doar o grămadă de obiecte acolo. Deoarece bilele și sprite-urile se comportă foarte similar, am creat o clasă de sprite abstracte cu proprietăți (câmpuri) X, Y, Speed (viteză) și Heading (direcție). Aveau aceleași metode pentru detectarea coliziunilor, săritul de pe marginea ecranului etc.
Principala diferență dintre o minge și un sprite este ceea ce este desenat exact - un cerc umplut sau un raster. Deoarece am implementat mai întâi sprite-urile, era logic să specificăm coordonatele x și y din colțul din stânga sus al locului în care se afla imaginea.

Odată ce sprite-urile au funcționat, am decis că pot implementa obiecte bile cu foarte puțin cod. Singura problemă a fost că am luat calea cea mai simplă (din punctul de vedere al implementatorului), indicând coordonatele x și y ale colțului din stânga sus al conturului care încadrează mingea.

De fapt, a fost necesar să se indice coordonatele x și y ale centrului cercului, așa cum se învață în orice manual de matematică și în orice altă sursă care menționează cercuri.

Spre deosebire de greșelile mele din trecut, aceasta i-a afectat nu numai pe colegii mei, ci și milioane de utilizatori App Inventor. Mulți dintre ei erau copii sau complet noi în programare. Au fost nevoiți să efectueze o mulțime de pași inutile atunci când lucrau la fiecare aplicație în care era prezentă mingea. Dacă îmi amintesc celelalte greșeli în râs, atunci aceasta mă face să transpir și astăzi.
În cele din urmă, am corectat acest bug abia recent, zece ani mai târziu. „Corectat”, nu „remediat”, pentru că, așa cum spune Joshua Bloch, API-urile sunt eterne. În imposibilitatea de a face modificări care ar afecta programele existente, am adăugat proprietatea OriginAtCenter cu valoarea false în programele vechi și true în toate cele viitoare. Utilizatorii pot pune o întrebare logică: cine s-a gândit chiar să plaseze punctul de plecare în altă parte decât în centru. La care? Pentru un programator care era prea leneș să creeze un API normal în urmă cu zece ani.
Lecții învățate
Când lucrați la API-uri (ceea ce aproape fiecare programator trebuie să facă uneori), ar trebui să urmați cele mai bune sfaturi prezentate în videoclipul lui Joshua Bloch ""sau :
- Un API vă poate aduce atât beneficii mari, cât și rău.. Un API bun creează clienți repetați. Cel rău devine coșmarul tău etern.
- API-urile publice, cum ar fi diamantele, durează pentru totdeauna. Dă totul: nu va mai exista niciodată o altă șansă de a face totul bine.
- Structurile API ar trebui să fie scurte — o pagină cu semnături și descrieri ale claselor și metodelor, care nu ocupă mai mult de un rând. Acest lucru vă va permite să restructurați cu ușurință API-ul dacă nu se dovedește perfect prima dată.
- Descrieți cazuri de utilizareînainte de a implementa API-ul sau chiar de a lucra la specificația acestuia. În acest fel, veți evita implementarea și specificarea unui API complet nefuncțional.
Dacă aș fi scris chiar și un scurt sinopsis cu un scenariu artificial, cel mai probabil aș fi identificat eroarea și aș fi corectat-o. Dacă nu, atunci unul dintre colegii mei cu siguranță ar face-o. Orice decizie care are consecințe de amploare trebuie gândită cel puțin o zi (acest lucru nu se aplică doar programării).
Titlul eseului lui Richard Gabriel, „Worrse Is Better”, se referă la avantajul care înseamnă să fii primul pe piață – chiar și cu un produs imperfect – în timp ce altcineva petrece o eternitate urmărind pe cel perfect. Reflectând la codul sprite-ului, îmi dau seama că nici nu a trebuit să scriu mai mult cod ca să-l înțeleg corect. Orice s-ar spune cineva, m-am înșelat grav.
Concluzie
Programatorii fac greșeli în fiecare zi, fie că scriu coduri cu erori sau nu doresc să încerce ceva care le va îmbunătăți abilitățile și productivitatea. Desigur, poți fi programator fără a face greșeli atât de grave ca mine. Dar este imposibil să devii un programator bun fără să-ți recunoști greșelile și să înveți din ele.
Întâlnesc constant studenți care simt că fac prea multe greșeli și, prin urmare, nu sunt tăiați pentru programare. Știu cât de comun este sindromul impostorului în IT. Sper că veți învăța lecțiile pe care le-am enumerat - dar amintiți-vă pe cea principală: fiecare dintre noi face greșeli - jenante, amuzante, groaznice. Voi fi surprins și supărat dacă pe viitor nu am suficient material pentru a continua articolul.
Sursa: www.habr.com
