Avatar billede poul10 Nybegynder
22. juni 2011 - 14:53 Der er 20 kommentarer og
2 løsninger

Fejlhåndtering

Hej med jer,
Jeg har lidt svært ved at finde den "bedste" måde at håndtere fejl på. Jeg skriver lige 2 eksempler, men kom endelig mere bedre ideer (tag jer ikke af kodefejl)

Ex 1)
Function Test(Byval test as string) As List(Of String)
    Dim fejlList As New List(Of String)()
 
    'Noget logik

    'Hvis der sker en fejl
    fejlList.Add(fejl)

    Return fejlList
End function

Altså en metode der returnerer en liste af strings som indeholder mine fejl.

Ude på min brugergrænseflade vil jeg så lave noget ala:

Dim fejlList As List(Of String) = Test("test...")

If fejlList.Count > 0
  'Skriv til en fejl log

Det er bare ikke så sigende og heller ikke særligt pænt.


-----------------------------------------

Eksempel 2:

Sub Test(Byval test as string, ByRef fejlList As List(Of String))
      'Noget logik

      'Hvis der sker fejl
      fejlList.Add(fejl)
End sub

Ude på grænsefladen:

Dim fejlList as New List(Of String)()
Test("Test....", fejlList)

If fejlList.Count > 0
    'Skriv til fejl log..

-------------------------------------
Jeg har mest valgt løsning 2, men nu kommer min kode til tider til at se ret grim ud når jeg kalder flere metoder der kræver fejlhåndtering:

Dim fejlList as New List(Of String)()
Test("Test....", fejlList)

if fejlList.Count = 0
    'Kalder Metode nummer 2 som også har sin egen fejlList
    Dim fejlList2 as new List(Of String)()
    Test2("Test2...", fejlList2)

    if fejlList2.Count > 0
        'Skriv til fejllog
    end if
else
    'skriv til fejllog
end if

Der kan sagtens være en masse "Skriv til fejl log" hele vejen ned og det irriterer mig lidt..

Så mit spørgsmål.. god/pæn fejlhåndtering.. How to? :)
Avatar billede plug1n Nybegynder
22. juni 2011 - 18:24 #1
øhh kan du ikke benytte exceptions?
Avatar billede poul10 Nybegynder
22. juni 2011 - 18:47 #2
Jo, men den fejl der bliver smidt af exceptionen smider jeg også ned i fejlList.

Ex:

Sub Metode(ByVal fejlList as list(of string))
    Try
        ValiderItem(fejlList)
        'Her sker der en valideringsfejl som jeg ligger ned i
          fejlList

        HentData()
        'HentData crasher og vi får en exception
    Catch (ex as Exception)
        fejlList.Add(ex.Message)
    End Try
End Sub

Ude på grænseflade:

kører igennem alle items i fejlList (hvis der er nogle) og skriver dem til en tabel i databasen..

Giver det mening eller laver jeg noget virkelig underligt?
Avatar billede plug1n Nybegynder
22. juni 2011 - 19:21 #3
Altså personligt vil jeg mene det er tosset at gøre det sådan. Jeg ville bare kaste den videre og så fange den, der hvor du på nuværende tidspunkt læser fra din liste.

jeg har lidt svær ved at se hvorfor du ønsker at lægge exceptions ned i en database...
-Skal du ikke bare håndtere dem og så videre i teksten?

Du er med på at hvis du i en catch blok fanger ex, kan du bare sige throw ex, så fortsætter den op af stakken?

Man kan sige at du flytter noget data der normalt ligger på stakken ind i din liste. -Og det ser jeg ikke umiddelbart nogen grund til.
Avatar billede poul10 Nybegynder
22. juni 2011 - 22:43 #4
jeg har lidt svær ved at se hvorfor du ønsker at lægge exceptions ned i en database...
-Skal du ikke bare håndtere dem og så videre i teksten?


Hvis jeg har et program/service der står og kører om natten vil jeg gerne kunne tjekke hvad der er gået galt hvis systemet ikke kører som det skal.. Jeg kunne også smide sådan nogle ting ned i Application loggen men jeg føler har jeg et bedre overblik i min egen log hvor jeg kan logge hvad jeg har lyst til.

Hvordan vil du logge 2 fejl på samme tid?
I mit tidligere eksempel kan der jo godt være en valideringsfejl som jeg gerne vil logge så jeg kan se hvad brugeren gjorde galt, men jeg har ikke lyst til at kaste denne som en exception da systemet i princippet godt kan køre videre.. jeg føler lidt at exceptions er "store" ting som gør at jeg ikke kan komme videre og derfor at nød til at afbryde
Avatar billede plug1n Nybegynder
22. juni 2011 - 23:26 #5
Nej, sådan må du ikke opfatte en exception.
En exception skal kastes når du kommer ud for en situation du ikke - på det pågældende sted - i koden kan gøre noget ved.
Ved at kaste den, 'håber' du der er nogen/noget på et højere niveau der ved hvad der så skal ske.

