Läs gärna artikeln om: Fredrik (och även Johan), Nu svarar Fredriks bror :-) Men Pelle verkar vara HELT omöjlig att nå... Vi har bett honom öppna krönikor men inget svar... Så vad gör man? :) Trycker nog inte att det är krönika material i heller...snarare en ren artikel Nepp, detta är inget körnika material utan mer en artikel som du säger men valde att lägga in det som ett forum inlägg för att kunna snabbt och enkelt skapa diskutioner kring ämnet och där ett forum är ett bra alternativ för det. Men du har säkert rätt att fler läser en artikel än hittar denna tråd, därför finns den även inskickad som en artikel men dock tar det ca: 1 vecka för en artikel att bli publicerad. Under tiden kan dom som läser denna tråd diskutera inlägget här. Ett fall när man inte kan ha returvärden för felhantering är vid konstruktorer. Då kan undantag vara smidiga att kasta. Tar tillbaka min text. Läste lite för hastigt och var i en irriterande sits... Sorry för det... Per: Byt ut exception med test? Det kan vara bra att göra tester på null mm så man slipper trista runtime exceptions...men att göra ett test och returnera en "felkod" som du gör i ditt andra exempel är ju motsägesefullt mot vad du du säger i ditt första exempel .Där vill du ju att man kastar exception istället för att returnera felkoder...hur går det ihop? Jag tycker inte att det andra exemplet är särskilt bra. Kontrollen är som sagt bra men om parametern inte är inom tillåtna värden borde ett exceptions kastas annars kan detta bara passera obemärkt förbi och skapa konstiga och svårhittade buggar. Nils: Jag håller fortfarande inte med. Att bara returnera en int fast något uppenbarligen är fel är ett väldigt konstigt sätt att hantera exceptions på i en applikation. Hur ska jag, som användare av api:et, veta att något har gått fel...jag får ju faktiskt tillbaka ett värde...hur vet jag att 0 betyder fel och inte är ett legitimt värde? Om jag vet att 0 betyder fel så måste det väl vara en sådan typ av felkod som du varnade för i första exemplet. Nils: Nils: Här finns olika designfilsofoer och olika sätt att lösa saker och ting på. Du skrev: "Metoden som användas som exempel har som uppgift att returnera ett värde om det finns något angivit för den period man anger som argument, finns inte värdet så returnerar vi 0 vilket inte är ett fel utan är ett standard värde för de perioder som inte har ett registrerat värde." Precis som du säger, så skulle inte du göra. Men vem säger att det är mer korrekt? I en flerskiktad och distribuerad arkitektur har du knappast en design där du kan ha en update metod på en user utan i affärslogiklagret har du kanske en metod som heter updatePerson(Person person) på en serviceklass, PersonService t ex. Då vill jag ha tillbaka Person objektet om allt går bra efterom jag kanske vill jobba vidare med personen...men som du säger olika system ställer olika krav...det är nog den viktigaste poängen du gör i ditt inlägg. Nils: Nils, Suck...jag ger upp. Vi pratar om två helt olika saker i två helt olika världar. Nils.Refactoring: Byt ut felkod med exception och byt ut exception med Test
Refactoring: Byt ut felkod med exception och byt ut exception med Test
http://www.pellesoft.se/area/articles/article.aspx?artid=831
Ge gärna feedback eller kommentarer i detta forumet. Skriv gärna egna fall och tips när exception kan eller bör slängas i detta forum.
/Fredrik Normén NSQUARED2
http://normen.mine.nu/myblogSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Varför inte skriva dessa som artiklar istället för inlägg i ett forum? Starta sedan en tråd där diskussionen kan fortlöpa och länka till den direkt från artiklen? Tror inte det är många som söker sig till forumet för att hitta information i artikelformat, så att publicera materialet som en artikel skulle fgör atat det når ut till fler personer.
Tyvärr är inte iheller detta forumet inte speciellt fullt av aktivitet iheller, så det gör att det troligen är ännu mindre folk som springer på informationen.Sv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Sv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Sv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
/Fredrik NorménSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Exempel:
<code>
class Rectangle {
private:
int left, top, width, height;
public:
class NoRectangle : public Exception { ... };
public:
Rectangle(int l, int t, int w, int h) : left(l), top(t), width(w), height(h) {
if(w<0 || h<0)
throw NoRectangle();
}
};
</code>Sv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Kul att du delar med dig åt folket. Sånt uppskattas.
Mvh JohanSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Ett mycket bra exempel där exception bör slängas. Om argument till en konstruktor är förväntat, så är det bra att slänga en exception. Även vid valiering, som i ditt fall där ett värde måste vara större eller lika med 0.
/Fredrik Normén NSQAURED2
http://normen.mine.nu/myblogSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Heter det inte "kasta" exceptions om man ska översätta "throws" till Svenska? "Slänger" känns helt fel :)
/NilsSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Bra att du märkte det. Exemplerna är kanske lite otydliga. Exempel 1, returnerar 0 eller -1, skulle även kunna returnera andra "felkoder". Metoden returnerar en speciel kod för att indikera ett fel. Exempel 2, returnerar inte en "felkod" utan ett "värde" exception i detta fall ska inte agera som en ersättare för ett test av ett tillstånd.
Angående "slänga" jämfört med "kasta" så har du nog rätt, ev så tror jag alla förstår vad jag skriver om, men jag ska gå igenom och ändra det, tycker "kasta" är ett bättra ord. Tack!
/Fredrik Normén NSQUARED2
http://normen.mine.nu/myblogSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Sv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Tänk dig detta senarie då. Du skall hämta en användare. Användaren finns inte fel koden blir en null retur. Rätt vanligt eller hur? När du updaterar en användare kanske du vill veta om det gick, då kollar du ju affected records om de är 0 returnera false är de 1 eller mer returnera true. Här gör du en test istället för att kasta ett exception. Precis som i Fredrik kod. Även om exemplet kanske är luddigt gäller det ju att se dess mänster inte fastna i orden eller hur? Det är oxå en egenskap som är possetiv hos utvecklare, att kunna se bakom ett exempel, ett exempel måste inte alltid vara baserat på något äkta, eller vad anser du? Hade det vart bättre om han ersatte orden med Foo istället? Jag personligen förstod exemplet utan problem även om jag inte hade sett det innan.
Mvh JohanSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Kanske jag har varit för otydlig i min artikel?
Om du ser på sista exemplet så istället för att fånga en exception och returnera 0 så görs ett test för att undvika att en exception uppstår. Metoden som användas som exempel har som uppgift att returnera ett värde om det finns något angivit för den period man anger som argument, finns inte värdet så returnerar vi 0 vilket inte är ett fel utan är ett standard värde för de perioder som inte har ett registrerat värde. Läs gärna texten en gång till och se på exemplerna så kanske du hänger med vad jag syftar på, om inte så ska jag försöka göra texten tydligare.
Tack för din feedback!
Mvh Fredrik Normén NSQUARED2
http://normen.mine.nu/myblogSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
"Tänk dig detta senarie då. Du skall hämta en användare. Användaren finns inte fel koden blir en null retur. Rätt vanligt eller hur?"
Ja, det är ganska vanligt att lösa det så, tyvärr ;). Ett snyggare sätt att lösa det är att kasta ett exception...för det är precis vad det är...ett undantag...man inte hittade användaren som man förväntade sig att hitta. Snyggare att kasta ett egendefinierat: NoSuchEntityException t ex. Om det ska vara ett checked exception eller runtime exception är sedan en annan fråga.
"När du updaterar en användare kanske du vill veta om det gick, då kollar du ju affected records om de är 0 returnera false är de 1 eller mer returnera true."
Om jag uppdaterar en användare så vill jag inte ha några ettor, nollor, false eller true tillbaka. Gick uppdateringen bra så kan man istället returnera den uppdaterade användaren, objektet, och gick det inte bra så *pang* kasta ett exception. Man kan med fördel använda runtimeexception om man inte kan rädda situatoinen på något sätt så slipper man bloata ner koden med en massa try/catch.
Jag ser som sagt inte mönstret i det...säg att man vill registrera en tid istället. Timmarna måste vara mellan 0-23 och minutrarna mellan 0-59...om man då anger 25:67 som timmar och minuter...hur ska appliaktionen reagera då? Den testar och ser att det inte riktigt stämmer...det är ju ockse en typ Index out of bounds. Ska man då returnera ett värde av någon typ? Snarare kasta ett exception.
Jag är forfarande inte övertygad...keep em coming :)
/NilsSv: Refactoring: Byt ut felkod med exception och byt ut exception med Test
Så tydligt står det inte beskrivet i din artikel men nu är jag med mer på vad du menar...fast jag tror inte att jag håller med att det är ett snyggt sätt att lösa just det exemplet som du visar ;) ...och jag vet itne om jag håller med om att det är en bra design principle...men vi tycker och tänker alla olika...och det är det som gör livet skoj :)
Ha det gott
/NilsSv: Refactoring: Byt ut felkod med exception och byt ut exception med Tes
Det är ju oftast systemkravet som vill säga hur saker gick.
Är det någon vits att exempelvis returnera en User om ex User.Update(user) gör att refferensen user är den du updaterar med? den innehåller ju datan om allt gick bra.
Att då returnera true eller false om updateringen gick ser inte jag som en felaktighet. Då du själv mot andra lager för bestämma hur detta skall handskas.
Sedan finns det ju olika skäl till varför en update inte gick genom, så troligen skickas olika Exception baserat på vilken källa som orsakade felet. Tänk om man updaterar userdata fast den datan du skickar in är korrekt vill du inte veta detta då? Genom att du får en true?
Om du ber om en person som inte finns så anser jag inte att du får ett untantag i mån av Exception.
Om du ropar efter Olle i skogen o han inte kommer inte rasar skogen samman? Det som händer är att ingen kommer null med andra ord.
Programmering är religion samt olika slags dialekter. Ingen är egentligen mer korrekt än det andra. Men ju närmre verkligheten du kan spegla betéendet ju mer korrekt är det. (beror ju på hur man tolkar verkligheten oxå.)
Mvh JohanSv: Refactoring: Byt ut felkod med exception och byt ut exception med Te
Du skrev "Om du ropar efter Olle i skogen o han inte kommer inte rasar skogen samman? Det som händer är att ingen kommer null med andra ord."
Ett dålig metafor faktiskt...om jag ropar på en metod t ex findByPrimaryKey(long id) som returnerar en person så förväntar jag ju mig att jag ska få en person tillbaka, eller gör man inte det(?)...får jag ingen person tillbaka så har ett undantag inträffat. Om jag tar det vidare på din metfor så går jag till skogen och ropar efter Olle och förväntar mig att han kommer...kommer han inte så har det skett ett undantag...skogen behöver inte rasa samman för att det ska vara ett undantag.
Men det är som sagt min syn att se på det. Vet inte om det finns mycket mer att säga i det här ämnet nu...känns som om det är uttömt.
/NilsSv: Refactoring: Byt ut felkod med exception och byt ut exception med T
Jag själv skulle undvika slänga en exception om jag frågar efter en användare som inte finns. Jag skulle använda mig av Martin Flowers reafcatroing "Introducing Null object" eller returnera null. Om jag skulle slänga ett exception så skulle jag behöva göra en try, catch, i det fallet skulle jag valt "Replace Exception With a Test".
Exempel där exception används:
<code>
public Class UserDA
{
public static User GetUserByUserName(string userName)
{
//.....
if( user == null )
throw new UserNotFoundException(...);
return user;
}
}
User user;
try
{
user = UserDA.GetUserByUserName("Admin");
}
catch(UserNotFoundException)
{
//...
}
</code>
Om jag skulle göra en refactoring på koden ovan så skulle jag använt mig av "Introducing Null" och "Replace Exception With a Test":
<code>
public Interface INullable
{
bool IsNull
{
get;
}
}
public Class User : INullable
{
public virtual bool IsNull
{
get { return false; }
}
}
public Class NullUser : User
{
public override IsNull
{
get { return true; }
}
}
public Class UserDA
{
public static User GetUserByUserName(string userName)
{
//.....
return ( user == null ) ? new NullUser() : user;
}
}
User user = UserDA.GetUserByUserName("Admin");
if( !user.IsNull )
//...
else
//...
</code>
Ev så skulle jag returnera null istället för ett NullUser objekt.
MEN skulle min GetUserByUserName enligt min spec ge ett fel om jag frågar efter en användare som inte finns, då skulle jag kasta en exception. Men om min GetUserByUserName är en generell metod som kan hämta en användare från olika datakällor med hjälp av providers, så skulle jag inte släng en exception eftersom jag kanske inte äger providerna och datakällorna som providerna går mot, så min metod måste utgå ifrån att användaren finns. Sedan är det upp till providern som används, om ett fel ska uppstå eller inte.
/Fredrik Normén NSQUARED2
http://normen.mine.nu/myblogSv: Refactoring: Byt ut felkod med exception och byt ut exception med T
Vem säger att min User inte skulle kunna ligga i affärsskiktet och ropa på en UserData (Datalagret)?
Sedan hade jag kanske gjort en class Person och då inte använt updatePerson(Person person) som namn då det är rätt uppenbart att jag redan är en person som vill updateras.
Person.update(person)
Det finns inga som helst regler i n-tier lösningar som kräver vart de olika namnen skall befinna sig.
Själv väljer jag att ha Eniteterna i ett eget lager. Sedan BOL, DAL och PL i sina separata. Där BOL mycket väl kan ha classer som User där DAL har UserData och där Enitetlagret (låt kalla det BE - Business Entity). kan ha en UserDescription eller UserInfo med dess attribut. Ja, vad som... Själv använder jag inte self mönstret där en entitet känner till sig själv. Utan det får DAL ta hand om. Alltså fylla upp datan baserat på någon slags identifiering.
findByPrimaryKey... Ja du. Får du exception när du kör Search för att göra en Find By FileName i exempelvis Linux eller Windows också? Eller får du tomt svar?
Och varför skall DAL kasta ett exception upp till BOL som sedan tar hand om det eller to m. får det att nå PL om en GetByName inte får tag i någon data? Borde inte DAL då ge null och i BOL får du själv bestämma vad du vill göra med detta resultat? Samma med Update om du updaterar så vill du ju från DAL få veta om det gick eller ej. Om det inte gick kan ju betyda att datan inte förändrats och på så vis inte updaterades där av affected 0, om det uppdaterades där av affectet mer än 0. Då anser du att ett exception skall slängas? Jag anser att exception skall slängas då det blir något fel, ex databasen kan inte nås, update sql-satsen var felaktig.
Att ropa efter Olle och inte få svar är ju inget undantag. Ett undantag vore ju mer om Per kom istället? Då vi inte vill acceptera en Per.
Som sagt. Programmering är som Religion och olika dialekter. I grupp handlar det om att komma överräns men för vida världen så gäller det att man har förståelse att det inte direkt finns strikta regler hur saker skall lösas. Det du anser bäst behöver inte vara bäst, men det är bäst för dig och mest rimligt då det ingår i ditt tankemönster. Man kan vrida o ha sig om verkligheten hur mycket man vill, men för mig är ett rop utan svar inget utantag. Det är ett rop utan svar. Om jag verkligen förväntar mig ett svar för att kunna fortsätta min resa fram i skogen så skulle kanske ett exception vara på sin plats då jag inte med tomt svar kan ta mig frammåt. I övrigt skulle jag nog bara bli förvånad, eller kanske inte ens kräva att jag får ett svar. Alla dessa berättelser kräver olika hanteringar. Sedan får man ju gå djupare ner i sin domän model för att se vem ansvarar för det ena eller det andra.
Mvh JohanSv: Refactoring: Byt ut felkod med exception och byt ut exception med
Sv: Refactoring: Byt ut felkod med exception och byt ut exception med
Gör vi? Hur då? Jag är nyfiken, vill gärna känna till de två "olika" världarna...
Ser väl inte direkt skillnad mellan att använda Java vs C# för skiktade lösningar.
Syftar du på MVC?
Mvh Johan