Teorema stergerii cu rest

Posted in Codare cu premeditare, Slagare internationale on April 13th, 2011 by Mihnea

Am stabilit deja ca lista inlantuita e un subiect delicat. Este timpul sa aratam ca nu doar Ovidiu “MVP” Cucu are probleme cu dinsa, ci si aia carora el le pupa bombeurile au mici dificultati in intelegerea acestei structuri de date fenomenal de complicate. Sa urmarim pentru inceput un scurt material motivational in care se incearca stergerea unei configuratii dintr-un proiect in Visual Studio 2008 (nu stiu de ce se misca in reluare, muie youtube sau muie ffdshow):

Asta e, nu s-a sters. Lucrurile devin insa cu 57% mai interesante daca incercam sa stergem mai multe configuratii deodata:

Acum s-a reusit stergerea, dar ar fi fost un pic mai bine daca ar fi sters ce i-am zis sa stearga, nu ce doream sa pastram (de asemenea gasesc interesant cum in dropdown a ramas selectat “Debug2011”, desi cind il deschizi nu e acolo). Care sa fie explicatia?

Pai e destul de simplu, de fapt. Proiectul are doua configuratii care se cheama Debug5, doua Debug6 si asa mai departe, cite una pentru fiecare platforma (Win32 si x64). Acest lucru se poate observa cu ochiul liber in vcproj, unde nu exista Debug5, ci Debug5|Win32 si Debug5|x64. Mai departe in arhitectura lui VS, o configuratie trebuie sa existe in toate platformele – nu poti, de exemplu, sa ai Debug5 doar in Win32. Orice programator care a folosit vreodata platforme multiple in VC stie asta. Indianul care a implementat stergerea nu stie. Cind apesi pe “Remove”, el cauta prima configuratie care se cheama “Debug5” si o rade. In felul asta se sterge doar aia de Win32, dar cind deschide din nou dropdown-ul, o gaseste p-aia de x64 si o afiseaza acolo, iar acum proiectul e intr-o stare invalida, cu o configuratie care nu exista in toate platformele. Workaround-ul este sa stergi o configuratie, sa inchizi dialogul de edit, sa-l deschizi din nou si s-o stergi inca o data. In felul asta se sterge si Debug5|x64, si proiectul e utilizabil din nou.

Daca te aventurezi sa stergi mai multe configuratii de-odata, ca in al doilea filmulet, se evidentiaza o noua latura a retardarii indiene, aceasta ruda karmica a retardarii ardelene. Boul sterge configuratiile dupa index, nu dupa nume. Daca stersul propriu-zis i-ar fi mers, asta n-ar fi fost o problema. Din pacate insa, deoarece configuratia ramine acolo cind se manifesta prima parte a incompetentei, se fut maparile intre indecsi si nume, asa ca atunci cind dai sa stergi Debug6, se sterge de fapt altceva (jumate de altceva, mai exact). Mai departe retardarea 1 se compune cu retardarea 2 intr-un fel sublim, astfel incit tu dai sa stergi 6 din cele 8 configuratii, dar de fapt se sterg doar 3, printre care si singurele doua pe care vroiai de fapt sa le pastrezi.

VC are acest bug de la 2005, de cind a fost introdus noul configuration manager, cu platforme si cacat. De atunci au iesit 2005 SP1, 2008, 2008 SP1 plus o intreaga pleiada de hotfix-uri, dar nimeni nu s-a ostenit sa invete cum functioneaza de fapt configuratiile si cum se cauta intr-o lista. Bug-ul s-a rezolvat in sfirsit in 2010, pacat ca ala e inutilizabil gratie rescrierii editorului in dotniet (plus alte “goodies”, gen gunoiul ala de MSBuild).

Sa trecem acum in tabara adversa. Aparent exista o corelatie intre retardare si softurile de instalat alte softuri. Cel mai idiot lucru scos vreodata de Microsoft este MSI (chiar luind in considerare Songsmith si reclama pentru el). Cel mai idiot lucru scos de Apple este PackageMaker, echivalentul hipsteristic al lui MSI. Iata ce face PackageMaker cind vrei sa stergi un target din installer:

Pentru asta n-am o explicatie, caci nu inteleg cum functioneaza mintea oamenilor care programeaza pentru Apple. Cert e ca atunci cind stergi ceva, reuseste sa amestece restul target-urilor si chiar sa lase un fisier orfan, atasindu-l de root-ul proiectului. As dori sa mentionez ca in mod normal n-ai cum sa atasezi fisiere direct acolo, folosind UI-ul lui.

Workaround-ul este sa editezi proiectul de mina, caci este tinut in XML. In XML-uri, mai exact. Cite 2 XML-uri pentru fiecare target, plus un XML mare, to rule them all (in speta, 71 de fisiere in proiectul din film). Si aceste XML-uri sint scrise pe o singura linie, cum mentionam in post-ul despre XCode. Si numele lor conteaza, fiind prefixate cu un numar. Si alea in care zici ca vrei sa instaleze tot ce-i intr-un director contin si numele fisierelor din directorul ala, la momentul la care ai facut proiectul. Care nu folosesc la nimic, pentru ca daca adaugi un nou fisier intre timp, se va copia, asa cum iti doresti, dar nu va fi trecut in XML. Si asa mai departe, in pula mea.

Ca sa fiu perfect obiectiv ar trebui sa expun si o muie dintr-un IDE de Linux. Gluma asta se scrie singura, va las pe voi sa va imaginati ce vreti.

Oricum, ce vroiam sa spun e ca le doresc epidermoliza buloasa alora care-s responsabili de chestiile astea. Sau munca silnica pe viata in mina cu Silviu Ardelean ca team leader.

Update: am elucidat si misterul PackageMaker. Si aici retardarea este usor de inteles: gunoiul are un index.xml in care, odata ce-l formatam sa nu mai fie tot pe o singura linie, putem vedea chestii de genul:

<choice title="8.5 plug-in" id="choice210">
	<pkgref id="com.nextlimit.realflowPluginForMaya.realflow.pkg"/>
</choice>
<choice title="2008 plug-in" id="choice211">
	<pkgref id="com.nextlimit.realflowPluginForMaya.realflow-1.pkg"/>
</choice>
<choice title="2009 plug-in" id="choice212">
	<pkgref id="com.nextlimit.realflowPluginForMaya.realflow-2.pkg"/>
</choice>

Mai jos in fisier scrie si:

<item type="file">01realflow.xml</item>
<item type="file">02realflow.xml</item>
<item type="file">03realflow.xml</item>

Observam deja un design fabulos, caci corespondenta dintre “choice-urile” alea si fisierele in care se spune ce contin se face pe baza ordinii. Nu s-a putut pune nodul ala de item sub nodul de choice, sau ceva. Mai departe, daca privim in 01realflow.xml, vedem ca e scris package name ala, ba chiar are si un UUID dupa care ar putea fi identificat:

<pkgref spec="1.12" uuid="A23E47A9-3AB3-4619-847F-2104601981F9">
	<config>
		<identifier>com.nextlimit.realflowPluginForMaya.realflow.pkg</identifier>

Atingerea de geniu este ca muistul tine package name-urile alea acolo doar de decor. De fapt el se asteapta ca in primul fisier sa fie definit intotdeauna pachetul “com.nextlimit.realflowPluginForMaya.realflow.pkg”, in al doilea sa fie ala cu -1 in coada, in al treilea ala cu -2 etc. Nu conteaza ce scrie de fapt in fisier, iar UUID-ul ala nu e folosit la nimic.

Deci ce se intimpla cind dai click dreapta remove? Pai simplu, indianul care a implementat functia de sters nu stie ca numele sint hardcodate. El sterge nodul din XML, sperind ca potriveala se va face dupa nume. Din cauza ca se face dupa ordine, totul aluneca cu o pozitie in jos, deci pachetul de 2009 ajunge in choice-ul de 2008, ala de 2010 in choice-ul de 2009 etc. Primul pachet ramine orfan, iar ultimul choice ramine gol.

Solutia e sa stergi de mina XML-urile corespunzatoare target-urilor de care vrei sa scapi, dupa care sa iei la rind toate XML-urile ramase si sa cirpesti package name-urile alea, ca sa fie consecutive. Apropo, nu eu am dat numele alea care-s toate la fel, sint generate de el pe baza numelor fisierelor din target-uri, iar daca le schimbi se fute.

Uimitor. Fabulos. Nici la scoala ajutatoare nu vezi asemenea “design”. Ala care a facut cacatul asta n-a inteles nimic din programare.

Cum ziceam, epidermoliza buloasa.

Tags: , , , , , , , , , , , , , ,