Download presentation
Presentation is loading. Please wait.
1
Defensive Programming for Better Future
Primož Gabrijelčič
2
About me Primož Gabrijelčič http://primoz.gabrijelcic.org
programmer, MVP, writer, blogger, consultant, speaker Blog Twitter @thedelphigeek Skype gabr42 LinkedIn gabr42 GitHub gabr42 SO gabr Google+ Primož Gabrijelčič
5
And now for something completely different …
6
Defensive Programming
IGNORE it, FIGHT it, MOCK it … just THINK about it! My personal view
7
“Defensive Programming”
= A collection of programming techniques + A collection of style recommendations
8
Defense in Depth
9
1. Data Checking 2. Future Proofing 3. Readable Code
first line of defense 2. Future Proofing never-sleeping guards 2. One never knows how specifications will change – and how some looser (probably you) will change one part of the program, but not another. Been there, done that, didn’t got a tee shirt 3. Your future help will be very grateful I know, I want a time machine just so that I can go 10 years back and give myself a lesson 3. Readable Code help your future self
10
Data Checking SANITIZE THE DATA!
SQL parameters – not even going there. Buffer size checking – more examples later.
11
Function result checking
Data Checking SQL parameters Buffer size checking Function result checking SQL parameters – not even going there. Buffer size checking – more examples later. Move cast() “Must be OK, I found it on StackOverflow”
12
Future Proofing SET UP GUARDS
13
Design by Contract expect precondition invariant maintain guarantee
postcondition Class invarians: not going there – no nice way to support them in Delphi
14
Precondition Postcondition Next: Use descriptive errors!
Note: Bad use of a constant!
15
Use Descriptive Errors!
16
Check data even when IT CANNOT BE WRONG
17
“Million-to-one chances ... crop up nine times out of ten.”
- Terry Pratchett
18
“Million-to-one chances ... crop up nine times out of ten.”
- Terry Pratchett
19
Check data even when IT CANNOT BE WRONG Especially then!
Checked: wrote that in 2009 64-bit support added in XE2, year 2012 1-in
20
Expect the Unexpected! unexpected values can appear … and they will!
enumerations case be wary when dealing with constants else if chain
21
Unsafe! Better Can the compiler solve this? No, and that’s why …
Can an ‘audit’ solve this? Yes, but then you must remember to run it …
22
Assert vs. raise vs. Log Will unhandled unexpected value hurt customer? Will the potential problem be caught in the develop/test cycle? Of course, if you can nicely exit when such problem is found, then do it, by all means.
23
“It is better to crash than to corrupt the data.”
- me
24
“It is better to crash than to corrupt the data.”
- me
25
Unit Tests Programmers do it with TestInsight
In this context, Unit Tests are a future-proofing technique.
26
Write readable code HELP YOUR FUTURE SELF
27
Readable code = Maintainable code
28
Readable code = Good design Good semantics Good formatting
= global strategy = implementation details = see & understand
29
“A good design is like a good house – dry and solid.”
- me “A good design is like a good house – dry and solid.” “A good design is like a good house – dry and solid.” Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion principle Don’t Repeat Yourself Not going there, read more about that stuff anywhere. I’m talking about my personal views today …
30
So … what is good code?
31
Simpler task: What is BAD code?
It is much simpler to show bad code then to explain what makes a code good … … because it is much easier to make fun of a fellow programmer than to fix your own code.
32
“So I took little bad with a good, It ain’t all black and white …”
- Iggy Pop
33
“It ain’t that bad!” (at first glance)
Don’t stay long on this code example, move to next slide.
34
That'
35
Kevlin Henney He’s DA MAN! Look him up on YouTube!
36
https://github.com/gabr42/GpDelphiCode
On github! Spend some time looking at that.
41
“Don’t be a smartass!”
42
“And who will support that?”
When optimization goes too far … I can definitely respect the fight for every CPU cycle, but … “Did you measure it?”
43
“Did you measure it?” - me
44
“Did you measure it?” - me
45
“But look, it is soooo beautiful!”
At least I put a comment in so in five years when I have to fix it … I’ll just remove everything and write the code from scratch. This code is much too dense to be maintainable. Still, sometimes you have to do something for your soul, not just for the man.
46
“My <insert>, does this ever end?”
deity 1769 lines!
47
What to do? Turn it into a class local methods ⇒ class methods
shared variables ⇒ class fields
48
Style Guide Why not just write good comments?
I‘ll let two great men speak …
49
“We can't expect bad programmer to write good comments
“We can't expect bad programmer to write good comments. We may be able to force them to use a coding style, though.” - Kevlin Henney (paraphrased) Kevlin Henney
50
What I consider beautiful these days
I’m not afraid (as I was for a long time) to let a method “breathe”. Vertical empty space inside a method is allowed You’ll still not find me writing “begin” below the “else”, that’s a pure first world waste of resources (vertical space). I do that for “implicit gotos” Exit, break, continue I do it also to break procedure into “verse” , like a poem Although that is always a sign that procedure should be split into two or more
51
Coding Style Suggestions
52
Self-documenting identifier names
i, j, k: integer; i, j, k: integer; AbstractSingletonProxyFactoryBean AbstractSingletonProxyFactoryBean Name should not tell you what the entity is, but what it does. TSimpleDSLCodegen.CompileBlock SyncEdit + refactor
53
Long procedures are BAD
Previous example should be enough … > 1 screen ⇒ bad And please don't start using 7pt point font on a 4K screen just to satisfy this rule. < 1 screen ⇒ good
54
Use variables to hold intermediate values
55
Use variables to hold intermediate values
iTeletext - Example of a good variable naming (in my book).
56
Use variables to hold intermediate values
57
Use variables to hold intermediate values
58
Use variables to hold intermediate values
59
Use variables to hold intermediate values
iTeletext is only used in first two lines – use an enumerator
60
Use variables to hold intermediate values
61
Use variables to hold intermediate values
62
Use variables to hold intermediate values
MMX: Add explaining var
63
MMX Code Explorer is now a free tool!
Great thanks to Gerrit Beuze & Uwe Raabe!
64
Simple cases first
65
Simple cases first
66
Simple cases first
67
Match allocation/deallocation
GetMem / FreeMem Create / Destroy If possible, keep them in the same method getmem … freemem create … destroy acquire … release Acquire / Release
68
Match allocation/deallocation
Visually Match allocation/deallocation try … finally try..finally is cheap if there is no exception (same goes for try..except)
69
Match allocation/deallocation
Visually Match allocation/deallocation Try .. Finally has added bonus of always releasing the FTableLock. That lock may (on exception) prevent the program from shutting down nicely.
70
With? Just say NO!
71
With? Just say NO! Is this a Component.Caption or Form.Caption?
What if component ATM doesn't contain a Caption property? We actually wanted to set .Text, but as our form contins Caption, the compiler doesn't complain.
72
Treat numbers with suspicion
73
Treat numbers with suspicion
Marked in the next slide …
74
Treat numbers with suspicion
75
Treat numbers with suspicion
76
Use FixInsight http://sourceoddity.com/fixinsight/
That was style, now we’re moving a bit up, to the architecture
77
Coding Architecture Suggestions
78
FreeAndNil or Free? How about None?
Free leaves behind a pointer to invalid memory or – worse – to some completely different data, allocated later. Use FreeAndNil.
79
Don’t be too smart(ass)
Write the simplest possible code – you’ll be grateful in five years.
80
“Code CAN be a work of art – just do it at home, not at work.”
- Kevlin Henney (paraphrased)
81
“Code CAN be a work of art – just do it at home, not at work.”
- Kevlin Henney (paraphrased)
82
Code to the interface Long topic. Not going there. I have something else to say …
83
Exceptions Exceptions
Danger, Will Robinson! MMX EAbort story, if time.
84
Can lead to a terrible design
How can I know that? Can lead to a terrible design TFileStream.Create nothing EFCreateError EFOpenError Read the documentation? Who does that! Worst Delphi API! How do I know a method may read an exception? I MUST read the documentation – or the source – or »live« this in practice And what if method is changed later? Maybe by adding another exception class being raised? Who will fix all the code? Who will even notice this change? Delphi <> java where you have to announce exceptions (which then creates terribly long-winded code) so we don't know which exceptions a method may raise just by looking at method definition.
85
“Exceptions should NEVER cross API boundary.”
- me Inside one unit, for example (even better – inside one class) I will »allow« using them. Sometimes they are great to “jump out” several levels. As far as external code is concerned, they must be replaced with Result + error property/retval.
86
“Exceptions should NEVER cross API boundary.”
- me Inside one unit, for example (even better – inside one class) I will »allow« using them. Sometimes they are great to “jump out” several levels. As far as external code is concerned, they must be replaced with Result + error property/retval.
87
AcquireExceptionObject ReleaseExceptionObject
88
“Exceptions should NEVER cross THREAD boundary.”
- me Inside one unit, for example (even better – inside one class) I will »allow« using them. Sometimes they are great to “jump out” several levels. As far as external code is concerned, they must be replaced with Result + error property/retval.
89
“Exceptions should NEVER cross THREAD boundary.”
- me Inside one unit, for example (even better – inside one class) I will »allow« using them. Sometimes they are great to “jump out” several levels. As far as external code is concerned, they must be replaced with Result + error property/retval.
90
Don’t “eat” exceptions!
On Error Resume Next try except end; Ignored exception =(maybe)=> wrong functioning of the program It is better to crash then to corrupt the data.
91
Catch them explicitly! Don’t catch ‘Exception’
92
Catch them explicitly!
93
Catch them explicitly!
94
Catch them explicitly! We even
Catch and log all exceptions even if they are later handled in code! Except exceptions which are handled explicitly. Example: with AutoLog.Expect(ERestRequestException) do try try actionRes := method.Invoke(Self, arguments); except on E: ERestRequestException do overrideResult := TRestResponse.Create(E.RestResponse); end;
95
Our practice Catch and log ALL exceptions Even HANDLED
Unless they are announced in a special way Totally not saying you have to do that! Why? Because of various legacy code that is (was) eating exceptions.
96
Our practice Totally not saying you have to do that!
Why? Because of various legacy code that is (was) eating exceptions. WITH in this case is just a formatting tool, except that it is not …
97
Use exception logger EurekaLog madExcept JclDebug
98
Wrapping up WHAT TO REMEMBER?
When I looked over my code for the last 20 years, I found out that I have something entirely different to say …
99
Don’t write the same code over and over.
100
Don’t write the same code over and over.
Try something new. Experiment. Learn. Make mistakes. "You learn nothing if you get it right in the first try"
101
Don’t write the same code over and over.
Try something new. Experiment. Learn. Make mistakes. Evolve.
102
A human being should be able to change a diaper, plan an invasion, butcher a hog, conn a ship, design a building, write a sonnet, balance accounts, build a wall, set a bone, comfort the dying, take orders, give orders, cooperate, act alone, solve equations, analyze a new problem, pitch manure, program a computer, cook a tasty meal, fight efficiently, die gallantly. Specialization is for insects. -Robert A. Heinlein
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.