Et eksempel kunne være en database timeout.
metoden der opererer med databasen ved sandsynligvis ikke hvad der skal ske i tilfælde af en sådan, men hvis der er en GUI vil det være meget simpelt blot at ignorere fejlen og bede brugeren forsøge igen når der er netforbindelse.

Hvis du ønsker at logge ting som ikke nødvendigvis er exceptions, tror jeg du skulle overveje at lave en 'helper' du kan kalde, som så sørger for at skrive til databasen.
Når du så opdager en validerings fejl (som bestemt heller ikke skal kaste en exception!!) laver du et kald som minder om dette:

Helper.RegistrerError("msg");

Helperen skal så indeholde logik til at gemme fejlene ned i databasen og hvad du ellers måtte ønske.

Du kan indkapsle din Main() i en try-catch blok, og kommer man i catch delen, ved du der er blevet kastet en exception som du ikke har håndteret.
Jeg anbefaler dig at gemme stackTracen fra dine exceptions, da det hjælper MEGET når du skal finde ud af hvad fejlen er.


Håber det giver nogenlunde mening !?
Det er naturligvis kun mit forslag til en løsning :-D
Avatar billede plug1n Nybegynder
22. juni 2011 - 23:41 #6
Kig evt på:
http://bit.ly/lgAIEh
Avatar billede arne_v Ekspert
23. juni 2011 - 03:55 #7
Lidt blandede kommentarer:

1) jeg vil helt klart foretraekke loesning #2, da listen med fejl er en side effect og ikke den primaere retur vaerdi

2) og det bliver netop smart ved multiple kald, da du kan faa puttet alle fejlene i samme liste (du skal ikke oprette en ny liste for hver kald)

3) exceptions er en rigtige maade at returnere fejl fra lavere lag til hoejere lag, men paa et tidspunkt skal de jo fanges og haanteres

4) for log filer og lignende der henvender sig til IT folk boer man bare logge de raa exceptions (helst med stack trace)

5) men for slut bruger UI skal fejlene praesenteres for brugerne paa en lidt paenere maade

6) det er ret standard at lade lavere lag returnere bruger venlige fejl beskeder i en liste til praesentations laget

7) dit eksempel med natligt batch job maa falde ind under #5 ikke #6
Avatar billede arne_v Ekspert
23. juni 2011 - 04:00 #8
Med hensyn til linket i #6:

A) det meste af det er rigtigt gode raad

B) man skal vaere opmaerksom paa at Java har checked og unchecked exceptions mens .NET kun har unchecked exceptions, saa noget er ikke relevant for VB.NET

C) jeg er meget uenig i at "log and throw" er et anti pattern

det er ikke det store praktiske problem at samme problem giver anledning til flere loggede exceptions

det er derimod et stort problem at kode goer nogle antaglser omkring den kaldende kode med hensyn til logning af fejl som ikke bliver checket og som kan have meget uheldige foeler hvis de ikke er opfyldt
Avatar billede poul10 Nybegynder
23. juni 2011 - 08:34 #9
plug1n:
Jeg føler bare det hjælper min kode mere hvis jeg tjekker en "fejlList" igennem for alle slags fejl fremfor kun at håndtere "ikke exceptions".

Main()
    Metode1(fejlList)
   
    if fejlList.Count > 0
      'Log her, uanset om fejlen indeholde en exception med stacktrace eller om det er en valideringsfejl. Jeg skal ikke få lov til at komme videre i systemet, men jeg vil logge hvorfor.
    end if

Modsat:

Main()
    Try
          Metode1(feljList)

          if fejlList.Count > 0
              'Log en masse andet udover exceptions
          end if
    Catch(ex As Exception)
          'Log exception
    End Try

Arne:
Du har ret i at det er dumt at jeg laver en liste for hver gang, det behøver jeg naturligvis ikke

3) exceptions er en rigtige maade at returnere fejl fra lavere lag til hoejere lag, men paa et tidspunkt skal de jo fanges og haanteres

Hvad siger du til min løsning med at smide alle former for fejl i en liste?
Avatar billede poul10 Nybegynder
23. juni 2011 - 08:42 #10
En anden ting var noget af det jeg prøvede at beskrive tidligere.
Hvis vi ser bort fra om fejlList skal medtage Exceptions eller ej så vil jeg til tider løbe i en situation ala:

