"Как не утонуть в ошибках в Go" - Илья Шихалеев, iSpring

Поділитися
Вставка
  • Опубліковано 10 січ 2019
  • Небольшой доклад об обработке ошибок в языке программирования Go и о том, как писать бизнес-логику на Go, не утонув в if err != nil.
    Презентация: speakerdeck.com/quasilyte/kak...
  • Наука та технологія

КОМЕНТАРІ • 19

  • @impnumb5713
    @impnumb5713 5 років тому +3

    А в итоге плодить море функций. Спасибо за способ.

    • @flamehowk
      @flamehowk 2 роки тому +2

      Я пложу не море функций, а один раз написал наборы стандартных функций для обработки ошибок со своими понятными названиями и просто использую их как библиотеку во всех своих приложениях. Получается - прекрасно.

  • @user-br3hw1us7k
    @user-br3hw1us7k Рік тому +3

    Если честно люди которые там по ходу повествования встревали со своими "ну очень важными уточнениями" вели себя крайне неуважительно для вопросов есть время в конце доклада а не по середине.

  • @flamehowk
    @flamehowk 2 роки тому +1

    Я просто написал библиотеку функций, внутри которых встроены все необходимые проверки ошибок и их обработка, и в своих программах вызываю уже мои функции. В результате код получается коротким и чистым - без всяких там +100500 if err... Очень удобная штука.
    Теоретически можно даже такую стандартную библиотеку написать для всех функций го, требующих обработки ошибок и выложить как заплатку на гитхаб, да токо лень этим заниматься - никто ведь даже спасибо не скажет... так что пока только для себя и только то, что нужно в работе.

    • @iSpringTech
      @iSpringTech  2 роки тому

      Спасибо за ваш комментарий! Было бы интересно посмотреть на ваше решение, даже не обобщённое :) Если выложите на гитхаб - скиньте ссылку, пожалуйста :)

    • @flamehowk
      @flamehowk 2 роки тому +1

      @@iSpringTech Да какое это решение... просто здравый смысл. Код же невозможно нормально читать и воспринимать, когда на каждом шагу эти сосиски из:
      if err != nil {
      ...to do something
      fmt.Println("
      Error: ", s, err)
      return
      }
      Поэтому делаю просто:
      Создаю в корневом src папочку libs - это пакет основных библиотек. В этом пакете создают несколько файлов, которые содержат целевые функции. Например, все функции, которые связаны с обработкой файлов лежат в файле file.go, функции для конвертирования типов данных в файле conv.go и так далее. Те функции, которые относятся ко всему сразу или не относятся ни к чему, ложу в общий файл называемый base.go.
      Дальше, к каждому из таких файлов создаю парный файл file_err.go, conv_err.go и так далее.
      В функциональный файл ложу функции, которые выполняют конкретную задачу. Возьмем к примеру "создать файл". Вот эта функция из файла file.go.:
      // Процедура для создания файла
      func FIL_creatFile(s_path string, s_name_ext string) {
      var s_path_name_ext string
      if s_name_ext == "" {
      fmt.Println("file name not specified")
      return
      } else {
      s_path_name_ext = s_path + s_name_ext
      ERR_creatFile(s_path_name_ext)
      }
      }
      Как видите, основная задача в этой функции передается на функцию ERR_creatFile, которая находится в file_err.go, вот она:
      func ERR_creatFile(s_path_name_ext string) {
      file, err := os.Create(s_path_name_ext)
      ERR_printError("Unable to create file:", err)
      file.Close()
      }
      Эта фукнция уже является обработчиком ошибки и в нее можно вставить то, что Вам нужно для конкретной задачи. В данном случае я никак не обрабатываю эту ошибку, а просто вывожу соощение о ней, так как в данный момент у меня рабочие процессы и никакой другой обработки мне не нужно.
      Функции типа ERR_printError, которые выполняют реактивные задачи обработки ошибок, лежат в общем файле errors.go.
      Вот например эта:
      // Процедура демонстрации ошибки
      func ERR_printError(s string, err error) {
      if err != nil {
      fmt.Println("
      Error: ", s, err)
      return
      }
      }
      Получается очень удобный библиотечный пакет, в котором хорошо понятно где что находится. Префиксы в коде позволяют быстро находить нужные функции и добавлять в них функционал если что нужно. Чтобы эти глобальные функции отличались от локальных функций каждого проекта, я в них префиксы пишу только заглавными буквами, а в локальных пакетах заглавной делаю только первую букву.
      Например. В базовой библиотеке функция создания файла начинается с FIL_, она стандартна и подходит для любых проектов. Ее задача - скрыть в себе обработчик ошибок. Если же в проекте мне нужна какая-то особая функция работы с файлами, например, запись в файл хэша файла, то я создаю в проете локальный пакет с библиотеками, где есть такой же файл file.go, но в нем функции начинаются с Fil_. Так я их различаю.
      Базовую библиотеку всегда подключаю через точку, это позволяет пользоваться этими функциями без дополнительных обозначений.
      В результате вместо сосисок, мой код выглялит как-то так:
      // Открываем файл для чтения
      file_reading := FIL_openReadFile(s_path_name_ext)
      defer file_reading.Close()
      // получаем статистику файла
      var i64_size_file int64
      stat := FIL_getStatFile(file_reading)
      i64_size_file = stat.Size() // Получаем размер файла
      // Разделяем s_path_name_ext на составляющие
      var s_path string
      var s_name string
      var s_ext string
      s_path, s_name, s_ext = FIL_splitPathNameExt(s_path_name_ext)
      // Сокращаем если нужно полное имя файла
      var s_name_ext string
      s_name_ext = s_name + "." + s_ext
      s_name_ext = FIL_cutNameFile(s_name_ext)
      // Добавляем расширение шифрованного файла
      s_name_ext = s_name_ext + ".cip"
      s_path_name_ext = s_path + s_name_ext
      // Проверяем существует ли файл
      bo := FIL_existsDirFile(s_path_name_ext)
      if bo == false {
      // Создаем файл для записи шифра
      FIL_creatFile(s_path, s_name_ext)
      } else {
      // Очищаем файл
      FIL_zeroingFile(s_path_name_ext, 0)
      }
      // Открываем файл для записи
      file_writing := FIL_openWriteFile(s_path_name_ext, Cs_perm)
      defer file_writing.Close()
      Код рабочий, рефакторинг еще не проводился, так что не удивляйтесь...
      НО, представьте себе, как будет выглядеть и насколько растянется вся эта констуркция - будь в ней сосиски...

    • @flamehowk
      @flamehowk 2 роки тому

      @@iSpringTech Теперь что касается создания некой базовой библиотеки обработки ошибок, которая вполне может спасти кучу нервов многим программистам, если им понравится такой подход.
      Во-первых, эту библиотеку нужно написать универсальной, то есть - она должна стать ОБЕРТКОЙ для всех фукнций стандартной библиотеки Go, которые имеют те или иные обработчики ошибок.
      Второе - эти обработчики должны содержать все возможные стардартные варианты обработки, а не так как у меня - только то, что мне нужно в данный момент.
      Третье - каждая функция должна содержать подключаемый интерфейс, который будет позволять пользователю подключать свои собственные обработчики, которые ему нужны в каких-то специфических задача.
      Ну и четвертое - каждая фукнция этой библиотеки должна иметь флаг, который позволяет включать или отключать те или иные обрабтчики - это нужно для различных режимов работы с кодом. Например, если я только начинаю программу, то мне ничего кроме вывода ошибки на печать не нужно и я из коробки должен иметь возможность установить при подаче данных в функцию на флаге какую-нибудь "1", что будет означать, что функция будет только выводить ошибку и никак ее не обрабатывать, ну или "0", если мне вообще ничего от нее не нужно... А уже в рабочем режиме ее можно запускать на полную катушку, ну или в продакшин.
      Итого, как Вы видите - это отдельный огромный кусок работы, который кто-то должен просто сесть, сделать, протестить и выложить всем на спасибо. И я бы рад это сделать, кабы мне так же за спасибо все давали - одежду, жилье, транспорт, пищу... Но не дают - все требуют деньог.
      Так что покамест добрыми делами сыт не будешь, я вынужден тратить время на то, за что можна хотя бы что-то взять с других людей.
      Такие-то дела...

    • @kavai9
      @kavai9 2 роки тому +2

      @@flamehowk ​ А как в вашем примере гарантируется, что файл создан? Или вызывающий код не контролирует ошибочных операций и они только в stdout логируются?

    • @kavai9
      @kavai9 2 роки тому +1

      @@flamehowk В итоге, если я правильно понял, ваше видение обобщённой библиотеки превращает её в набор гибко настраиваемых функций, с передачей флагов и обработчиков ошибок. В стандартном подходе, где обработка остаётся на уровне вызывающего кода, получается похожий подход, но без вашей обёртки. В таком случае не понимаю необходимости предлагаемого решения. В го ошибки - это значения и вызывающий код обязан их обработать. Да, для бизнес логики можно перенести/спрятать обязанность обработки ошибок в структуры/функции. Обобщённое решение хорошо подходит для обобщённых компонентов, как работа с файлами в вашем примере. Плюс есть ситуация с необходимостью накопления ошибки. Ваше решение возможно хорошо подходит для ваших задач, но как его в итоге обобщить и в чём будет итоговая выгода - я не понял.

  • @McRay8
    @McRay8 3 роки тому +2

    Дайте слайды пожалуйста

    • @iSpringTech
      @iSpringTech  3 роки тому +2

      Без проблем, ловите :) speakerdeck.com/quasilyte/kak-nie-utonut-v-oshibkakh

    • @McRay8
      @McRay8 3 роки тому

      @@iSpringTech оу май ..) спасибо

    • @user-ks8do2up5j
      @user-ks8do2up5j Рік тому +1

      В середине 70-х годов на сельском клубе появляется объявление:
      "Лекция "Виды любви". Лекция со слайдами."
      На лекцию приходит вся деревня.
      На трибуну выходит лектор и начинает:
      Первый вид любви - это любовь мужчины к женщине.
      Народ: Слайды! Слайды!
      Лектор: Слайды будут позже.
      Второй вид любви - это любовь мужчины к мужчине.
      Народ: Слайды! Слайды!
      Лектор: Слайды будут позже.
      Третий вид любви - это любовь женщины к женщине.
      Народ: Слайды! Слайды!
      Лектор: А ещё, товарищи, существует такой вид любви как любовь советского человека к своей Родине. ВОТ ТЕПЕРЬ БУДУТ СЛАЙДЫ!