|
| paranoia error check i alle funktioner Fra : Troels |
Dato : 06-04-05 08:31 |
|
Der er nogen der prøver at få trumfet et niveau af error check i ALLE
funktioner igennem, som jeg synes begynder at ligne paranoia.
Jeg mener at have læst et par kommentarer her i gruppen med referencer til
en bog/webside der fremfører, at hvis dette gøres overdrevet og forkert, så
højner det faktisk ikke systemstabiliteten, mindsker ikke udviklingstiden,
etc - tvært imod.
Erder nogen der kan hjælpe med et link ?
tpt
| |
Niels Dybdahl (06-04-2005)
| Kommentar Fra : Niels Dybdahl |
Dato : 06-04-05 08:55 |
|
> Der er nogen der prøver at få trumfet et niveau af error check i ALLE
> funktioner igennem, som jeg synes begynder at ligne paranoia.
> Jeg mener at have læst et par kommentarer her i gruppen med referencer til
> en bog/webside der fremfører, at hvis dette gøres overdrevet og forkert,
så
> højner det faktisk ikke systemstabiliteten, mindsker ikke udviklingstiden,
> etc - tvært imod.
Der er ingen tvivl om at hvis det gøres "forkert", så sænker det
systemstabiliteten.
Og det øger uden tvivl udviklingstiden.
Det er også et helvede at teste al fejltestningskoden igennem.
Defor bruger nyere sprog exceptions istedet. Det giver den hurtige
udviklingstid, højere stabilitet (hvis man fanger disse exceptions på et
passende sted) og meget nemmere test af fejlhåndtering.
Så søg evt efter en begrundelse for hvorfor C++, C#, Java etc bruger
exceptions.
Niels Dybdahl
| |
Jesper Louis Anderse~ (06-04-2005)
| Kommentar Fra : Jesper Louis Anderse~ |
Dato : 06-04-05 11:12 |
|
Troels <nejtakjegf?rspamnok@dk.dk> wrote:
> Der er nogen der pr?ver at f? trumfet et niveau af error check i ALLE
> funktioner igennem, som jeg synes begynder at ligne paranoia.
> Jeg mener at have l?st et par kommentarer her i gruppen med referencer til
> en bog/webside der fremf?rer, at hvis dette g?res overdrevet og forkert, s?
> h?jner det faktisk ikke systemstabiliteten, mindsker ikke udviklingstiden,
> etc - tv?rt imod.
Det er ikke helt klart hvad du mener med error check. Mener du noget i stil
med
foobar (baz *p)
{
assert(p != NULL);
...
}
Eller, mener du det, som Niels Dybdal siger (at man checker returvaerdi
for et systemkald). Det sidste er paa nogen maader et problem, men med
passende abstraktionsbibliotek er det faktisk til at komme uden om. Det
tager dog lang tid at skrive et saadant. Jeg foretraekker som regel
exception-baserede mekanismer, der _ikke_ bare er bygget paa setjmp(). Det
har jeg set for mange gange nu, til jeg synes det er sjov.
Du kunne ogsaa mene unit-tests. Det tror jeg generelt ikke saenker laesbarheden
og stabiliteten af koden.
Kort sagt, hvad mener du?
--
jlouis
| |
Troels (06-04-2005)
| Kommentar Fra : Troels |
Dato : 06-04-05 15:27 |
|
Generelt:
Jeg mener at en funktion / modul bør lave checks på de ting den har ansvar
for. Om det giver mening på et højere niveau, har det ovenliggende niveau
ansvar for, og så må det checkes her.
Hvis jeg har en driverfunktion der har til opgave at tænde noget lys, er jeg
imod at indføre noget kode i driveren der checker om system staten er som
den skal være. Hvis nogen kalder lightOn() ja så tændes lyset.
Derudover så irriterer den sidste else i dette mig :
typedef enum
{
FALSE,
TRUE
}BOOL;
BOOL testSomething ()
{
if ( ....)
return TRUE;
else
return FALSE
}
void myFunc()
{
if ( testSomething () == TRUE )
{
.........
}
else if ( testSomething () == FALSE )
{
......
}
else
{
// panic !!
}
}
En anden udgave af det samme: Switch som en luxus if er forbudt :
switch (state)
{
case ON:
case PAUSE:
doSomething
}
skal laves således at ALLE enum værdier nævnes:
switch (state)
{
case ON
case PAUSE
doSomething()
break;
case OFF
// do nothing
break;
default:
doPanic(); // unknown state
break;
}
Her er jeg måske bare sart?
tpt
"Jesper Louis Andersen" <jlouis@miracle.mongers.org> skrev i en meddelelse
news:n8pci2-9t4.ln1@miracle.mongers.org...
> Troels <nejtakjegf?rspamnok@dk.dk> wrote:
>
>> Der er nogen der pr?ver at f? trumfet et niveau af error check i ALLE
>> funktioner igennem, som jeg synes begynder at ligne paranoia.
>> Jeg mener at have l?st et par kommentarer her i gruppen med referencer
>> til
>> en bog/webside der fremf?rer, at hvis dette g?res overdrevet og forkert,
>> s?
>> h?jner det faktisk ikke systemstabiliteten, mindsker ikke
>> udviklingstiden,
>> etc - tv?rt imod.
>
> Det er ikke helt klart hvad du mener med error check. Mener du noget i
> stil
> med
>
> foobar (baz *p)
> {
> assert(p != NULL);
>
> ...
> }
>
> Eller, mener du det, som Niels Dybdal siger (at man checker returvaerdi
> for et systemkald). Det sidste er paa nogen maader et problem, men med
> passende abstraktionsbibliotek er det faktisk til at komme uden om. Det
> tager dog lang tid at skrive et saadant. Jeg foretraekker som regel
> exception-baserede mekanismer, der _ikke_ bare er bygget paa setjmp(). Det
> har jeg set for mange gange nu, til jeg synes det er sjov.
>
> Du kunne ogsaa mene unit-tests. Det tror jeg generelt ikke saenker
> laesbarheden
> og stabiliteten af koden.
>
> Kort sagt, hvad mener du?
>
>
> --
> jlouis
| |
Morten Guldager (06-04-2005)
| Kommentar Fra : Morten Guldager |
Dato : 06-04-05 17:48 |
|
2005-04-06 Troels wrote
>
> Generelt:
> Jeg mener at en funktion / modul bør lave checks på de ting den har ansvar
> for. Om det giver mening på et højere niveau, har det ovenliggende niveau
> ansvar for, og så må det checkes her.
>
> Hvis jeg har en driverfunktion der har til opgave at tænde noget lys, er jeg
> imod at indføre noget kode i driveren der checker om system staten er som
> den skal være. Hvis nogen kalder lightOn() ja så tændes lyset.
>
> Derudover så irriterer den sidste else i dette mig :
> ...
> default:
> doPanic(); // unknown state
> break;
> }
>
> Her er jeg måske bare sart?
Det synes jeg. Det er meget almindeligt at nogen får introduceret en
ny funktionalitet i en andens kode, helt uden at fortælle om det.
Den slags kan man fange med sådan en "internal program error" ting.
Jeg bruger ihvertfald den slags "dette er en umulig situation" checks
i mine statemaskiner. (som dog er skrevet i perl)
/Morten
| |
Jesper Louis Anderse~ (06-04-2005)
| Kommentar Fra : Jesper Louis Anderse~ |
Dato : 06-04-05 19:00 |
|
Troels <nejtakjegf?rspamnok@dk.dk> wrote:
> Her er jeg m?ske bare sart?
Nej, du har bare valgt det forkerte sprog at programmere i. Du er noedt til at
lave en del safeguarding, fordi det som regel fjerner fejl af den mere lumske
type. Jeg synes ikke at defensiv programmering er en daarlig ting. Tvaertimod.
--
jlouis
| |
Niels Dybdahl (07-04-2005)
| Kommentar Fra : Niels Dybdahl |
Dato : 07-04-05 08:41 |
|
> Derudover så irriterer den sidste else i dette mig :
>
> typedef enum
> {
> FALSE,
> TRUE
> }BOOL;
>
> BOOL testSomething ()
> {
> if ( ....)
> return TRUE;
> else
> return FALSE
> }
>
> void myFunc()
> {
> if ( testSomething () == TRUE )
> {
> .........
> }
> else if ( testSomething () == FALSE )
> {
> ......
> }
> else
> {
> // panic !!
> }
> }
Hvis det er et multitrådet program, så kan testSomething returnere noget
andet i andet kald end første også giver det mening. Hvis det ikke er
multitrådet så er der ikke så meget mening i at kalde testSomething to gange
og så falder det sidste else væk.
> En anden udgave af det samme: Switch som en luxus if er forbudt :
> switch (state)
> {
> case ON:
> case PAUSE:
> doSomething
> }
>
> skal laves således at ALLE enum værdier nævnes:
> switch (state)
> {
> case ON
> case PAUSE
> doSomething()
> break;
> case OFF
> // do nothing
> break;
> default:
> doPanic(); // unknown state
> break;
> }
Det er en god vane altid at inkludere default. Derved tvinges man til at
overveje hvad der skal ske ved andre værdier. Ofte kan man bare sætte en
kommentar og en break ind, så andre kan læse at situationen er blevet
overvejet.
Niels Dybdahl
| |
Troels (08-04-2005)
| Kommentar Fra : Troels |
Dato : 08-04-05 11:16 |
|
>
> Hvis det er et multitrådet program, så kan testSomething returnere noget
> andet i andet kald end første også giver det mening. Hvis det ikke er
> multitrådet så er der ikke så meget mening i at kalde testSomething to
> gange
> og så falder det sidste else væk.
>
Ja, to kald af funktionen er fjollet, men det bagvedliggende princip om
"check af hele værdimængden" hvor jeg skal checke om min BOOL enum er
_andet_ end TRUE eller FALSE holder jo stadig. Og det hader jeg.
Iøvrigt står der heldigvis "bør" mange steder i en sådan kodestandard, så
lidt plads er der vel til sund fornuft. Det kunne jo være at man fik en
konsensus om at det er ok at nøjes med at checke TRUE/FALSE på lige netop
BOOL typen.
tpt
| |
Mogens Hansen (07-04-2005)
| Kommentar Fra : Mogens Hansen |
Dato : 07-04-05 18:35 |
|
"Troels" <nejtakjegfårspamnok@dk.dk> wrote in message
news:4253902b$0$243$edfadb0f@dread11.news.tele.dk...
>
> Der er nogen der prøver at få trumfet et niveau af error check i ALLE
> funktioner igennem, som jeg synes begynder at ligne paranoia.
Meget generelle regler, der siger at ALLE funktioner skal et eller andet vil
være vanskelige at gennemføre, idet verden ikke er tilstrækkelig homogen.
Reglerne skal være lidt mere afslappet for at være troværdige.
Når det er sagt er det en vældig god ide at overveje hvad der er pre- og
post-condition for at kalde en funktion.
Altså hvilke betingelser skal være opfyldt for at man må kalde funktionen,
og hvilke betingelser er garanteret at gælde når funktionen har returneret.
Man kan sikkert finde noget nyttigt om emnet ved f.eks. at kigge på nogen af
de overvejelser som Betrand Meyer har i gjort i forbindelse med design by
contract.
I C og C++ kan man udtrykke pre- og post-conditions ved at anvende assert.
På den måde bliver det både dokumenteret overfor andre programmører og det
bliver løbende verificeret under udvikling at det bliver overholdt.
Et godt eksempel jeg lige faldt over stammer fra "C/C++ Users Journal",
april 2005 side 51:
vector<int>::size_type firstprod(const vector<int>& v, int n)
{
assert(!v.empty());
for(vector<int>::const_iterator it = v.begin(); it != v.end(); ++it) {
int val = *it * n;
if(val > v.back())
return val;
}
assert(false);
}
Den første assert siger at det er en pre-condition at "v" ikke er tom.
Den anden assert siger at det er en post-condition at det var muligt at
finde et gyldigt svar.
Man kunne have valgt andre løsninger:
* Putte noget i vectoren hvis den er tom
* Kaste en exception hvis den er tom
men den form for defensiv programmering, vil kunne dække over en
misforståelse hos programmøren der kalder funktionen.
Generelt syntes jeg at det er bedre at et program går ned med et højt brag
end at det forsøger at fortsætte på ukendte forudsætninger.
> Jeg mener at have læst et par kommentarer her i gruppen med referencer til
> en bog/webside der fremfører, at hvis dette gøres overdrevet og forkert,
> så højner det faktisk ikke systemstabiliteten, mindsker ikke
> udviklingstiden, etc - tvært imod.
Jeg mener at overvejelser og klarhed omkring pre- og post-condition kan
bidrage væsentligt til at øge system stabilitet, mindske udviklingstid og
lette vedligehold.
Venlig hilsen
Mogens Hansen
| |
Troels (08-04-2005)
| Kommentar Fra : Troels |
Dato : 08-04-05 11:07 |
|
>
> vector<int>::size_type firstprod(const vector<int>& v, int n)
> {
> assert(!v.empty());
> for(vector<int>::const_iterator it = v.begin(); it != v.end(); ++it)
> {
> int val = *it * n;
> if(val > v.back())
> return val;
> }
> assert(false);
> }
>
> Den første assert siger at det er en pre-condition at "v" ikke er tom.
> Den anden assert siger at det er en post-condition at det var muligt at
> finde et gyldigt svar.
>
Ja, den checker på alle de ting den har at operere på. Fint.
En anden ting er så at funktionen vil blive fanget af (forslag til) vores
kodestandard på to andre punkter, nemlig.
* multible exit-points
* for løkker skal altid køres helt igennem, ellers bruges top / bundtest
konstruktionerne while eller do-while
Hvad synes folk om disse to regler ?
( personligt holder jeg meget af at breake mig ud af for sætninger , men
.... )
tpt
| |
Morten Guldager (08-04-2005)
| Kommentar Fra : Morten Guldager |
Dato : 08-04-05 13:52 |
|
2005-04-08 Troels wrote
>>
>> vector<int>::size_type firstprod(const vector<int>& v, int n)
>> {
>> assert(!v.empty());
>> for(vector<int>::const_iterator it = v.begin(); it != v.end(); ++it)
>> {
>> int val = *it * n;
>> if(val > v.back())
>> return val;
>> }
>> assert(false);
>> }
>
> En anden ting er så at funktionen vil blive fanget af (forslag til) vores
> kodestandard på to andre punkter, nemlig.
> * multible exit-points
> * for løkker skal altid køres helt igennem, ellers bruges top / bundtest
> konstruktionerne while eller do-while
>
> Hvad synes folk om disse to regler ?
Trælse.
> ( personligt holder jeg meget af at breake mig ud af for sætninger
Det er ihvertfald også en teknik jeg bruger ofte.
Men det kræver at man så har styr på e.v.t. oprydning andetsteds.
/Morten
| |
Niels Dybdahl (08-04-2005)
| Kommentar Fra : Niels Dybdahl |
Dato : 08-04-05 14:35 |
|
> > vector<int>::size_type firstprod(const vector<int>& v, int n)
> > {
> > assert(!v.empty());
> > for(vector<int>::const_iterator it = v.begin(); it != v.end(); ++it)
> > {
> > int val = *it * n;
> > if(val > v.back())
> > return val;
> > }
> > assert(false);
> > }
> >
> > Den første assert siger at det er en pre-condition at "v" ikke er tom.
> > Den anden assert siger at det er en post-condition at det var muligt at
> > finde et gyldigt svar.
> >
>
> Ja, den checker på alle de ting den har at operere på. Fint.
>
> En anden ting er så at funktionen vil blive fanget af (forslag til) vores
> kodestandard på to andre punkter, nemlig.
> * multible exit-points
> * for løkker skal altid køres helt igennem, ellers bruges top / bundtest
> konstruktionerne while eller do-while
> Hvad synes folk om disse to regler ?
Som nævnt bruger jeg exceptions til fejlhåndtering, hvilket gør at der er
mange exitpoints i mine programmer.
Løkker bliver uoverskuelige, hvis man skal plastre dem til med boolske
variable, som holder styr på om man skal hoppe ud ved slutningen eller ej.
Så foretrækker jeg en pænere struktur som for det meste afspejler problemet
bedre.
Da jeg læste på DTH blev vi også frarådet at opbygge "tilstandsmaskiner"
hvor det ikke er nødvendigt.
Niels Dybdahl
| |
Mogens Hansen (08-04-2005)
| Kommentar Fra : Mogens Hansen |
Dato : 08-04-05 18:36 |
|
"Troels" <nejtakjegfårspamnok@dk.dk> wrote in message
news:425657db$0$276$edfadb0f@dread11.news.tele.dk...
> >
>> vector<int>::size_type firstprod(const vector<int>& v, int n)
>> {
>> assert(!v.empty());
>> for(vector<int>::const_iterator it = v.begin(); it != v.end(); ++it) {
>> int val = *it * n;
>> if(val > v.back())
>> return val;
>> }
>> assert(false);
>> }
>>
>> Den første assert siger at det er en pre-condition at "v" ikke er tom.
>> Den anden assert siger at det er en post-condition at det var muligt at
>> finde et gyldigt svar.
>>
>
> Ja, den checker på alle de ting den har at operere på. Fint.
>
> En anden ting er så at funktionen vil blive fanget af (forslag til) vores
> kodestandard på to andre punkter, nemlig.
> * multible exit-points
Det kan være meget nyttigt at returnere fra flere steder i en funktion.
Det kan sagtens gøre strukturen mere klar. Ikke mindst hvis man anvender det
med RAII.
> * for løkker skal altid køres helt igennem, ellers bruges top / bundtest
> konstruktionerne while eller do-while
Se ovenstående funktion - der er vist ikke noget objektivt at udsætte på
den.
>
> Hvad synes folk om disse to regler ?
Meget firkantede regler er sjældent fornuftige.
Uddannelse der belyser baggrunder for hvorfor nogle foreslår en given regel
er langt mere nyttig.
Venlig hilsen
Mogens Hansen
| |
Jesper Dybdal (08-04-2005)
| Kommentar Fra : Jesper Dybdal |
Dato : 08-04-05 19:00 |
|
"Troels" <nejtakjegfårspamnok@dk.dk> wrote:
>En anden ting er så at funktionen vil blive fanget af (forslag til) vores
>kodestandard på to andre punkter, nemlig.
>* multible exit-points
>* for løkker skal altid køres helt igennem, ellers bruges top / bundtest
>konstruktionerne while eller do-while
>
>Hvad synes folk om disse to regler ?
De er absurde. Så skal man jo til at simulere de to konstruktioner vha.
booleans, og det gør da koden helt ulæselig - og forøger risikoen for fejl
betragteligt.
Hvis jeg har forstået dig ret, så skal I fx omskrive den helt normale og
perfekt læselige konstruktion:
for (;;)
{ <kodestump A>
if (<betingelse>)
break;
<kodestump B>
}
til enten noget med kodegentagelse:
<kodestump A>
while (!<betingelse>)
{ <kodestump B>
<kodestump A>
}
eller noget med at bruge en boolean til at implementere break:
Done = FALSE;
while (!Done)
{ <kodestump A>
if (<betingelse>)
Done = TRUE;
else
<kodestump B>
}
Begge dele er umådelig kluntede i forhold til den naturlige med break - og man
kan alligevel først gennemskue logikken når man har indset at det bare er en
løkke med exitbetingelsen i midten, skrevet på ulæseligt Pascal'sk i stedet
for med C's naturlige "break". Det samme gælder multiple "return"s.
Hvis din arbejdsplads vil have Pascal-kode, hvorfor så bruge en C-oversætter
til det?
Paranoide fejltjek har jeg derimod meget sympati for - hvis det ikke
overdrives.
--
Jesper Dybdal, Denmark.
http://www.dybdal.dk (in Danish).
| |
|
|