Main()
    Metode1(fejlList)
    if fejlList.Count > 0
        'Log
    else
        Metode2(fejlList)       
        if fejlList.Count > 0
            'Log
        else
            Metode3(fejlList)
            if fejlList.Count > 0
              'Log
            end if
        end if
    end if

osv.. Der kan godt komme en del "if fejlList.Count > 0 blabla..", det er ik skide pænt.. har i nogle forslag her?
Avatar billede plug1n Nybegynder
23. juni 2011 - 10:25 #11
Hej Arne. Jeg kunne godt tænke mig at høre lidt mere om den strategi med at returnere fejllister. Hvilke fordele indebærer det at gøre sådan?

Poul.
Grunden til jeg ikke ville gøre det med at sende lister rundt, skyldes at jeg ville mene det forurener koden. Et kald ud til en static helper metode er til at forstå når du vender tilbage til koden.

Men nu er jeg ikke senior udvikler endnu, så lur mig om ikke Arne har en kende mere styr på det :-)
Avatar billede arne_v Ekspert
23. juni 2011 - 17:15 #12
re #9)

Jeg vil kun bruge fejl liste i tilfaelde af at brugervenlige fejl beskeder skal vises til bruger.
Avatar billede arne_v Ekspert
23. juni 2011 - 17:17 #13
re #10)

Du logger unconditional hvor du har brug for det.

Og i UI itererer du over listen med fejl beskeder.

Ingen if overhovedet.
Avatar billede arne_v Ekspert
23. juni 2011 - 17:18 #14
re #11)

Fordelen med en fejl liste er at brugeren faar alle fejlene paa en gang. I.s.f. at skulle submitte data igen og igen og hver gang faa en ny fejl.
Avatar billede poul10 Nybegynder
23. juni 2011 - 17:31 #15
mht #13
Jeg er ikke sikker på hvad du mener Arne.. Jeg vil jo kun kalde Metode2 hvis der ikke er nogle fejl i metode1, så jeg er vel nød til at lave et tjek?
Kan du give et eksempel muligvis, jeg vil gerne slippe af med det kode i hvert fald hvis jeg kan
Avatar billede arne_v Ekspert
24. juni 2011 - 04:25 #16
Demo:

using System;
using System.Collections.Generic;

namespace E
{
    public class Program
    {
        public static void M1(int v1, List<string> err)
        {
            Console.WriteLine("M1");
            if(v1 < 1)
            {
                err.Add("v1 is too small");
            }
        }
        public static void M2(int v2, List<string> err)
        {
            Console.WriteLine("M2");
            if(v2 < 1)
            {
                throw new Exception("v2 is too small");
            }
        }
        public static void M3(int v3, List<string> err)
        {
            Console.WriteLine("M3");
        }
        public static void BL(int v1, int v2, int v3, List<string> err)
        {
            try
            {
                M1(v1, err);
                M2(v2, err);
                M3(v3, err);
            }
            catch(Exception ex)
            {
                err.Add(ex.Message);
            }
        }
        public static void PL(int v1, int v2, int v3)
        {
            List<string> err = new List<string>();
            BL(v1, v2, v3, err);
            foreach(string e in err)
            {
                Console.WriteLine(e);
            }
        }
        public static void Main(string[] args)
        {
           
            PL(0, 0, 0);
            Console.ReadKey();
        }
    }
}
Avatar billede poul10 Nybegynder
24. juni 2011 - 08:59 #17
Tak for eksemplet. Jeg tror vi lukker den her. Smid et svar så får i point :)
Avatar billede poul10 Nybegynder
24. juni 2011 - 09:15 #18
Og dog..
Arne:

Lad os sige at M1 er en metode som henter en bruger fra databasen. Denne metode fejler så, kan være pga. en validering, og man får ikke en bruger tilbage.

Metode2 kræver så at man skal bruge denne bruger, men i dit eksempel tjekker man ikke for fejl i metode1, så man kalder bare metode2 uden en bruger og så fejler den også naturligvis.
Avatar billede arne_v Ekspert
24. juni 2011 - 15:04 #19
Hvis der ikke skal fortsaettes normalt saa smider du en exception.

Det er hvad M2 illusterer.
Avatar billede arne_v Ekspert
24. juni 2011 - 15:04 #20
svar
Avatar billede arne_v Ekspert
24. juni 2011 - 15:04 #21
plug1n har ioevrigt ogsaa bidraget i traaden
Avatar billede plug1n Nybegynder
24. juni 2011 - 19:15 #22
Jamen jeg kaster også et lille frækt svar :-)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester