1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
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}
|