From 4d940eff936ce867b3180b5a63a4302d73260dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Sat, 3 Oct 2020 16:21:41 +0200 Subject: Add presentation for Linuxdays 2020 --- 2020-linuxdays/makefile | 10 ++ 2020-linuxdays/pres.pdf | Bin 0 -> 78631 bytes 2020-linuxdays/pres.tex | 379 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 389 insertions(+) create mode 100644 2020-linuxdays/makefile create mode 100644 2020-linuxdays/pres.pdf create mode 100644 2020-linuxdays/pres.tex diff --git a/2020-linuxdays/makefile b/2020-linuxdays/makefile new file mode 100644 index 0000000..a90bd93 --- /dev/null +++ b/2020-linuxdays/makefile @@ -0,0 +1,10 @@ +FILE=pres + +$(FILE).pdf: $(FILE).tex $(patsubst %.svg,%.pdf,$(wildcard *.svg)) + lualatex -shell-escape $< + +%.pdf: %.svg + inkscape -D -z --file=$< --export-pdf=$@ --export-latex + +clean: + ls | grep -v -E "($(FILE).tex|makefile|scheme|svg|png|jpg|eps)$$" | xargs rm -rf diff --git a/2020-linuxdays/pres.pdf b/2020-linuxdays/pres.pdf new file mode 100644 index 0000000..33e08d6 Binary files /dev/null and b/2020-linuxdays/pres.pdf differ diff --git a/2020-linuxdays/pres.tex b/2020-linuxdays/pres.tex new file mode 100644 index 0000000..288b5e1 --- /dev/null +++ b/2020-linuxdays/pres.tex @@ -0,0 +1,379 @@ +\documentclass[aspectratio=169]{beamer} +\usetheme{metropolis} +\usepackage{lmodern} +\usepackage[czech]{babel} +\usepackage[utf8]{inputenc} +\usepackage{graphicx} +\usepackage{emoji} +\setemojifont{Quivira} +\usepackage{wrapfig} +\usepackage{color} +\usepackage{mathtools} +\usepackage{hyperref} +\usepackage{epstopdf} +\usepackage{amsmath} +\usepackage{minted} +\hypersetup{ + colorlinks, + citecolor=black, + filecolor=black, + linkcolor=black, + urlcolor=black +} +\usepackage{pdflscape} + +\title{Proradná obsluha chyb \emoji{dagger}} +\author{Kar(t)el Kočí} +\date{3.10.2020} + +\begin{document} + +\frame{\titlepage} + +\begin{frame}[fragile] + \frametitle{Kdo za ty chyby může?} + \only<2>{\huge \textbf{Uživatel!}} + \only<3>{\footnotesize Programátor..} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co si pod chybami programátor představí?} + \begin{itemize} + \item \textbf{Nečekaný stav dat} + \item Nečekaný běh aplikace (špatný algoritmus) + \item Nečekané ukončení aplikace (segfault, ..) + \item Nečekaný obsah souboru či čtení ze soketu + \item Nečekaný obsah sdílené paměti + \item \textbf{Nečekaná návratová hodnota} + \item Nečekaný stav souborů (chybějící složka atd.) + \item Nečekaná odezva od periferie či soketu + \item A další \ldots + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co si pod chybami představí uživatel?} + \Large Nefunguje to! +\end{frame} + +\begin{frame}[fragile] + \frametitle{Teď vážně, požadavky} + \begin{columns} + \column{.45\textwidth} + Uživatel: + \begin{itemize} + \item Nechce, aby program spadl + \item Když už spadne, tak chce vědět jak to opravit + \item Když už neřekneme jak opravit, tak chce vědět proč + \item Nechce více informací než dokáže vstřebat + \end{itemize} + \column{.45\textwidth} + Programátor: + \begin{itemize} + \item To někdy není možné a je to jediné východisko + \item Programátor nemůže pokrýt každou situaci + \item To nemusí být ani v moci programu + \item Potřebuje trace, například aby dohledal jak se to stalo + \end{itemize} + \end{columns} + Programátor není Bůh, ale měl by být a měl by se snažit uživatelům práci s + jeho stvořením zpříjemnit. +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co s chybou když nastane?} + Záleží na tom o jakou chybu se jedná. + \begin{itemize} + \item Fatální chyby + \begin{itemize} + \item Pády (\textit{segfault, invalid instruction, \ldots}) + \item Nečekané stavy (\textit{tady ještě před chvílí byl soubor \ldots}) + \item Bezvýchodné stavy (\textit{tady měl být soubor se vstupem \dots}) + \end{itemize} + \item Řešitelné chyby + \begin{itemize} + \item Krajní (\textit{soubor vytvořil někdo jiný \ldots}) + \item Očekávané (\textit{soubor se nezdařilo vytvořit, protože chybí složka, vytvoříme složku \dots}) + \item Ignorované (\textit{unlink souboru selhal, protože neexistuje \dots}) + \end{itemize} + \end{itemize} + + A taky záleží, jestli jsme knihovna nebo program! +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co když nastane pád?} + + \begin{columns} + \column{.50\textwidth} + \centerline{\textbf{Program}} + Pokud se nesnaží, tak se ani o tom nedozví. + \column{.50\textwidth} + \centerline{\textbf{Knihovna}} + Ani se o tom nedozví a většinou by se neměla ani snažit. + \end{columns} + + \vspace{1cm} + + \begin{minted}[frame=lines]{c} +struct foo *foo = NULL; +foo->fee = 0; + \end{minted} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co když nastane nečekaný stav?} + \begin{columns} + \column{.50\textwidth} + \centerline{\textbf{Program}} + Ukončení programu a výpis stavových informací + \begin{minted}[frame=lines]{python} +file = open(path, "w") +file.close() +file = open(path) +# raises: FileNotFoundError + \end{minted} + \begin{minted}[frame=lines]{c} +fclose(file); +file = fopen(path, "r"); +assert(file); + \end{minted} + \column{.50\textwidth} + \centerline{\textbf{Knihovna}} + Necháme vyřešit aplikaci. Nikdy ne \texttt{exit} a vyvarujte se + \texttt{abort}. + \begin{minted}[frame=lines]{c} +fclose(file); +file = fopen(path, "r"); +if (file == NULL) { + liberrno = LIB_ERR_LOST_FILE; + return false; +} + \end{minted} + \end{columns} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Odbočka k C a knihovnám: Jak hlásit error?} + \begin{itemize} + \item Návratová hodnota funkce + \begin{minted}[frame=lines]{c} +enum { + FOO_ERR_FOO, +} foo() { return FOO_ERR_FOO; } + \end{minted} + \item Proměnná s chybou + \begin{minted}[frame=lines]{c} +enum liberror { + LIB_ERR_FOO, +}; +thread_local enum liberror liberrno; + \end{minted} + \item Výjimka (s nějakou knihovnou, která je implementuje) + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co když nastane bezvýchodný stav?} + \begin{columns} + \column{.50\textwidth} + \centerline{\textbf{Program}} + Ukončení programu. + \begin{minted}[frame=lines]{python} +try: + file = open(sys.argv[1]) +except FileNotFoundError: + logger.critical("Input missing: %s", + sys.argv[1]) +except PermissionError: + logger.critical( + "Input unaccessible: %s", + sys.argv[1]) + \end{minted} + \column{.50\textwidth} + \centerline{\textbf{Knihovna}} + Necháme vyřešit aplikaci. + \begin{minted}[frame=lines]{python} +def handle_args(argv): + """ + :raises FileNotFoundError: + First argument wasn't valid path + :raises PermissionError: + First is unaccessible path + """ + file = open(argv[1]) + \end{minted} + \end{columns} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Odbočka k ukončovacím rutinám: Jak ukončit program?} + Je nutné uvolnit každou dosažitelnou paměť? + + Rozdělme si zdroje vůči procesu:\\ + + \begin{columns} + \column{.50\textwidth} + Interní + \begin{itemize} + \item Alokovaná paměť + \item Otevřené file descriptory (soubory, sockety, atd.) + \item Namapovaná paměť + \end{itemize} + \column{.50\textwidth} + Externí + \begin{itemize} + \item Data buffery s výstupem na disk (ne \texttt{fclose} ale \texttt{fflush}) + \item Dočasné soubory dosažitelné na file-systému + \end{itemize} + \end{columns} + + \vspace{0.4cm} + + Dělejme jen to, co musíme. Zbytek za nás udělá kernel a jazyk. + + Interní za nás udělá někdo jiný, my se musíme starat pouze o externí. +\end{frame} + +\begin{frame}[fragile] + \frametitle{Ještě větší odbočka k C \texttt{exit}} + \url{https://www.gnu.org/software/libc/manual/html_node/Termination-Internals.html} + + \begin{minted}[frame=lines]{c} +typedef void (*onexit_t)(void *arg); +struct onexit { onexit_t func; void *arg; struct onexit *next; }; +struct onexit *onexit = NULL; +void onexit_handler() { + for (; onexit; onexit = onexit->next) + onexit->func(onexit->arg); +} + +atexit(onexit_handler); + \end{minted} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co když nastane řešitelná chyba?} + \begin{columns} + \column{.50\textwidth} + \centerline{\textbf{Program}} + Tak ji prostě vyřešíme, nebo ještě lépe ji předejdeme. + \begin{minted}[frame=lines]{python} +pathlib.Path("foo").mkdir( + parents=True, exist_ok=True) +file = open("foo/fee", "w") + \end{minted} + \column{.50\textwidth} + \centerline{\textbf{Knihovna}} + Tak ji vyřešíme. Lepší je ale nechat vybrat aplikaci, jestli se má + automaticky řešit nebo vrátit raději error. + \begin{minted}[frame=lines]{python} +def open(self, path, mkdir=True): + if mkdir: + pathlib.Path(path).parent.mkdir( + parent=True, exist_ok=True) + file = open(path, "w") + \end{minted} + \end{columns} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Závěrem: jde to i přehnat} + \begin{minted}[frame=lines]{c} +int fd = open(path, O_RDONLY); +char buf[BUFSIZ]; +while (true) { + if (read(fd, buf, BUFSIZ) == -1) { + switch (errno) { + case EWOULDBLOCK: + case EAGAIN: + continue; + \end{minted} +\end{frame} + +\begin{frame}[fragile] + \Large Error: unable to exit, user is not informed! +\end{frame} + +\begin{frame}[fragile] + \frametitle{Nahlášení chyby} + Před tím než chybu ošetříme, musíme ji nahlásit! + + V pořadí od vývojářsky po uživatelsky přivětivé: + \begin{itemize} + \item Memory dump + \item Stack trace + \item Popis chyby se zdrojem chyby (zdrojový soubor, funkce, řádka, \dots) + \item Popis chyby + \item Popis chyby a návrh řešení + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co kdy zvolit ale?} + \begin{description} + \item[Memory dump] jen pro pády a většinou zajistí systém + \item[Stack trace] jen pro nečekané stavy a na vyžádání + \item[Zdroj chyby] jen jako méně invazivní alternativa ke stacktrace + \item[Popis] vždy + \item[Návrh řešení] vždy pokud je možné + \end{description} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Co v popisu říci uživateli, aby jim i nám to k něčemu bylo?} + \begin{enumerate} + \item Popis by měl být pokud možno unikátní pro každou chybu. + \item Poskytnout výpis relevantních dat (cesta k souboru a pod.). + \item Nevypisujte nerelevantní data! + \item Popis by měl být výstižný a přesný. + \end{enumerate} + + Ujistěte se, že data která vypisujete jsou validní! + \begin{verbatim} +Called uri_path on URI of scheme: https + \end{verbatim} + \begin{minted}[frame=lines]{diff} +-error("URI download failed (" .. u:path() .. "): " .. u:download_error()) ++error("Getting URI (" .. u:uri() .. ") failed: " .. u:download_error()) + \end{minted} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Kdy hlásit chybu?} + \textbf{Vždy!} + + Hlašte chyby ve více úrovních: + \begin{description} + \item[CRITICAL] pro nečekané a bezvýchodné stavy (následuje ukončení + programu) + \item[ERROR] pro krajní řešitelné chyby + \item[WARNING] pro krajní řešitelné chyby + \item[NOTICE] žádné chyby + \item[INFO] pro očekávané chyby + \item[DEBUG] pro ignorované chyby + \end{description} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Checklist závěrem} + \begin{enumerate} + \item Zamyslete se, co za data od volání získáte, a jak moc datům ke + kterým přistupujete můžete věřit + \item Chyby které nám mohou nastat rozřadíme + \item Při detekci chyby oznámíme uživateli + \item Vyřešíme chybu dle toho o jaký typ se jedná + \end{enumerate} +\end{frame} + + +\begin{frame} + \Large \textbf{Fatal error: no more slides \emoji{cry}} + + \Large Děkuji za pozornost. + + \url{git.cynerd.cz} +\end{frame} + +\end{document} -- cgit v1.2.3