Идиом за справяне с експлозията на код за грешки в Go

  1. Имам голям проблем със изгледа на кода ми след като се справя с всички грешки. Никой никога не трябва да ги игнорира. В следствие на странната идея "няма exeption-и" се получава крайно грозен код. Нека говоря с такъв:

    func (lib LocalLibrary) AddMedia(filename string) error {
        _, err := os.Stat(filename)
    
        if err != nil {
            return err
        }
    
        file, err := taglib.Read(filename)
    
        if err != nil {
            return err
        }
    
        artistID, err := lib.getArtistID(file.Artist())
    
        if err != nil {
            return err
        }
    
        albumID, err := lib.getAlbumID(file.Album(), artistID)
    
        if err != nil {
            return err
        }
    
        err = lib.insertTrack(file.Title(), artistID, albumID)
    
        if err != nil {
            return err
        }
    
        return nil
    }
    

    Ще забележите ужасно повтарящите се

        if err != nil {
            return err
        }
    

    Общо взето ако проверите репозиторията на проекта ми ще забележите, че тези три реда са повторени много десетки пъти. Има и няколко вариации, които също се повтарят често и при това една след друга в една и съща функция. Всъщност няма да е никакво преувеличение ако кажа, че поне 40% от кода ми е повторение на горните 3 реда. В примера са 65%. Това просто не трябва да е така. Има ли някакъв идиом с който се справяме с това? До сега нищо не ми е хрумнало. Освен да го правя като kernel хората с goto? Но goto нищо няма да промени точно в този случай. Даже ще добави още повече код и ще го направи по - трудно четимо.

  2. Ще трябва да заменя if err == nil {...} със if if albumID == nil {...} - все тая. Дори сега е по - добре защото поне са абсолютно еднакви. А преместването в друга функция няма да помогне защото тази функция пак ще трябва да връща грешка, когато е имало такава при четене. Ако това което исках е да няма if-ове щеше да правя thing, _ = function(..) и изобщо да не ме интересуват грешките :) За нещастие това е кратък път към ада!

  3. Аз имах предвид нещо от този сорт:

    func (lib LocalLibrary) AddMedia(filename string) error {
        file, err := fooReadsAFile(filename)
    
        if err != nil {
            return err
        }
    
        artistID := lib.getArtistID(file.Artist()) // artistID, _ := ... is also good
    
        albumID := lib.getAlbumID(file.Album(), artistID)
    
        return lib.insertTrack(file.Title(), artistID, albumID) // returns error if nil in the arguments
    }
    

    Не знам какво правиш в getArtistID и getAlbumID, но според мен няма смисъл да връщат грешки. Ако има някаква валидация на данните от файла просто я махни от там и я сложи след четенето от файла.

  4. @Кирил и Роб: и преди да ми кажете знаех, че не е правилно. И дваматa не успявате да кажете как е :Д Това прави коментарите ви не особено полезни.

    @Александър: не е лоша идея, но така ще загубя грешките. И всъщност само ще изместя if-овете от AddMedia в insertTrack. Също така трудно се парви int, който също така може да е и nil в go. Като допълнителен проблем ще е, че веднъж стигнал до insertTrack и видял, че има нещо нередно (artistID или albumID е nil), вече няма да знам какво е било нередно. И ще трябва да върна някаква измислена генерална грешка "няма (артист|албум)", като по този начин всъщност скрия истинския проблем. Това ще е ад ако трябва да го дебъгвам след това. А getArtistID и getAlbumID ровят в базата данни и е напълно възможно да се случат цяла плеяда от грешки. Някой е изтрил файла на базата междувременно, диска се е счупил, свършила е рамта и не може да се направят заявки, вече нямам права да чета и още кой ли знае какво.

    От друга страна ако съм се погрижил грешката да стигне до правилното място и всъщнот тя гласи "not an error" все тая че съм се борил :) За щастие вече съм си я превел:

    not an error == actually an error when you try to execute an empty SQL query

    Цялото нещо ми прилича на някакъв много ранен alpha тест на игра, в която всички животни ти пускат пилешки крака, защото не сме имали достатъчно време да го доизпипаме. Да, в крайна сметка си получаваш храната, но е много много странно, малко смешно и леко объркващо.

Трябва да сте влезли в системата, за да може да отговаряте на теми.