Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Als er al iets anders moet worden gemeten dan lengte, dan is het unstructured cyclomatic complexity: die is afgeleid van het gebruik van goto's en andere ongestructureerde manieren van programmeren.
Vandaar de grens op 2x op het scherm, "maar liever niet natuurlijk".Grijze Vos schreef op dinsdag 16 oktober 2012 @ 20:19:
2 schermen? wat mij betreft mag dat enkel en alleen als het gaat om heel simpele maar verbose code, zoals mapping code van datamodel naar viewmodel oid. Normaliter ligt de grens toch wel bij 1 scherm voor 1 functie.
Dat is niet echt het punt, je mag er ook een getalletje aan hangen. Het idee is dat je iets wat niet in z'n geheel op je scherm past sowieso niet in 1x kan overzien. Dus als jij en jouw collega's allemaal de functie in 2x op het scherm kunnen zien, is het goed. En als je erover twijfelt of de functie te lang is: opsplitsensig69 schreef op dinsdag 16 oktober 2012 @ 21:05:
[...]
2 schermen zegt ook niks natuurlijk. Welke resolutie? Welk font size? Op mijn scherm wordt dat een flinke functie namelijk
Ach, bij mijn vorige opdracht zat ik regelmatig te wroeten in dispatcher-code van meer dan 1000 regels, waarbij de 'simpele' afhandeling direct in de dispatcher-functie stond. Allemaal handgeschreven, meeste cases voorzien van een break..., en elk (bijna) event stond in 3 functies
Maar als je bij de 'l' bent, moet je oppassen..oisyn schreef op dinsdag 16 oktober 2012 @ 19:34:
[...]
Dan nog steeds niet. Uiteraard is het tweede tellertje dan j. Of x en y.
Dan weet je niet of het I of l is.
Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.
Toch gek dat 'i' algemeen geaccepteerd is als index-variabele en dat er voor de rest dan gezeurd wordt over te korte variabelenamen die je niet kunt begrijpen.
Is er iemand die in zijn for-loopjes bewust een variabelenaam als "index" of "counter" gebruikt oid?
Als ik niet voor mezelf programmeer? Zeker wel. Over het algemeen gaan for-loopjes en whathaveyou wel met variabelen die ik specifiek benoem én documenteer om zodoende ook voor de andere geeks (ja het zijn allemaal geeks in het bedrijf waar ik werkDavio schreef op woensdag 17 oktober 2012 @ 08:56:
Keke.
Toch gek dat 'i' algemeen geaccepteerd is als index-variabele en dat er voor de rest dan gezeurd wordt over te korte variabelenamen die je niet kunt begrijpen.
Is er iemand die in zijn for-loopjes bewust een variabelenaam als "index" of "counter" gebruikt oid?
Er zijn diverse static code analysers die daar over vallen inderdaad en ik ben het daar wel mee eens.Davio schreef op woensdag 17 oktober 2012 @ 08:56:
Keke.
Toch gek dat 'i' algemeen geaccepteerd is als index-variabele en dat er voor de rest dan gezeurd wordt over te korte variabelenamen die je niet kunt begrijpen.
In for loopjes kun je binnen C99 in ieder geval beter geen gebruik maken van het woord index als variabele, omdat het mogelijk verwarring kan scheppen met de functie index.Is er iemand die in zijn for-loopjes bewust een variabelenaam als "index" of "counter" gebruikt oid?
Zelf gebruik ik altijd idx als index-counter bij enkelvoudige for-loopjes.
If money talks then I'm a mime
If time is money then I'm out of time
Zoals hierboven ook al genoemd wordt inderdaad, gebruik vaak 'idx' in enkele for loops. Vaker gebruik ik foreach, en dan is het zinvol om een enkelvoud de nemen van de naam waarover je loopt. Bijvoorbeeld:Davio schreef op woensdag 17 oktober 2012 @ 08:56:
Keke.
Toch gek dat 'i' algemeen geaccepteerd is als index-variabele en dat er voor de rest dan gezeurd wordt over te korte variabelenamen die je niet kunt begrijpen.
Is er iemand die in zijn for-loopjes bewust een variabelenaam als "index" of "counter" gebruikt oid?
1
2
3
4
| foreach($values as $value) { //code } |
Werkelijk?MBV schreef op dinsdag 16 oktober 2012 @ 23:44:
Ik heb toevallig 2 afstudeerscripties over analyse van code geschreven (eerste op het HBO over analyse van een bestaande code-base, 2e op de TU over hoe je embedded sql kan analyseren). Ik heb daarbij nooit een voorbeeld kunnen vinden van Java of C/C++ code die een hoge cyclomatic complexity heeft, maar niet te lang is. Dus wat mij betreft is die discussie een non-issue: zolang je je functies fatsoenlijk opdeelt, zal je cyclomatic complexity ook beperkt zijn.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| public Object convert(Object destination, Object source, Class<?> destClass, Class<?> sourceClass) { if (source == null) return null; if (source instanceof JAXBElement<?>) return mapper.map(((JAXBElement<?>) source).getValue(), destClass); if (destClass == JAXBElement.class) { ObjectFactory objectFactory = new ObjectFactory(); if (source instanceof Leveringen) { return objectFactory.createOpvragenLeveringResponse(mapper.map(source, JaxbOpvragenLeveringResponse.class)); } if (source instanceof JaxbVastleggenLeveringRequest) { return objectFactory.createVastleggenLeveringRequest((JaxbVastleggenLeveringRequest) source); } String classSimpleName = sourceClass.getSimpleName(); Method method = ReflectionUtils.getMethod(objectFactory, "create" + classSimpleName); Class destActualClass; try { if(classSimpleName.startsWith("Jaxb")){ Class.forName(objectFactory.getClass().getPackage().getName() + "." + classSimpleName); return destination; }else{ destActualClass = Class.forName(objectFactory.getClass().getPackage().getName() + ".Jaxb" + classSimpleName); } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return ReflectionUtils.invoke(method, objectFactory, new Object[] { mapper.map(source, destActualClass) }); } return null; } |
Heb ik net even via Sonar uit een project hier gevist (Project waar mbt de code kwaliteit een berg alarmbellen af gingen
Het voordeel van cyclomatic complexity is dat het daarwerkelijk de complexiteit meet. Een wat langere methode welke niet complex is, is beter leesbaar dan een korte methode met veel geneste strukturen. En dat lijkt me juist wat je zou willen bereiken.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
[ Voor 14% gewijzigd door Jaap-Jan op 17-10-2012 09:28 ]
| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett
Ik vind het juist altijd wel fijn als je aangeeft WAT je precies aan't tellen bent. Maar ik snap je punt en op zich is het geen ramp om het één of het ander te doen.Jaap-Jan schreef op woensdag 17 oktober 2012 @ 09:27:
Ik gebruik 'i' in plaats van 'idx' omdat die extra letters niets toevoegen. Vrijwel alle programmeurs zijn er wel mee bekend, het is duidelijk wat het is en buiten de loop dient het ook geen enkel belang meer, dus waarom zou je dat uitgebreid documenteren? In code weliswaar. Oké, dan praat ik niet over i vs. idx, maar over een nog langere, beter beschrijvende naam.
Korte namen hebben wel een voordeel: De code neemt minder sch(r)ijfruimte in!
Wat mij al meteen vertelt dat cyclomatic complexity dus een waardeloze metric is, want die functie wordt er echt niet leesbaarder op door 'm op te gaan zitten delen. Ik zou die derde if wel omdraaien om er zo een early-out van te maken, net als de vorige twee ifs.Janoz schreef op woensdag 17 oktober 2012 @ 09:24:
[...]
Werkelijk?
Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public Object convert(Object destination, Object source, Class destClass, Class sourceClass) { if (source == null) return null; if (source instanceof JAXBElement) return mapper.map(((JAXBElement) source).getValue(), destClass); if (destClass == JAXBElement.class) { ObjectFactory objectFactory = new ObjectFactory(); if (source instanceof Leveringen) { return objectFactory.createOpvragenLeveringResponse(mapper.map(source, JaxbOpvragenLeveringResponse.class)); } if (source instanceof JaxbVastleggenLeveringRequest) { return objectFactory.createVastleggenLeveringRequest((JaxbVastleggenLeveringRequest) source); } String classSimpleName = sourceClass.getSimpleName(); Method method = ReflectionUtils.getMethod(objectFactory, "create" + classSimpleName); Class destActualClass; try { if(classSimpleName.startsWith("Jaxb")){ Class.forName(objectFactory.getClass().getPackage().getName() + "." + classSimpleName); return destination; }else{ destActualClass = Class.forName(objectFactory.getClass().getPackage().getName() + ".Jaxb" + classSimpleName); } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return ReflectionUtils.invoke(method, objectFactory, new Object[] { mapper.map(source, destActualClass) }); } return null; }
Heb ik net even via Sonar uit een project hier gevist (Project waar mbt de code kwaliteit een berg alarmbellen af gingen). Voldoet aan de 'alles op 1 scherm', maar heeft toch een whooping complexity van 15.
Verder ben ik persoonlijk wel fan van meer witregels, maar goed, dat is zoals gezegd dus persoonlijk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| public Object convert(Object destination, Object source, Class destClass, Class sourceClass) { if (source == null) return null; if (source instanceof JAXBElement) return mapper.map(((JAXBElement) source).getValue(), destClass); if (destClass != JAXBElement.class) return null; ObjectFactory objectFactory = new ObjectFactory(); if (source instanceof Leveringen) return objectFactory.createOpvragenLeveringResponse(mapper.map(source, JaxbOpvragenLeveringResponse.class)); if (source instanceof JaxbVastleggenLeveringRequest) return objectFactory.createVastleggenLeveringRequest((JaxbVastleggenLeveringRequest) source); String classSimpleName = sourceClass.getSimpleName(); Method method = ReflectionUtils.getMethod(objectFactory, "create" + classSimpleName); Class destActualClass; try { if(classSimpleName.startsWith("Jaxb")) { Class.forName(objectFactory.getClass().getPackage().getName() + "." + classSimpleName); return destination; } else { destActualClass = Class.forName(objectFactory.getClass().getPackage().getName() + ".Jaxb" + classSimpleName); } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return ReflectionUtils.invoke(method, objectFactory, new Object[] { mapper.map(source, destActualClass) }); } |
[ Voor 29% gewijzigd door .oisyn op 17-10-2012 09:55 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
De functie is sowieso ruk. Om dit werkbaarder en onderhoudbaar te krijgen zul breder aanpassingen moeten doen..oisyn schreef op woensdag 17 oktober 2012 @ 09:51:
[...]
Wat mij al meteen vertelt dat cyclomatic complexity dus een waardeloze metric is, want die functie wordt er echt niet leesbaarder op door 'm op te gaan zitten delen.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Wellicht dat het overall design van het project idd niet goed in elkaar zit, getuige de instanceof's of de check of een classnaam begint met "Jaxb", maar dat is eigenlijk irrelevant voor de discussie die we nu aan het voeren zijn.
[ Voor 35% gewijzigd door .oisyn op 17-10-2012 10:00 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
, en daar reageer ik op.Wat mij al meteen vertelt dat cyclomatic complexity dus een waardeloze metric is, want die functie wordt er echt niet leesbaarder op door 'm op te gaan zitten delen.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Dan zul je je baan tot in lengte van dagen kunnen houden of de volgende dag een andere baan zoeken, afhankelijk van het bedrijf en de kennis van de collega's / managers.
Of je daar nou blij van moet worden...? Ik krijg soms nog vragen over een project waar ik anderhalf jaar terug voor het laatst aan heb gewerkt...Davio schreef op woensdag 17 oktober 2012 @ 10:37:
Je moet gewoon zorgen dat je de enige bent die het begrijpt.
Dan zul je je baan tot in lengte van dagen kunnen houden
We are shaping the future

Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.
Ja, die hebben immers tijd zat, omdat ze zelf niet programmeren.
Welke verbeteringen stel je dan voor? Opdelen in nog meer functies gaat deze code niet leesbaarder maken denk ik.Janoz schreef op woensdag 17 oktober 2012 @ 09:24:
[...]
Werkelijk?
Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public Object convert(Object destination, Object source, Class<?> destClass, Class<?> sourceClass) { if (source == null) return null; if (source instanceof JAXBElement<?>) return mapper.map(((JAXBElement<?>) source).getValue(), destClass); if (destClass == JAXBElement.class) { ObjectFactory objectFactory = new ObjectFactory(); if (source instanceof Leveringen) { return objectFactory.createOpvragenLeveringResponse(mapper.map(source, JaxbOpvragenLeveringResponse.class)); } if (source instanceof JaxbVastleggenLeveringRequest) { return objectFactory.createVastleggenLeveringRequest((JaxbVastleggenLeveringRequest) source); } String classSimpleName = sourceClass.getSimpleName(); Method method = ReflectionUtils.getMethod(objectFactory, "create" + classSimpleName); Class destActualClass; try { if(classSimpleName.startsWith("Jaxb")){ Class.forName(objectFactory.getClass().getPackage().getName() + "." + classSimpleName); return destination; }else{ destActualClass = Class.forName(objectFactory.getClass().getPackage().getName() + ".Jaxb" + classSimpleName); } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return ReflectionUtils.invoke(method, objectFactory, new Object[] { mapper.map(source, destActualClass) }); } return null; }
Heb ik net even via Sonar uit een project hier gevist (Project waar mbt de code kwaliteit een berg alarmbellen af gingen). Voldoet aan de 'alles op 1 scherm', maar heeft toch een whooping complexity van 15.
Het voordeel van cyclomatic complexity is dat het daarwerkelijk de complexiteit meet. Een wat langere methode welke niet complex is, is beter leesbaar dan een korte methode met veel geneste strukturen. En dat lijkt me juist wat je zou willen bereiken.
Een goede functie heeft een zelfbeschrijvende naam en is doelmatig en to-the-point. Het voorbeeld dat jij gaf is gewoon heel erg slechte code en past ook perfect hier thuis. Hoe kun je een algemene convert methode schrijven die type object returned, maar toch in het model domein prikt?
createVastleggenLeveringRequest, JABX objecten en andere onzin.
Ik denk dat lange en onduidelijke routines vanzelf ontstaan door slecht class design en slechte abstractie. Dan moet je door een paar lagen abstractie heenprikken, in internals gaan wroeten en met if en for loops je informatie te pakken zien te krijgen en dan weer casten. Dat is volgens mij ook precies wat hier gebeurt. Met goede abstractie worden je functies automatisch overzichtelijker en kleiner.

Hmm, het werkt niet meer, even in de code behind kijken.
1
| if (this.medewerkerTabControl.SelectedTab.Name == "tabPage3") |

Ik heb er maar dit van gemaakt:
1
| if (this.medewerkerTabControl.SelectedTab == foobarTabPage) |
En het control staat verder nog vol met panel1, button4, textBox3, enz ...
Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.
Dan heb je van boven naar beneden bijvoorbeeld textBox2, textBox3 en textBox1.

En de tabindex die volledig door elkaar loopt, dus als je door een form heen tabt spring je van hot naar her.Davio schreef op woensdag 17 oktober 2012 @ 11:53:
Het mooiste is als ze in de layout dan ook niet meer logisch staan, omdat ze na het toevoegen heen en weer gesleept zijn.
Dan heb je van boven naar beneden bijvoorbeeld textBox2, textBox3 en textBox1.
Certified smart block developer op de agile darkchain stack. PM voor info.
In een foreach of lambda gebruik ik, zeker als het toch maar één regel is, stiekem lekker toch éénletterige variabelen:
1
2
3
4
5
6
7
8
| foreach (var o in Objects) { o.Foo(); } // of Objects.ForEach(o => o.Foo()); |
Houdt het wat mij betreft net zo leesbaar, zo mogelijk soms zelfs leesbaarder dan de naam voluit schrijven. Dan moet je weer gaan zitten turen waar je nu Object en waar je Objects aanspreekt.
Als echter gegenereerde namen niet veranderd worden, haal je het bloed onder m'n nagels vandaan. Klasse Foo in bestand Class1.cs?

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...
1
| Objects.ForEach(Foo); |
[ Voor 33% gewijzigd door Megamind op 17-10-2012 16:55 ]
Ja, werkelijk. Ook op code-bases waarvan alle alarmbellen afgingen. Ik geef toe dat er wel een stuk of 3 uitzonderingen waren (in de categorie waar jij een voorbeeld van geeft), maar op 5 miljoen regels code is dat niet echt significant.Janoz schreef op woensdag 17 oktober 2012 @ 09:24:
[...]
Werkelijk?
Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public Object convert(Object destination, Object source, Class<?> destClass, Class<?> sourceClass) { if (source == null) return null; if (source instanceof JAXBElement<?>) return mapper.map(((JAXBElement<?>) source).getValue(), destClass); if (destClass == JAXBElement.class) { ObjectFactory objectFactory = new ObjectFactory(); if (source instanceof Leveringen) { return objectFactory.createOpvragenLeveringResponse(mapper.map(source, JaxbOpvragenLeveringResponse.class)); } if (source instanceof JaxbVastleggenLeveringRequest) { return objectFactory.createVastleggenLeveringRequest((JaxbVastleggenLeveringRequest) source); } String classSimpleName = sourceClass.getSimpleName(); Method method = ReflectionUtils.getMethod(objectFactory, "create" + classSimpleName); Class destActualClass; try { if(classSimpleName.startsWith("Jaxb")){ Class.forName(objectFactory.getClass().getPackage().getName() + "." + classSimpleName); return destination; }else{ destActualClass = Class.forName(objectFactory.getClass().getPackage().getName() + ".Jaxb" + classSimpleName); } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return ReflectionUtils.invoke(method, objectFactory, new Object[] { mapper.map(source, destActualClass) }); } return null; }
Heb ik net even via Sonar uit een project hier gevist (Project waar mbt de code kwaliteit een berg alarmbellen af gingen). Voldoet aan de 'alles op 1 scherm', maar heeft toch een whooping complexity van 15.
Het voordeel van cyclomatic complexity is dat het daarwerkelijk de complexiteit meet. Een wat langere methode welke niet complex is, is beter leesbaar dan een korte methode met veel geneste strukturen. En dat lijkt me juist wat je zou willen bereiken.
Je geeft zelf al het goede antwoord op je vraag. Zodra je dit soort functies gaat schrijven en vervolgens er code in gaat zetten die meer doet dan alleen converteren, dan is alle hoop verloren, ongeacht de lengte, cyclomatic complexity, etc.Waster schreef op woensdag 17 oktober 2012 @ 11:12:
[...]
Welke verbeteringen stel je dan voor?
[knip]
Met goede abstractie worden je functies automatisch overzichtelijker en kleiner.
Voor een klant twee api's aan elkaar aan het knopen, zo goed als klaar (eindelijk) het is gewoon data heen en weer synchroniseren tussen twee webdiensten, in de ene kan je dynamisch formulieren maken zeg maar met data. En de volgorde van synchroniseren ging fout (e.g het had straat,plaats,postcode,land moeten zijn) maar het was iets anders.
Toen dacht de klant slim te zijn door velden in de dynamische formulieren aan te passen om het probleem op te lossen. En dat systeem kan enkel de beschrijvingen aanpassen als er al data in staat kan er geen veldnaam veranderd worden.. dus nu klopt het configuratiebestand niet meer met wat het doet.
En het fixen is niet echt te doen aangezien er al 5k records in sync staan...


Dus nu maar met commentaar opgelost.
Punctuation is a bitch, huh?ZpAz schreef op woensdag 17 oktober 2012 @ 21:25:
Eigen werk![]()
Voor een klant twee api's aan elkaar aan het knopen, zo goed als klaar (eindelijk) het is gewoon data heen en weer synchroniseren tussen twee webdiensten, in de ene kan je dynamisch formulieren maken zeg maar met data. En de volgorde van synchroniseren ging fout (e.g het had straat,plaats,postcode,land moeten zijn) maar het was iets anders.
Toen dacht de klant slim te zijn door velden in de dynamische formulieren aan te passen om het probleem op te lossen. En dat systeem kan enkel de beschrijvingen aanpassen als er al data in staat kan er geen veldnaam veranderd worden.. dus nu klopt het configuratiebestand niet meer met wat het doet.
En het fixen is niet echt te doen aangezien er al 5k records in sync staan...
Dus nu maar met commentaar opgelost.
OT: klinkt het als een interessant systeem. Ik zie alleen niet in hoe iets dergelijks foutief gesynct kan worden.
En iets fout, mja het is een vrij uitgebreid systeem enkel de config file om het aan elkaar te knopen is al 400 regels code. Aangezien de applicaties dynamisch kunnen worden aangemaakt in Podio, met elk dynamische veldnamen, type velden e.d. en ik het zo wilde opzetten dat je enkel bij het aangeven via een config welke data uit welke 'podio applicatie' naar welke 'applicatie' binnen harvest moest zonder dit 'hardcoded' aan te geven.
Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info
Elke programmeur is ook bekend met for (int i = 0; i < 100; i++) { }, maar dat betekent niet dat het overmatig complex is, in vergelijking met functionele equivalenten als map() of each(). (bij for-loops werk je immers met veel side-effects; initialisatie, bijhouden, checken van een index, elementen in-order uit een array of lijst halen, etc).Jaap-Jan schreef op woensdag 17 oktober 2012 @ 09:27:
Ik gebruik 'i' in plaats van 'idx' omdat die extra letters niets toevoegen. Vrijwel alle programmeurs zijn er wel mee bekend, het is duidelijk wat het is en buiten de loop dient het ook geen enkel belang meer, dus waarom zou je dat uitgebreid documenteren? In code weliswaar. Oké, dan praat ik niet over i vs. idx, maar over een nog langere, beter beschrijvende naam.
Om vervolgens dit te doen:Please note that [...] is an internal static method in System.Configuration.dll. If we want to call that here, we have to use reflection and that's what we want to avoid.
1
2
| Type typeFactory = Type.GetType(InternalConfigSettingsFactoryTypeString, true); s_configSettingsFactory = (IInternalConfigSettingsFactory) Activator.CreateInstance(typeFactory, true); |
Lijkt mij toch een vorm van reflectie, maar goed. Het ergste is de opmerking die ze over hun eigen code maken: "which is an internal static method", zodat ze een lelijke workaround moeten implementeren. HET HELE FREAKING FRAMEWORK is opgebouwd uit internal static methodes! Ik word er echt totaal krankjorum van.
Omdat ze geen zin hebben om na te denken over een fatsoenlijk architectuur, maken ze er maar wat globale spaghetti van die ze afschermen met internal, een constructie over welk bestaansrecht je uitgebreid kunt discussieren.
Sorry, maar ik moest het ff kwijt. Zit al 3 dagen aan te hikken tegen de blackbox die .NET heet.
Wij onderbreken deze thread voor reclame:
http://kalders.be
Dé voornaamste eigenschap van een blackbox is dat je niet kunt zien wat er binnenin gebeurt. Hier heb je de source code inclusief comments, dus daar is weinig ondoorzichtbaars aanGrimaceODespair schreef op donderdag 18 oktober 2012 @ 14:17:
Sorry, maar ik moest het ff kwijt. Zit al 3 dagen aan te hikken tegen de blackbox die .NET heet.
Verder wel benieuwd wat je dan zoal uitspookt dat je hier last van zou hebben?
Kater? Eerst water, de rest komt later
Verwijderd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| var err= ""; function locateAppWindow(win) { try { var parent = win.parent; if (win != parent) { var pApp = parent.Application; if (pApp || !win.Application) { return locateAppWindow(parent); } } } catch (ex) { } return win; } |
Vanuit ANSI C# (bestaat er eigenlijk zoiets?) gezien is het een blackboxHaan schreef op donderdag 18 oktober 2012 @ 14:37:
[...]
Dé voornaamste eigenschap van een blackbox is dat je niet kunt zien wat er binnenin gebeurt. Hier heb je de source code inclusief comments, dus daar is weinig ondoorzichtbaars aan
Verder wel benieuwd wat je dan zoal uitspookt dat je hier last van zou hebben?
Eigenlijk heb ik alleen hun standaard VirtualPathProvider provider nodig om een methode te testen die een VirtualPathProvider gebruikt. Die is dus van het type MapPathBasedVirtualPathProvider, een internal class. En dat hebben ze dus alleen maar internal gemaakt, omdat het zo slecht in elkaar zit dat het niet te isoleren valt. Dus heb ik maar mijn eigen PhysicalPathProvider gemaakt.
Vervolgens gebruikt de methode die ik probeer te testen ook nog ViewEngine.FindView, een methode die een cascade van internals, statics, sealeds en privates genereert.
Er is van dat hele framework zo ongeveer niks te isoleren of eenvoudig te mocken. Je vind online wel voorbeeld van gedeeltelijke mocks, maar die gaan niet ver genoeg voor mijn scenario.
Wij onderbreken deze thread voor reclame:
http://kalders.be
Een eigen taal niet, een fatsoenlijk framework zou ik graag wel doen
Maar ik vraag me serieus af wat voor soort developers daar in het team zitten. Ik weet dat ze een paar grote lichten hebben rondlopen die de architectuur uitdenken, maar het lijkt wel alsof ze het implementeren ervan als "dom klopwerk" beschouwen. Tenminste, zo laat de code zich lezen. Ik kan me nauwelijks voorstellen dat zoiets onderhoudbaar is...
Wij onderbreken deze thread voor reclame:
http://kalders.be
Natuurlijk zal een bedrijf als Microsoft er alles aan moeten doen om waardeloze code te voorkomen, maar ook de Microsoft developers zijn niet perfect......hmm, zal mijn cv eens sturen.
Ik snap ook wel dat je niet altijd de schoonheidsprijs kunt verdienen met je code, maar ik zie ook het verschil tussen code die is neergezet door een genie en code die door een mindere god is ingeklopt en dan nog code die er alleen staat "zodat het werkt". Ik kan er zo moeilijk bij dat je met het potentieel dat MS heeft (lees: $$$) toch niet beter kan dan wat je in het framework overal tegenkomt.Davio schreef op donderdag 18 oktober 2012 @ 15:13:
Ik denk dat het uiteindelijk een beetje is zoals in elk bedrijf: In een ideale wereld creëer je de meest elegante en bugvrije software en kun je daar een eeuwigheid over doen en oneindig veel geld aan besteden. In de praktijk heb je te maken met deadlines, verschil in kennis tussen collega's, communicatieve fouten en ga zo maar door.
Zal wel weer aan mij liggen en mijn ideaalbeeld van de wereld
Wij onderbreken deze thread voor reclame:
http://kalders.be
sja wij simpele zielen zien "winst" als een middel om meer personeel in te huren zodat iedereen meer tijd heeft om het product te verbeteren en leuker te maken. In de grote boze beursgenoteerde bedrijvenwereld is "winst" echter niet meer dan een middel om aandeelhouders aan een groter huis te helpen. Iedere gewerkte seconde zonder duidelijk resultaat, is weer een dakpan minder.GrimaceODespair schreef op donderdag 18 oktober 2012 @ 15:46:
[...]
Ik snap ook wel dat je niet altijd de schoonheidsprijs kunt verdienen met je code, maar ik zie ook het verschil tussen code die is neergezet door een genie en code die door een mindere god is ingeklopt en dan nog code die er alleen staat "zodat het werkt". Ik kan er zo moeilijk bij dat je met het potentieel dat MS heeft (lees: $$$) toch niet beter kan dan wat je in het framework overal tegenkomt.
Zal wel weer aan mij liggen en mijn ideaalbeeld van de wereld
Maar het is mij nog steeds onduidelijk wat je precies wil. Ik ken de VirtualPathProvider niet maar wat ik wel weet is dat 9 van de 10 keer mensen die dit soort problemen hebben zelf verkeerd zitten.GrimaceODespair schreef op donderdag 18 oktober 2012 @ 14:51:
[...]
Vanuit ANSI C# (bestaat er eigenlijk zoiets?) gezien is het een blackbox
Eigenlijk heb ik alleen hun standaard VirtualPathProvider provider nodig om een methode te testen die een VirtualPathProvider gebruikt. Die is dus van het type MapPathBasedVirtualPathProvider, een internal class. En dat hebben ze dus alleen maar internal gemaakt, omdat het zo slecht in elkaar zit dat het niet te isoleren valt. Dus heb ik maar mijn eigen PhysicalPathProvider gemaakt.
Vervolgens gebruikt de methode die ik probeer te testen ook nog ViewEngine.FindView, een methode die een cascade van internals, statics, sealeds en privates genereert.
Er is van dat hele framework zo ongeveer niks te isoleren of eenvoudig te mocken. Je vind online wel voorbeeld van gedeeltelijke mocks, maar die gaan niet ver genoeg voor mijn scenario.
C# is een ISO standaard en er zijn maar weinig andere Microsoft producten die zo uitvoerig zijn gedocumenteerd en waarvan code beschikbaar is. De blackbox opmerking is mij dan ook een raadsel.
*zucht*. Mijn post ging over variabelennaamgeving, en ik wilde even snel een lambda tikken. Lees het dan maar als Objects.Where(o => o.Foo == bar);.
Ik last dit stukje op dat blog:
1
| foreach(Foo foo in foos){ statement involving foo; } |
als "statement involving plankton".
[ Voor 18% gewijzigd door CodeCaster op 18-10-2012 19:44 ]
https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...
En tussen de inzendingen zitten echt briljante stukjes code die - ongelofelijk maar waar - perfect compilen met gccGoals of the Contest
- To write the most Obscure/Obfuscated C program within the rules.
- To show the importance of programming style, in an ironic way.
- To stress C compilers with unusual code.
- To illustrate some of the subtleties of the C language.
- To provide a safe forum for poor C code. :-)
Enkele voorbeeldjes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| #include<stdio.h> typedef unsigned int _;_ d,b, #define i(I1,Il,lI)if(Il){lI;}else{I1;} I[256], n,y,a,r,u,k,o ,L,l[ 256],O,K[ /**/ #define\ q(g) g char\ *C, *Q,c[\ ]= "KfW"\ "" "Ww|"\ /* 'UU!\ % NYA!\ */ "Z}"\ ";fRo?JtJaV<x4@*?R?&JV1" ".s"\ "{Fyj2_;khB1xQ5oxm~mS@B|(pa>oRU" "Ro"\ "nB}h@o?)d.X)NSTIUCz7@%",*s[]={c,"#en" "di"\ "f/*}||1;\n__DATA__\40*/\n\n#ifndef\40q\n#d" "ef"\ "ine\x20q\n#include<stdio.h>\ntypedef\40unsign" "e"\ "d\x20int\x20_;_\x20K[]={\n#include\40__FILE__\n#u" "n"\ "def q","0},L,O,l[256],I[256],n,y,a,r,u,k,o;"#g"char" "*"\ "S,s[]=\"",c,c,"\";int main(){X();for(S=s+*K;*S>37;){for" "(o"\ "=0;o<5;o++)r=r*85+(83+*S++)%89;r","^=*x();for(o=0;o<4;o++" ")"\ "{s[O++]=r&255;r>>=8;}}return!fwrite(s,O-*S%5,1,stdout);}\n" "#"\ "endif",c},S[256]="#ifdef/*\n'true'\40or\40q{\nexec\40head\40" "-"\ "8\40$0\n};for(open$O,$0;<$O>;print\40if$f){$f|=/^$/;}q{*/q",/* */z; 256];q(_*x(){if(!L--){y+=++a;for(o=0;o<256;y=l[o++]=I[255&(k>>10 )]+u ){n^=(o&1)?n>>(( o& 2)?16:6):n<<((o&2)?2:13);u=I[o];k=I[o]=I[255& (u>> 2)]+(n+=I[(o+128) & 255]) +y;}L=255;}return&l[L];}_*X(){for(O=0 ;256 >O;I[O++]=0);for(O = 0; sizeof(K)/sizeof( _)> O;O++)I[O&255] ^=K[ O];for(n=y=a=L=O=0 ;O<1<<24;++ O)x( );r=O=0x0; return&O;})int/*^^*/ main (int p,char**P){FILE* Z=fopen(p> (+ 1)?P[01 ] :"/dev/urandom", "rb" );i(;,Z,O=fread(K,256 ,4,Z);/*P */ fclose(Z))X();for(p=b=d =O= 0;O<256;K[O++]=0)*K=+ 86;for(O =1;12> O;K[O++]=*x());X(); for (C=Q=S;r-8;){i(*C++=34, (r-4&&r -5)||C- S ,;)z=Q[p++];i(;,z != 32||r-3,i(i(C+=sprintf(( C), "%uU" ",",K[b++]);i(d=1;C =S ;i(d=02,b-12,;),b%6,;),r-1 ,i(b= fread(c,1,4,stdin);i (p =O=0,b,for(d=O=0;O<04;O++)d +=(c[O]&255)<<(8*O);d ^= *x();for(p=5;p;c[--p]=O<32?O+ 95:O+6){O=d%85;d/=85;} O= 5)i(d=0,b<4,c[O++]=b?b-1?b-2?36: 37:33:35 ;d=2)c[O]=0,r-4,i(i (d= 2 |d,C!=S+6,*C++=(*x()%34)+93;p--),r -5,*s= C;d|=2) )),z ,i(*C++ =92 , z-63||C [-1]-63||C>S+76,;)*C++=z))i( ;,d>1,d= d-2 ;Q=s[r] ;i( ; ,r<3|| r>5,d=1;i(;,r-1, *C=0)C=S) i(;, r-4, p=0)++ r) i(*(C++ )= 34,r <4||r>5|| C<S+ 78,;)i (*C++=0;d=1; C=S ,r<3 || r> 5 ||C<S+ 79,; )i(;,d, puts ( S); d=0 )} return 0;} |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| Int L[A],m,b,*D=A, *c,*a=L,C,*U=L,u;s (_){u--&&s(a=*a);} char*B,I,O;S(){b=b --?b:m|read(0,&I,1 )-1;return~I>>b&1; }k(l,u){for(;l<=u; U-L<A?*U++=46^l++[ "-,&,,/.--/,:-,'/" ".-,-,,/.-,*,//..," ]:exit(5));}p(Int*m){ return!*U?*m=S()?U++,!S ()?m[1]=p(++U),2:3:1,p(U) :S()?U+=2:p(U[1]++),U-m;}x( c){k(7*!b,9);*U++=b&&S();c&&x (b);}d(Int*l){--l[1]||d(l[d(*l), *l=B,B=l,2]);}main(e){for(k(10,33 ),a[4]-=m=e-2&7,a[23]=p(U),b=0;;e-2 ?e?e-3?s(D=a),C=a [3],++1[a=a[2]],d( D):c?D=c,c=*D,*D= a,a=D:exit(L[C+1]) :C--<23?C=u+m&1?O =O+O|C&1,9:write(m ||(O=C+28),&O,1)+ 1:(S(),x(0<b++?k(0, 6),U[-5]=96:0)):( D=B?B:calloc(4,X)) ?B=*D,*D=c,c=D,D[ 2]=a,a[++D[1]]++,D [3]=++C+u:exit(6) )e=L[C++],u=L[C];} |
Respect

Hij bedoelt dan ook niet C# de taal, maar .NET het platform. En dat is qua extensibility inderdaad ronduit een drama. Zelf je VPP schrijven? Copy paste maar de hele meuk vanuit de sources en maak je aanpassingen.PolarBear schreef op donderdag 18 oktober 2012 @ 19:39:
[...]
C# is een ISO standaard en er zijn maar weinig andere Microsoft producten die zo uitvoerig zijn gedocumenteerd en waarvan code beschikbaar is. De blackbox opmerking is mij dan ook een raadsel.
Het enige fatsoenlijk extensible stukje wat ze bij microsoft geproduceerd hebben is ASP.NET MVC, vanaf versie 3.
Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info
Oef ... je bespaart me een rantGrijze Vos schreef op vrijdag 19 oktober 2012 @ 13:34:
[...]
Hij bedoelt dan ook niet C# de taal, maar .NET het platform. En dat is qua extensibility inderdaad ronduit een drama. Zelf je VPP schrijven? Copy paste maar de hele meuk vanuit de sources en maak je aanpassingen.
Het enige fatsoenlijk extensible stukje wat ze bij microsoft geproduceerd hebben is ASP.NET MVC, vanaf versie 3.
Wij onderbreken deze thread voor reclame:
http://kalders.be
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| ... private Boolean canClone; public void setCanClone(Boolean canClone) { if (canClone == null) { this.canClone = canClone; } else { this.setCanClone(canClone.booleanValue()); } } public void setCanClone(boolean canClone) { this.canClone = new Boolean(canClone); } |
en dan vraag je je af waarom autoboxing/unboxing er pas in JDK5 bij is gekomen

//edit ... deze schoot mij ineens nog te binnen, had ik bij een collega is op het scherm gezien en we hebben er toch 5 minunten mee kunnen lachen (ps. heb de code niet meer, vandaar de stomme namen)
1
2
3
4
5
6
7
8
| public void doSomething(boolean val) { if (val == true) { } else { } } |
//edit2: ... nu we toch bezig zijn, hoe sommige developers hun Integers omzetten naar een String
1
2
| Integer i = 5; //bijvoorbeeld hé ... String iAsString = "" + i; |
//edit3: ... I'm on a roll. Een SQL query zoals hieronder heeft ons ooit is zware problemen bezorgd (ken de echte query niet, meer het kwam op hetzelfde neer).
1
2
| insert into db2.table1(id, codeType, codeSeq, actId, actType, modId) select (nextval for db2.c_seq), t2.codeTypeCode codeType, t2.codeSequence codeSeq, t2.activityType actType, t2.activityId actId, t2.modUserId modId from db2.table2 t2; |
[ Voor 56% gewijzigd door Hardfreak op 19-10-2012 20:18 ]
Things I wish my life had: a debug port, a try-catch feature and good memory management
Wat is hier zo slecht aan?Hardfreak schreef op vrijdag 19 oktober 2012 @ 19:58:
//edit2: ... nu we toch bezig zijn, hoe sommige developers hun Integers omzetten naar een String
Java:
1 2 Integer i = 5; //bijvoorbeeld hé ... String iAsString = "" + i;
Ik weet dat er Integer.toString(i) is, maar ik gebruik regelmatig jouw voorbeeld.
Gokje: er wordt een lege string aangemaakt, daarnaast wordt i gecast naar een string (explicit casting, weer een stringobject aangemaakt) en die twee worden aan elkaar geplakt waarbij een derde stringobject wordt aangemaakt. Dat in tegenstelling tot één string bij de toString?Jegorex schreef op vrijdag 19 oktober 2012 @ 23:14:
[...]
Wat is hier zo slecht aan?
Ik weet dat er Integer.toString(i) is, maar ik gebruik regelmatig jouw voorbeeld.
Mijn laatste (grote) reviews: Medal of Honor (VR), Half-Life: Alyx (VR)
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Bovendien heeft i.toString() het voordeel NullPointerExceptions to throwen als i null is, als je code ineens rare dingen doet weet je ineens waar het vandaan komt (bijvoorbeeld wanneer je later Integer.valueOf(iAsString) zou moeten gebruiken dan krijg je een NumberFormatException en dan kan je maar gaan zoeken waar die "null" String vandaan kwam).
Things I wish my life had: a debug port, a try-catch feature and good memory management
En zelfs MVC heeft nog zijn nukken. (*Kuch* DataAnnotationsModelValidatorProvider...)Grijze Vos schreef op vrijdag 19 oktober 2012 @ 13:34:
[...]
Het enige fatsoenlijk extensible stukje wat ze bij microsoft geproduceerd hebben is ASP.NET MVC, vanaf versie 3.
Zoals ik al zei.Hardfreak schreef op zaterdag 20 oktober 2012 @ 13:45:
Hoe het exact verloopt weet ik niet, maar het is zeker niet zo efficiënt als i.toString().
1
2
3
4
5
6
7
8
| String s = "" + i; // is equivalent aan: StringBuilder b = new StringBuilder(); b.append(""); b.append(i); String s = b.toString(); |
Waarbij b.append(i) en Integer.toString(i) intern precies hetzelfde zullend doen (volgens de JDK 7 implementatie roepen ze beide de method Integer.getChars() aan).
Maar goed, het is natuurlijk ook afhankelijk van hoe de VM er vervolgens mee omgaat, kan best dat hij dit soort specifieke gevallen detecteert omdat ze nou eenmaal vaak gebruikt worden.
Dat geldt natuurlijk alleen voor Integer, niet voor int, die veruit het meest gebruikt wordt.Bovendien heeft i.toString() het voordeel NullPointerExceptions to throwen als i null is
[ Voor 11% gewijzigd door .oisyn op 20-10-2012 15:14 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Hangt er maar vanaf wat je wil.oisyn schreef op zaterdag 20 oktober 2012 @ 15:12:
[...]
Zoals ik al zei.
Java:
1 2 3 4 5 6 7 8 String s = "" + i; // is equivalent aan: StringBuilder b = new StringBuilder(); b.append(""); b.append(i); String s = b.toString();
Waarbij b.append(i) en Integer.toString(i) intern precies hetzelfde zullend doen (volgens de JDK 7 implementatie roepen ze beide de method Integer.getChars() aan).
Maar goed, het is natuurlijk ook afhankelijk van hoe de VM er vervolgens mee omgaat, kan best dat hij dit soort specifieke gevallen detecteert omdat ze nou eenmaal vaak gebruikt worden.
[...]
Dat geldt natuurlijk alleen voor Integer, niet voor int, die veruit het meest gebruikt wordt.
1
| "" |
heeft trouwens niet altijd tot gevolg dat er een nieuwe String aangemaakt wordt, soms worden die pointers opnieuw gebruikt.
Enkel new String("") heeft als garantie dat er een nieuw object (nieuwe pointer) wordt aangemaakt.
[ Voor 12% gewijzigd door Hardfreak op 20-10-2012 17:54 ]
Things I wish my life had: a debug port, a try-catch feature and good memory management
Alle string literals worden geïnternd, dus je kunt zelfs zeggen dat er nooit nieuw String object wordt aangemaakt als een literal meer dan eens voorkomt.Hardfreak schreef op zaterdag 20 oktober 2012 @ 17:51:
Java:
1""
heeft trouwens niet altijd tot gevolg dat er een nieuwe String aangemaakt wordt, soms worden die pointers opnieuw gebruikt.
Sorry, maar met dit soort argumenten heb ik meer moeite dan met de zogenaamde inefficiënte code....Hardfreak schreef op zaterdag 20 oktober 2012 @ 13:45:
Hoe het exact verloopt weet ik niet, maar het is zeker niet zo efficiënt als i.toString().
Voor mij vragen voor het vaststellen van een slechte programmeerstijl:
- Levert de code fouten op?
- Is het onduidelijk wat er bedoeld wordt?
- Is er sprake van inconsequentheid?
Programmeren is op een gegeven moment ook stopen als het goed genoeg is, het hoeft niet altijd perfect te zijn...
En waarschijnlijk heeft deze collega zich dit ooit een keer aangeleerd en is er door niemand opgewezen. Daarvoor zijn codereviews nou uitermate geschikt en nuttig....
[ Voor 0% gewijzigd door HeSitated op 21-10-2012 16:26 . Reden: inconsistent vs inconsequent: klein verschilletje ;) ]
Of de collega werkt in meer programmeertalen en vindt het een acceptable loss vs in elke programmeertaal de 100% exacte syntax kennen.HeSitated schreef op zaterdag 20 oktober 2012 @ 20:52:
[...]
En waarschijnlijk heeft deze collega zich dit ooit een keer aangeleerd en is er door niemand opgewezen. Daarvoor zijn codereviews nou uitermate geschikt en nuttig....
Als je hierover valt alszijnde "bad coding" dan verbaast het me meer dat je programma op meer dan 1 computer werkt. Ik bedoel de .net/java VM kan je ook wel omzeilen, directx kan je zelf ook veel efficienter implementeren, waarom nog memory allocation door het OS laten doen, dat kan je zelf efficienter dan gehinderd door code die ook rekening houdt met swap etc.
Been there, done thatGomez12 schreef op zaterdag 20 oktober 2012 @ 21:42:
directx kan je zelf ook veel efficienter implementeren, waarom nog memory allocation door het OS laten doen, dat kan je zelf efficienter dan gehinderd door code die ook rekening houdt met swap etc.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Verwijderd
Code is niet altijd inefficiënt door het feit dat er 4x meer cycles doorlopen moeten worden om hetzelfde te doen, code kan ook gewoon inefficiënt zijn omdat ze moeilijk te begrijpen valt. Op zich is een concatenate van een lege String met een random object om dit te casten naar een String niet echt onduidelijk, maar het helpt de leesbaarheid er ook niet op vooruit. Als je probeert om een 4 jaar oude webapp te debuggen waar ondertussen al 4 jaar lang wijzigingen aan zijn aangebracht (change request, bugfixes, ...) dan zie je liever .toString() staan dan iets andersHeSitated schreef op zaterdag 20 oktober 2012 @ 20:52:
[...]
Sorry, maar met dit soort argumenten heb ik meer moeite dan met de zogenaamde inefficiënte code....![]()
Voor mij vragen voor het vaststellen van een slechte programmeerstijl:En ja als het in een lus gebeurd die honderd miljoen keer doorlopen wordt, heb je volledig gelijk. Maar dan zou ik toch maar eens gaan kijken of er niet ergens anders meer performance winst te halen valt.
- Levert de code fouten op?
- Is het onduidelijk wat er bedoeld wordt?
- Is er sprake van inconsistentie?
Programmeren is op een gegeven moment ook stopen als het goed genoeg is, het hoeft niet altijd perfect te zijn...
En waarschijnlijk heeft deze collega zich dit ooit een keer aangeleerd en is er door niemand opgewezen. Daarvoor zijn codereviews nou uitermate geschikt en nuttig....
En ja, daarom doen wij nu ook code reviews, maar zo'n dingen halen we gewoon niet aan gezien er belangrijkere punten zijn aan te halen dan dat (String compare met '==' bijvoorbeeld). Bovendien werken de developers van toen al lang niet meer aan die applicatie.
Meerdere programmeertalen denk ik niet, ik denk voornamelijk oude gewoonten uit Java 1.4 .Gomez12 schreef op zaterdag 20 oktober 2012 @ 21:42:
[...]
Of de collega werkt in meer programmeertalen en vindt het een acceptable loss vs in elke programmeertaal de 100% exacte syntax kennen.
Als je hierover valt alszijnde "bad coding" dan verbaast het me meer dat je programma op meer dan 1 computer werkt. Ik bedoel de .net/java VM kan je ook wel omzeilen, directx kan je zelf ook veel efficienter implementeren, waarom nog memory allocation door het OS laten doen, dat kan je zelf efficienter dan gehinderd door code die ook rekening houdt met swap etc.
Ik noem dit geen bad coding, dit is ook geen bad coding topic, het is gewoon een slecht voorbeeld van een cast van een Integer naar een String object.
Ik snap ook niet waarom je hier begint over het omzeilen van VM's en DirectX. Ja die dingen kunnen efficiënter op sommige vlakken, maar als je dat doet werkt er juist een ander onderdeel weer minder efficiënt. Als je code alles aan moet kunnen, dan ga je een evenwicht moeten zoeken tussen efficiëntie, rubuustheid, featureset en maintainability. Dat is een delicaat evenwicht wat soms moeilijk te vinden en te behouden is.
De code waar ik het over heb heeft een lage maintainability, een lage efficiëntie, en lage robuustheid en een veel te grote en varierende featureset. Een String concatenate gebruiken puur en alleen om een cast uit te voeren maakt het er niet echt beter op (niet persé slechter, maar tel al die kleine details bij elkaar op en je hebt een monster van een applicatie).
[ Voor 32% gewijzigd door Hardfreak op 21-10-2012 11:33 . Reden: 2e quote beantwoord ]
Things I wish my life had: a debug port, a try-catch feature and good memory management
1
2
3
4
5
| CultureInfo culture = new CultureInfo("nl-NL"); DateTimeFormatInfo dfi = (new CultureInfo("nl-NL").DateTimeFormat); var week1 = culture.Calendar.GetWeekOfYear(new DateTime(2012, 12, 31), dfi.CalendarWeekRule, dfi.FirstDayOfWeek); var week2 = culture.Calendar.GetWeekOfYear(new DateTime(2013, 1, 1), dfi.CalendarWeekRule, dfi.FirstDayOfWeek); |
week1 != week2
This does not map exactly to ISO 8601.
Voor het Internationaal Strafhof ermee
Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.

Mother north, how can they sleep while their beds are burning?
http://blogs.msdn.com/b/s...mat-in-microsoft-net.aspxkenneth schreef op vrijdag 02 november 2012 @ 15:13:
C#:
1 2 3 4 5 CultureInfo culture = new CultureInfo("nl-NL"); DateTimeFormatInfo dfi = (new CultureInfo("nl-NL").DateTimeFormat); var week1 = culture.Calendar.GetWeekOfYear(new DateTime(2012, 12, 31), dfi.CalendarWeekRule, dfi.FirstDayOfWeek); var week2 = culture.Calendar.GetWeekOfYear(new DateTime(2013, 1, 1), dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
week1 != week2
[...]
Voor het Internationaal Strafhof ermee
MS SQL 2008 heeft wel een werkende ISO week functie MSDN: DATEPART (Transact-SQL)
Gelukkig hoef ik het niet te fixen, dat is aan de andere developer

Look, runners deal in discomfort. After you get past a certain point, that’s all there really is. There is no finesse here.
'auto' is de automatische compile-time type deduction van de nieuwe C++ versie. Dus je kan nu dingen schrijven als:
1
2
| auto x = some_function(); x->doStuff(); |
Erg handig, maar ik vraag me af wat men hier denkt over die uitspraak: use auto wherever possible. Ik zie zelf namelijk wel wat problemen met deze aanpak.
1) Als je vrijwel overal auto voor gebruikt zie je wat dieper in de code niet meer met wat voor type je nou precies werkt. Zoals in het voorbeeld hierboven, wat is 'x' nou eigenlijk? En wat als doStuff weer iets returned dat je weer als 'auto' variabele opschrijft. Ik ben bang voor functies waar je de hele code naar boven terug moet lezen om bij te houden met wat voor type je te maken hebt. Natuurlijk zal je code editor hier hints over geven, maar toch bevordert het volgens mij niet *altijd* de leesbaarheid van code.
2) Als ik het return type van some_function() hier aanpas, dan krijg ik geen compiler error op de assignment aan x, maar pas later in de code waar ik x gebruik. Of helemaal geen error maar ander programmagedrag. Even stom voorbeeld ter illustratie:
1
2
3
4
5
| float someFunc() {return 3.0f;} auto x = someFunc(); float y = 2 / x; |
y is nu ~0.66. Stel dat ik nu someFunc verander om een int te retourneren, dan compilet alles prima, maar is y gelijk aan 0.0.
Ik heb dus een beetje gemengde gevoelens over 'auto'; in sommige gevallen heel erg handig, maar als programmeurs het overal als short-cut te gebruiken... kan het problemen geven.
Zelf vind ik dat ook een probleem, dus gebruik ik auto nu vooral voor iterators en in loops over ranges.Zoijar schreef op zaterdag 03 november 2012 @ 16:45:
Erg handig, maar ik vraag me af wat men hier denkt over die uitspraak: use auto wherever possible. Ik zie zelf namelijk wel wat problemen met deze aanpak.
Auto in plaats van builtin types als float en int vind ik niet zo nuttig.
[ Voor 9% gewijzigd door Olaf van der Spek op 03-11-2012 16:54 ]
Is dat niet ongeveer hetzelfde als "var" in C#? Ik denk dat dezelfde regels dan wel gelden.Zoijar schreef op zaterdag 03 november 2012 @ 16:45:
Ik las net een artikeltje van Herb Sutter over C++11 waar hij stelt: "Use auto wherever possible."
Ja, ik geloof het wel.Styxxy schreef op zaterdag 03 november 2012 @ 17:07:
Is dat niet ongeveer hetzelfde als "var" in C#? Ik denk dat dezelfde regels dan wel gelden.
Welke regels zijn dat?Styxxy schreef op zaterdag 03 november 2012 @ 17:07:
[...]
Is dat niet ongeveer hetzelfde als "var" in C#? Ik denk dat dezelfde regels dan wel gelden.
We are shaping the future
In oudere SQL-versies werkt dat niet goed, en dan nog kan het per installatie anders zijn ingestelt.PolarBear schreef op zaterdag 03 november 2012 @ 09:25:
[...]
http://blogs.msdn.com/b/s...mat-in-microsoft-net.aspx
MS SQL 2008 heeft wel een werkende ISO week functie MSDN: DATEPART (Transact-SQL)
Ik weet dat 4 januari altijd in week 1 valt, en met de gevonden offset uit programmatuur en/of databases ga ik verder rekenen...
Het kan soms dubbelop en overbodig zijn, maar ik wil zelf dat het gegarandeerd goed is.
Speel ook Balls Connect en Repeat
Ik zou dat ook zo doen. Debuggen van automatisch castende variabelen is erg lastig. Zelfs als je expliciet types gebruikt krijg je af en toe al rare toestanden, als de conversie-operator of constructor voor rare types is geimplementeerd. Ik ben het volgende commentaar wel tegengekomen bij een vorige opdracht (mocht iemand toegang hebben tot de letterlijke tekst, voel je vrij om het te verbeteren):Olaf van der Spek schreef op zaterdag 03 november 2012 @ 16:53:
[...]
Zelf vind ik dat ook een probleem, dus gebruik ik auto nu vooral voor iterators en in loops over ranges.
Auto in plaats van builtin types als float en int vind ik niet zo nuttig.
1
2
3
4
5
6
7
| /* ================================== ==== Think big red FLASHING sign: ====== TO ALL INTEGRATORS: DO NOT IMPLEMENT OPERATOR BOOL!!! If we implement operator bool on this coordinate type, we will get really strange unwanted behavior! ================================== */ |
Kennelijk maakten sommigen wat foutjes tijdens terugmergen van bugfixes uit andere branches. "Think big red flashing sign" staat er letterlijk in, in de header van een klasse die een XY-coordinaat voorstelt. Ik geloof dat het probleem was dat als je 2 instanties vergeleek, de C++-compiler het eerst naar een boolean converteert en daarna gaat vergelijken.
Ik heb recent zelf in een model-driven omgeving wat structuur aangebracht, dus ook interfaces aangepast, waarbij ik vergat wat argumenten van integer (default) naar real te veranderen. De compiler van de scripttaal keurt standaard een typeconversie van integer naar real en vice-versa goed. Bij gebrek aan een werkende simulatieomgeving bleek op het embedded device dat dat wat raar gedrag gaf

Klopt. Ik implementeer die dingen ook nooit meer. Geen casts (maak dan gewoon een toXXX() member) en elke single parameter ctor explicit.MBV schreef op zaterdag 03 november 2012 @ 20:58:
Ik zou dat ook zo doen. Debuggen van automatisch castende variabelen is erg lastig.
Er is geen auto-generated operator==(), zoals er wel een auto-generated operator=() bestaat. Ik zou geen idee hebben waarom men ooit een operator bool() zou willen implementeren op een vector, maar als je ze wilt vergelijken moet je sowieso een operator==() hebben, en dan maakt het niet meer uit dat er een operator bool() bestaat.MBV schreef op zaterdag 03 november 2012 @ 20:58:
Ik geloof dat het probleem was dat als je 2 instanties vergeleek, de C++-compiler het eerst naar een boolean converteert en daarna gaat vergelijken.
En inderdaad, een conversion operator zorgt ervoor dat je type impliciet naar dat andere type te converteren is, en dat je er "gratis" dus ook ineens alle functies maar vooral operators bij krijgt die op dat andere type werken. Soms wil je dat ook (met als bijkomend nadeel dat als het type templatized is en zijn operators ook het dan ineens niet meer werkt

Dat implicit conversion operators een doorn in het oog zijn onderschrijft de standards committee ook (het std::iostream verhaal spreekt wat dat betreft ook boekdelen). Voor een conversion constructor had je al explicit. Sinds C++11 heb je die ook op conversion operators. Met een explicit operator bool() kun je je type wel testen in een if, maar kun je er niet zomaar iets bij optellen.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ik zie nooit zo in dat het nou zo veel meer type-werk is om if (str.empty()) te doen ipv if (str), en de eerdere versie toont duidelijker aan wat het doet. if (str) lijkt een beetje op een nullptr check.Olaf van der Spek schreef op zondag 04 november 2012 @ 01:20:
Operator bool() voor strings lijkt me anders wel handig, ik check vaak op !empty()
Zodat je ook ineens str + 5 kunt doen. Of een string geven aan een functie die een int verwacht. Ja, heel handig.Olaf van der Spek schreef op zondag 04 november 2012 @ 01:20:
Operator bool() voor strings lijkt me anders wel handig, ik check vaak op !empty()
Overigens, toen ik het in mijn vorige post over een vector had ging het om een geometrische vector. Het voorbeeld van MLM ging namelijk om een coordinaten-type. Wat moet een operator bool() dan doen, kijken of hij (0, 0) is?
[ Voor 26% gewijzigd door .oisyn op 04-11-2012 02:09 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Explicit operator bool() const, operator const void*() const of iets beters van Boost dan? Het gaat om het idee..oisyn schreef op zondag 04 november 2012 @ 02:08:
[...]
Zodat je ook ineens str + 5 kunt doen. Of een string geven aan een functie die een int verwacht. Ja, heel handig.
Ligt eraan, als je een invalid value hebt voor de coordinaten class kun je daarop checken.Overigens, toen ik het in mijn vorige post over een vector had ging het om een geometrische vector. Het voorbeeld van MLM ging namelijk om een coordinaten-type. Wat moet een operator bool() dan doen, kijken of hij (0, 0) is?
Is het toch ook een beetje?Zoijar schreef op zondag 04 november 2012 @ 01:25:
if (str) lijkt een beetje op een nullptr check.
Als je een var hebt is het inderdaad simpel, maar als je iets hebt als
1
2
3
4
5
6
7
8
9
10
| std::string f() { return "Olaf"; } int main() { if (std::string s = f()) use(s); while (std::string s = f()) use(s); } |
dan is empty() toch ineens een stuk lastiger. Voor types als SQL result en row is zoiets ook handig.
Wat is er complex aan? data() is trouwens de standaard naam voor zo'n functie.Zoijar schreef op zondag 04 november 2012 @ 02:14:
Een van de weinige dingen die ik zie waar ik een cast operator heb is voor m'n matrix classes naar value_type*, zodat ik ze makkelijk door kon geven aan opengl functies. Maar bij nader inzien is dat ook eigenlijk onnodig complex en moet ik die gewoon vervangen door toFloatPtr() oid.
[ Voor 5% gewijzigd door Olaf van der Spek op 04-11-2012 14:01 ]
Ja, daar is het wel handig geef ik toe. Dit is niks, zeker niet met veel argumenten en foutgevoelig:Olaf van der Spek schreef op zondag 04 november 2012 @ 14:00:
dan is empty() toch ineens een stuk lastiger. Voor types als SQL result en row is zoiets ook handig.
1
| for (std::string x = f(); !x.empty(); x = f()) {} |
of anders moet je je var buiten de scope halen:
1
2
| std::string x; while (x = f(), !x.empty()) {} |
maar dan heb je ook buiten je loop toegang tot x als nadeel (Als dat echt heel erg is knal je er twee braces omheen...) Dan is je bool cast wel elegant.
Mogelijk onvoorzien gedrag in verschillende situaties.Wat is er complex aan? data() is trouwens de standaard naam voor zo'n functie.
1
2
3
4
| OGLMatrixFunc(float* M) {} Matrix A; OGLMatrixFunc(A + 1); |
Telt niet bij elk element 1 op, omdat ik geen scalar operator+ heb. Argument is nu een pointer naar het tweede element, OGL leest over boundary, crash.
Zal ook een deel persoonlijke voorkeur zijn.
Je bedoelt mijn voorbeeld? Autocorrect.oisyn schreef op zondag 04 november 2012 @ 02:08:
Overigens, toen ik het in mijn vorige post over een vector had ging het om een geometrische vector. Het voorbeeld van MLM ging namelijk om een coordinaten-type. Wat moet een operator bool() dan doen, kijken of hij (0, 0) is?
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

.edit: ah wacht ik zie het al, de timelapse view gaat alleen maar de root-branch in vanaf revisie #1 in de branch, hij splitst niet af bij elke willekeurige integrate. Je moet dus op de comment klikken, dan in de integrate tab een timelapse view op de source doen, dan daar weer de comment opzoeken en dat herhalen tot je bij de daadwerkelijke change uitkomt.
[ Voor 50% gewijzigd door .oisyn op 05-11-2012 16:20 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Dat is het nadeel van pointers. Explicit helpt hier ook niet echt.Zoijar schreef op zondag 04 november 2012 @ 14:51:
Telt niet bij elk element 1 op, omdat ik geen scalar operator+ heb. Argument is nu een pointer naar het tweede element, OGL leest over boundary, crash.
2008 is 4 jaar oud, aan ouder doe ik niet. We draaien hier inmiddels 2012 in productie.Onbekend schreef op zaterdag 03 november 2012 @ 20:01:
[...]
In oudere SQL-versies werkt dat niet goed, en dan nog kan het per installatie anders zijn ingestelt.
Ik weet dat 4 januari altijd in week 1 valt, en met de gevonden offset uit programmatuur en/of databases ga ik verder rekenen...
Het kan soms dubbelop en overbodig zijn, maar ik wil zelf dat het gegarandeerd goed is.
1
2
3
4
5
6
7
8
9
| #region PUKE HAZARD SuspendDispatch = true; var tick = Environment.TickCount; while (Environment.TickCount - tick < 2500) OpenNETCF.Windows.Forms.Application2.DoEvents(); // please god no... :@ lock (SuspendDispatchLock) { SuspendDispatch = true; // make double-sure } #endregion |
I rest my case.
Het hele idee dat de UI thread moet gaan wachten op iets is natuurlijk bij voorbaat fout. Een betere methode zou ongeveer het volgende moeten zijn: de UI thread zegt dat het een notificatie van 'iets' wil. Over (zeg) 10 seconden schedule je een callback die, indien 'iets' niet gebeurd is, daar melding van maakt en appropriate action onderneemt. De UI thread wacht nergens op en gaat lekker verder. Mocht 'iets' gebeuren, dan kan die de "er iets niets gebeurd" callback uitschakelen, en de UI thread vertellen dat 'iets' is gebeurd.
Wij onderbreken deze thread voor reclame:
http://kalders.be
Met soortgelijke boetes voor overtredingen dan wel! En verplicht op cursus bij te schrijnende overtredingenGrimaceODespair schreef op dinsdag 06 november 2012 @ 17:05:
Eigenlijk zou er voor Threading zoiets als een rijbewijs moeten zijn: Je mag niet aan threading doen als je geen Threading-bewijs hebt. Anders ben je strafbaar.
Dit topic is gesloten.
Uiteraard is het in dit topic niet de bedoeling dat andere users en/of topics aangehaald worden om ze voor gek te zetten. Lachen om je eigen code, of over dingen die je "wel eens tegengekomen bent" is prima, maar hou het onderling netjes.