-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhow_to_be_a_programmer.html
3269 lines (3079 loc) · 193 KB
/
how_to_be_a_programmer.html
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
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"><title>How to be a Programmer: A Short, Comprehensive, and Personal Summary</title><meta name="generator" content="DocBook XSL Stylesheets V1.60.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="id2792795"></a>How to be a Programmer: A Short, Comprehensive, and Personal Summary</h1></div><div><div class="author"><h3 class="author"><span class="firstname">Robert</span> <span class="othername">L</span> <span class="surname">Read</span></h3></div></div><div><p class="copyright">Copyright � 2002, 2003 Robert L. Read
</p></div><div><div class="legalnotice">
Copyright <p class="copyright">Copyright � 2002, 2003 </p> by Robert L. Read.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version
published by the Free Software Foundation;
with one Invariant Section being ‘<span class="quote">History (As of February, 2003)</span>’,
no Front-Cover Texts, and one Back-Cover Text:
‘<span class="quote">The original version of this document was written by Robert L. Read
without renumeration and dedicated to the programmers of Hire.com.</span>’
A copy of the license is included in the section entitled ‘<span class="quote">GNU
Free Documentation License</span>’.
</div></div><div><p class="pubdate">2002</p></div></div><div></div><hr></div><div class="dedication" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="id2792897"></a>Dedication</h2></div></div><div></div></div><p>
To the programmers of Hire.com.
</p></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt>1. <a href="#id2792906">Introduction</a></dt><dd><dl><dt><a href="#id2792914"></a></dt></dl></dd><dt>2. <a href="#id2790271">Beginner</a></dt><dd><dl><dt><a href="#id2790277">Personal Skills</a></dt><dd><dl><dt><a href="#id2790282">Learn to Debug</a></dt><dt><a href="#id2789958">How to Debug by Splitting the Problem Space</a></dt><dt><a href="#id2790059">How to Remove an Error</a></dt><dt><a href="#id2790119">How to Debug Using a Log</a></dt><dt><a href="#id2789469">How to Understand Performance Problems</a></dt><dt><a href="#id2789540">How to Fix Performance Problems</a></dt><dt><a href="#id2794319">How to Optimize Loops</a></dt><dt><a href="#id2794412">How to Deal with I/O Expense</a></dt><dt><a href="#id2794476">How to Manage Memory</a></dt><dt><a href="#id2794568">How to Deal with Intermittent Bugs</a></dt><dt><a href="#id2838857">How to Learn Design Skills</a></dt><dt><a href="#id2838894">How to Conduct Experiments</a></dt></dl></dd><dt><a href="#id2839021">Team Skills</a></dt><dd><dl><dt><a href="#id2839027">Why Estimation is Important</a></dt><dt><a href="#id2839075">How to Estimate Programming Time</a></dt><dt><a href="#id2839206">How to Find Out Information</a></dt><dt><a href="#id2791028">How to Utilize People as Information Sources</a></dt><dt><a href="#id2791115">How to Document Wisely</a></dt><dt><a href="#id2791248">How to Work with Poor Code</a></dt><dt><a href="#id2791306">How to Use Source Code Control</a></dt><dt><a href="#id2791350">How to Unit Test</a></dt><dt><a href="#id2791383">Take Breaks when Stumped</a></dt><dt><a href="#id2791398">How to Recognize When to Go Home</a></dt><dt><a href="#id2793056">How to Deal with Difficult People</a></dt></dl></dd></dl></dd><dt>3. <a href="#id2791504">Intermediate</a></dt><dd><dl><dt><a href="#id2791510">Personal Skills</a></dt><dd><dl><dt><a href="#id2791515">How to Stay Motivated</a></dt><dt><a href="#id2791595">How to be Widely Trusted</a></dt><dt><a href="#id2789608">How to Tradeoff Time vs. Space</a></dt><dt><a href="#id2853103">How to Stress Test</a></dt><dt><a href="#id2853204">How to Balance Brevity and Abstraction</a></dt><dt><a href="#id2853289">How to Learn New Skills</a></dt><dt><a href="#id2853347">Learn to Type</a></dt><dt><a href="#id2853376">How to Do Integration Testing</a></dt><dt><a href="#id2853401">Communication Languages</a></dt><dt><a href="#id2853477">Heavy Tools</a></dt><dt><a href="#id2853555">How to analyze data</a></dt></dl></dd><dt><a href="#id2853758">Team Skills</a></dt><dd><dl><dt><a href="#id2853764">How to Manage Development Time</a></dt><dt><a href="#id2853827">How to Manage Third-Party Software Risks</a></dt><dt><a href="#id2853901">How to Manage Consultants</a></dt><dt><a href="#id2853943">How to Communicate the Right Amount</a></dt><dt><a href="#id2853974">How to Disagree Honestly and Get Away with It</a></dt></dl></dd><dt><a href="#id2854037">Judgement</a></dt><dd><dl><dt><a href="#id2854043">How to Tradeoff Quality Against Development Time</a></dt><dt><a href="#id2854111">How to Manage Software System Dependence</a></dt><dt><a href="#id2854176">How to Decide if Software is Too Immature</a></dt><dt><a href="#id2854300">How to Make a Buy vs. Build Decision</a></dt><dt><a href="#id2854441">How to Grow Professionally</a></dt><dt><a href="#id2854482">How to Evaluate Interviewees</a></dt><dt><a href="#id2854560">How to Know When to Apply Fancy Computer Science</a></dt><dt><a href="#id2854650">How to Talk to Non-Engineers</a></dt></dl></dd></dl></dd><dt>4. <a href="#id2854792">Advanced</a></dt><dd><dl><dt><a href="#id2854798">Technological Judgment</a></dt><dd><dl><dt><a href="#id2854804">How to Tell the Hard From the Impossible</a></dt><dt><a href="#id2854864">How to Utilize Embedded Languages</a></dt><dt><a href="#id2854925">Choosing Languages</a></dt></dl></dd><dt><a href="#id2855025">Compromising Wisely</a></dt><dd><dl><dt><a href="#id2855030">How to Fight Schedule Pressure</a></dt><dt><a href="#id2855109">How to Understand the User</a></dt><dt><a href="#id2855216">How to Get a Promotion</a></dt></dl></dd><dt><a href="#id2855274">Serving Your Team</a></dt><dd><dl><dt><a href="#id2855280">How to Develop Talent</a></dt><dt><a href="#id2855381">How to Choose What to Work On</a></dt><dt><a href="#id2855401">How to Get the Most From Your Teammates</a></dt><dt><a href="#id2855474">How to Divide Problems Up</a></dt><dt><a href="#id2855514">How to Handle Boring Tasks</a></dt><dt><a href="#id2855545">How to Gather Support for a Project</a></dt><dt><a href="#id2855566">How to Grow a System</a></dt><dt><a href="#id2855689">How to Communicate Well</a></dt><dt><a href="#id2855760">How to Tell People Things They Don't Want to Hear</a></dt><dt><a href="#id2855804">How to Deal with Managerial Myths</a></dt><dt><a href="#id2855892">How to Deal with Organizational Chaos</a></dt></dl></dd></dl></dd><dt><a href="#id2855968">Glossary</a></dt><dt>A. <a href="#id2856630"></a></dt><dt>B. <a href="#id2857195">History (As Of February, 2003)</a></dt><dt>C. <a href="#gfdl">GNU Free Documentation License</a></dt><dd><dl><dt><a href="#gfdl-0">PREAMBLE</a></dt><dt><a href="#gfdl-1">APPLICABILITY AND DEFINITIONS</a></dt><dt><a href="#gfdl-2">VERBATIM COPYING</a></dt><dt><a href="#gfdl-3">COPYING IN QUANTITY</a></dt><dt><a href="#gfdl-4">MODIFICATIONS</a></dt><dt><a href="#gfdl-5">COMBINING DOCUMENTS</a></dt><dt><a href="#gfdl-6">COLLECTIONS OF DOCUMENTS</a></dt><dt><a href="#gfdl-7">AGGREGATION WITH INDEPENDENT WORKS</a></dt><dt><a href="#gfdl-8">TRANSLATION</a></dt><dt><a href="#gfdl-9">TERMINATION</a></dt><dt><a href="#gfdl-10">FUTURE REVISIONS OF THIS LICENSE</a></dt><dt><a href="#gfdl-addendum">ADDENDUM: How to use this License for
your documents</a></dt></dl></dd></dl></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="id2792906"></a>Chapter�1.�Introduction</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><a href="#id2792914"></a></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div></div><div></div></div><p>
To be a good programmer is difficult and noble.
The hardest part of making real a collective vision
of a software project is dealing with
one's coworkers and customers.
Writing computer programs is important and takes great intelligence
and skill. But it is really child's play compared to
everything else that a good programmer must do to make a
software system that succeeds for both the customer and
myriad colleagues for whom she is partially responsible.
In this essay I attempt to summarize as concisely as possible
those things that I wish
someone had explained to me when I was twenty-one.
</p><p>
This is very subjective and, therefore, this essay is doomed
to be personal and somewhat opinionated. I confine myself to problems that a
programmer is very likely to have to face in her work.
Many of these problems and their solutions are so general to
the human condition that I will probably seem preachy.
I hope in spite of this that this essay will be useful.
</p><p>
Computer programming is taught in courses.
The excellent books:
<i class="citetitle">The
Pragmatic Programmer</i>
[<span class="citation">Prag99</span>],
<i class="citetitle">Code Complete</i>
[<span class="citation">CodeC93</span>],
<i class="citetitle">Rapid Development</i>
[<span class="citation">RDev96</span>], and
<i class="citetitle">Extreme Programming Explained</i>
[<span class="citation">XP99</span>] all teach
computer programming
and the larger issues of being a good programmer.
The essays of Paul Graham[<span class="citation">PGSite</span>] and Eric Raymond[<span class="citation">Hacker</span>]
should certainly be read before or along with this article.
This essay differs from those excellent works by
emphasizing social problems and comprehensively summarizing
the entire set of necessary skills as I see them.
</p><p>
In this essay the term <i class="firstterm">boss</i> to refer to whomever gives
you projects to do. I use the words <i class="firstterm">business</i>,
<i class="firstterm">company</i>,
and <i class="firstterm">tribe</i>, synonymously except that business connotes
moneymaking, company connotes the modern workplace and
tribe is generally the people you share loyalty with.
</p><p>
Welcome to the tribe.
</p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="id2790271"></a>Chapter�2.�Beginner</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><a href="#id2790277">Personal Skills</a></dt><dd><dl><dt><a href="#id2790282">Learn to Debug</a></dt><dt><a href="#id2789958">How to Debug by Splitting the Problem Space</a></dt><dt><a href="#id2790059">How to Remove an Error</a></dt><dt><a href="#id2790119">How to Debug Using a Log</a></dt><dt><a href="#id2789469">How to Understand Performance Problems</a></dt><dt><a href="#id2789540">How to Fix Performance Problems</a></dt><dt><a href="#id2794319">How to Optimize Loops</a></dt><dt><a href="#id2794412">How to Deal with I/O Expense</a></dt><dt><a href="#id2794476">How to Manage Memory</a></dt><dt><a href="#id2794568">How to Deal with Intermittent Bugs</a></dt><dt><a href="#id2838857">How to Learn Design Skills</a></dt><dt><a href="#id2838894">How to Conduct Experiments</a></dt></dl></dd><dt><a href="#id2839021">Team Skills</a></dt><dd><dl><dt><a href="#id2839027">Why Estimation is Important</a></dt><dt><a href="#id2839075">How to Estimate Programming Time</a></dt><dt><a href="#id2839206">How to Find Out Information</a></dt><dt><a href="#id2791028">How to Utilize People as Information Sources</a></dt><dt><a href="#id2791115">How to Document Wisely</a></dt><dt><a href="#id2791248">How to Work with Poor Code</a></dt><dt><a href="#id2791306">How to Use Source Code Control</a></dt><dt><a href="#id2791350">How to Unit Test</a></dt><dt><a href="#id2791383">Take Breaks when Stumped</a></dt><dt><a href="#id2791398">How to Recognize When to Go Home</a></dt><dt><a href="#id2793056">How to Deal with Difficult People</a></dt></dl></dd></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2790277"></a>Personal Skills</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2790282"></a>Learn to Debug</h3></div></div><div></div></div><p>
Debugging is the cornerstone of being a programmer.
The first meaning of the verb <span class="emphasis"><em>to debug</em></span> is to remove errors, but
the meaning that really matters is <span class="emphasis"><em> to see into the execution of a program by examining it</em></span>.
A programmer that cannot debug effectively is blind.
</p><p>
Idealists that think design, or analysis, or
complexity theory, or whatnot, are more fundamental are not
working programmers. The working programmer does not live in an ideal world.
Even if you are perfect, your are surrounded by and must
interact with code written by major software companies, organizations
like GNU, and your colleagues. Most of this code is imperfect and
imperfectly documented. Without the ability to gain visibility into
the execution of this code the slightest bump will throw you permanently.
Often this visibility can only be gained by experimentation,
that is, debugging.
</p><p>
Debugging is about the running of programs, not programs themselves.
If you buy something from a major software company, you usually don't
get to see the program. But there will still arise places where the
code does not conform to the documentation (crashing your entire machine
is a common and spectacular example), or where the documentation is mute.
More commonly, you create an error, examine the code you
wrote and have no clue how the error can be occurring. Inevitably, this
means some assumption you are making is not quite correct, or some
condition arises that you did not anticipate. Sometimes the magic trick
of staring into the source code works. When it doesn't, you must debug.
</p><p>
To get visibility into the execution of a program you must be able to
execute the code and observe something about it. Sometimes this is visible,
like what is being displayed on a screen, or the delay between two events.
In many other cases, it involves things that are not meant to be visible,
like the state of some variables inside the code, which lines of code
are actually being executed, or whether certain assertions hold across a
complicated data structure. These hidden things must be revealed.
</p><p>
The common ways of looking into the ‘<span class="quote">innards</span>’ of an executing program can be categorized as:
</p><div class="itemizedlist"><ul type="disc" compact="compact"><li><p>Using a debugging tool, </p></li><li><p>Printlining --- Making a temporary modification to the program,
typically adding lines that print information out, and </p></li><li><p>Logging --- Creating a permanent window into the programs
execution in the form of a log.</p></li></ul></div><p>
Debugging tools are wonderful when they are stable and available, but the
printlining and logging are even more important.
Debugging tools often lag
behind language development, so at any point in time they may
not be available. In addition, because the debugging tool may subtly change the way
the program executes it may not always be practical.
Finally, there are some kinds of debugging, such as checking
an assertion against a large data structure, that require writing code
and changing the execution of the program.
It is good to know how to use debugging tools when they are stable,
but it is critical to be able to employ the other two methods.
</p><p>
Some beginners fear debugging when it requires modifying
code. This is understandable---it is a little like exploratory
surgery. But you have to learn to poke at the code and make it jump;
you have to learn to experiment on it, and understand that nothing that
you temporarily do to it will make it worse. If you feel this fear,
seek out a mentor---we lose a lot of good programmers at the delicate
onset of their learning to this fear.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2789958"></a>How to Debug by Splitting the Problem Space</h3></div></div><div></div></div><p>
Debugging is fun, because it begins with a mystery. You think it should
do something, but instead it does something else.
It is not always quite so simple---any
examples I can give will be contrived compared to what sometimes happens
in practice. Debugging requires creativity and ingenuity. If there is a
single key to debugging is to use the
<i class="firstterm"> divide and conquer</i> technique on the mystery.
</p><p>
Suppose, for example, you created a program that should do
ten things in a sequence. When you run it, it crashes.
Since you didn't program it to crash, you now have a mystery.
When out look at the output, you see that the first seven
things in the sequence were run successfully. The last three are
not visible from the output, so now your mystery is smaller:
‘<span class="quote">It crashed on thing #8, #9, or #10.</span>’
</p><p>
Can you design an experiment to see which thing it crashed on? Sure.
You can use a debugger or we can add printline statements (or the equivalent
in whatever language you are working in) after #8 and #9.
When we run
it again, our mystery will be smaller, such as
‘<span class="quote">It crashed on thing #9.</span>’
I find that bearing in mind exactly what the mystery is at any point
in time helps keep one focused. When several people are working
together under pressure on a problem it is easy to forget what the
most important mystery is.
</p><p>
The key to divide and conquer as a debugging technique
is the same as it is for algorithm design: as long as you do a
good job splitting the mystery in the middle, you won't have to
split it too many times, and you will be debugging quickly.
But what is the middle of a mystery? There is where
true creativity and experience comes in.
</p><p>
To a true beginner, the
space of all possible errors looks like every line in the source code.
You don't have the vision you will later develop to see the other
dimensions of the program, such as the space of executed lines, the
data structure, the memory management, the interaction with foreign code,
the code that is risky, and the code that is simple.
For the experience programmer, these other
dimensions form an imperfect but very
useful mental model of all the things that can go wrong. Having that
mental model is what helps one find the middle of the mystery effectively.
</p><p>
Once you have evenly subdivided the space of all that can go wrong, you
must try to decide in which space the error lies. In the simple case
where the mystery is: ‘<span class="quote">Which single unknown line makes my program crash?</span>’,
you can ask yourself:
‘<span class="quote">Is the unknown line executed before or after this line that
I judge to be executed in the about the middle of the running program?</span>’
Usually you will not be so lucky as to know that the error
exists in a single line, or even a single block.
Often the mystery will be more like: ‘<span class="quote">Either there is a pointer in that
graph that points to the wrong node, or my algorithm that adds
up the variables in that graph doesn't work.</span>’ In that case you may
have to write a small program to check that the pointers in the graph
are all correct in order to decide
which part of the subdivided mystery can be eliminated.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2790059"></a>How to Remove an Error</h3></div></div><div></div></div><p>
I've intentionally separated the act of examining a program's
execution from the act of fixing an error. But of course, <span class="emphasis"><em> debugging</em></span>
does also mean removing the bug.
Ideally you will have perfect understanding of the code and will
reach an ‘<span class="quote">A-Ha!</span>’ moment where you perfectly see the error and
how to fix it. But since your program will often use
insufficiently documented systems
into which you have no visibility,
this is not always possible. In other cases
the code is so complicated that your understanding cannot be
perfect.
</p><p>
In fixing a bug, you want to make the smallest change that
fixes the bug. You may see other things that need improvement;
but don't fix those at the same time. Attempt to employ
the scientific method of changing one thing and only one thing
at a time. The best process for this is to be able to easily
reproduce the bug, then put your fix in place, and then rerun the
program and observe that the bug no longer exists. Of course,
sometimes more than one line must be changed, but you should
still conceptually apply a single atomic change to fix the
bug.
</p><p>
Sometimes, there are really several bugs that look like one.
It is up to you to define the bugs and fix them one at a time.
Sometimes it is unclear what the program should do
or what the original author intended. In this
case, you must exercise your experience and judgment and assign
your own meaning to the code. Decide what it should do,
and comment it or clarify it in some way and then make the
code conform to your meaning. This is an intermediate or
advanced skill that is sometimes harder than writing the
original function in the first place, but the real world
is often messy. You may have to fix a system you cannot
rewrite.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2790119"></a>How to Debug Using a Log</h3></div></div><div></div></div><p>
<i class="firstterm"> Logging</i> is the practice of writing a system so that it produces a
sequence of informative records, called a <i class="firstterm"> log</i>. <i class="firstterm"> Printlining</i> is just producing a simple, usually temporary, log.
Absolute beginners must understand and use logs because their
knowledge of the programming is limited; system architects must
understand and use logs because of the complexity of the system.
The amount of information that is provided by the log should be configurable,
ideally while the program is running.
In general, logs offer three basic advantages:
</p><div class="itemizedlist"><ul type="disc"><li><p>
Logs can provide useful information about bugs that are hard
to reproduce (such as those that occur in the production environment but
that cannot be reproduced in the test environment).
</p></li><li><p>
Logs can provide statistics and data relevant to
performance, such as the time passing between statements.
</p></li><li><p>
When configurable, logs allow general information to be
captured in order to debug unanticipated specific problems
without having to modify and/or redeploy the code just to deal
with those specific problems.
</p></li></ul></div><p>
The amount to output into the log is always a compromise
between information and brevity.
Too much information makes the
log expensive and produces <i class="firstterm"> scroll blindness</i>, making it hard
to find the information you need.
Too little information and it may not
contain what you need.
For this reason, making what is output configurable is
very useful.
Typically, each record in the log will identify its position in
the source code, the thread that executed it if applicable,
the precise time of execution, and, commonly, an additional useful piece
of information, such as the value of some variable, the amount of
free memory, the number of data objects, etc.
These log statements are sprinkled
throughout the source code but are particularly at major functionality
points and around risky code.
Each statement can be assigned a level
and will only output a record if the system
is currently configured to output that level.
You should design the log statements to address
problems that you anticipate.
Anticipate the need to measure performance.
</p><p>
If you have a permanent log, printlining can now be done in terms
of the log records, and some of the debugging statements will
probably be permanently added to the logging system.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2789469"></a>How to Understand Performance Problems</h3></div></div><div></div></div><p>
Learning to understand the performance of a running system
is unavoidable for the same reason that learning debugging is.
Even if the
code you understand perfectly precisely the cost
of the code you write, your code will
make calls into other software systems
that you have little control over or visibility into.
However, in practice
performance problems are a little different and a little easier
than debugging in general.
</p><p>
Suppose that you or your customers
consider a system or a subsystem to be too slow.
Before you try to make it faster,
you must build a mental model of why it is slow.
To do this you can use a profiling tool or a
good log to figure out where the time or other
resources are really being spent.
There is a famous dictum that 90% of the time will be
spent in 10% of the code.
I would add to that the importance
of input/output expense (I/O) to performance issues.
Often most of the time is spent in I/O in one way or another.
Finding the expensive I/O and the expensive 10% of
the code is a good first step to building your mental model.
</p><p>
There are many dimensions to the performance of a
computer system, and many resources consumed.
The first resource to measure is <i class="firstterm"> wall--clock time</i>,
the total time that passes for the computation.
Logging wall-clock time is particularly valuable because it can inform
about unpredictable circumstance that arise in situations where other profiling is impractical.
However, this may not always represent the whole picture.
Sometimes something that
takes a little longer but doesn't burn up so many processor seconds will
be much better in computing environment you actually have to deal with.
Similarly, memory, network bandwidth, database or other server accesses
may, in the end, be far more expensive than processor seconds.
</p><p>
Contention for shared resources that are synchronized can
cause deadlock and starvation.
Deadlock is the inability to proceed because of
improper synchronization or resource demands.
Starvation is the failure to schedule a component properly.
If it can be at all anticipated,
it is best to have a way of measuring this contention
from the start of your project.
Even if this contention does not occur,
it is very helpful to be able to assert that with confidence.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2789540"></a>How to Fix Performance Problems</h3></div></div><div></div></div><p>
Most software projects can be made with relatively little effort
10 to 100 times
faster than they are at the they are first released.
Under time-to-market pressure,
it is both wise and effective to choose a solution that
gets the job done simply and quickly, but less efficiently
than some other solution. However, performance is a part
of usability, and often it must eventually be considered more carefully.
</p><p>
The key to improving the performance of a very complicated
system is to analyze it well enough to find the
<i class="firstterm"> bottlenecks</i>, or places where most of the resources are consumed.
There is not much sense
in optimizing a function that accounts for only 1% of the
computation time.
As a rule of thumb you should think carefully before doing
anything unless you think it is going to make the system or
a significant part of it at least twice as fast.
There
is usually a way to do this. Consider
the test and quality assurance effort that your change
will require.
Each change brings a test burden
with it, so it is much better to have a few big changes.
</p><p>
After you've made a two-fold improvement in something, you need
to at least rethink and perhaps reanalyze to discover the
next-most-expensive bottleneck in the system,
and attack that to get another two-fold improvement.
</p><p>
Often, the bottlenecks in performance will be an example of
counting cows by counting legs and dividing by four, instead
of counting heads. For example, I've made errors such as
failing to provide a relational database system with a proper
index on a column I look up a lot, which probably made it
at least 20 times slower.
Other examples include doing
unnecessary I/O in inner loops, leaving in debugging
statements that are no longer needed, unnecessary memory
allocation, and, in particular, inexpert use of libraries and
other subsystems that are often poorly documented with respect
to performance. This kind of improvement is sometimes called
<i class="firstterm"> low-hanging fruit</i>, meaning that it can be easily picked to
provide some benefit.
</p><p>
What do you do when you start to run out of low-hanging fruit?
Well, you can reach higher, or chop the tree down. You can continue
making small improvements or you can seriously redesign a system or
a subsystem. (This is a great opportunity to use your skills as
a good programmer, not only in the new design but also in convincing
your boss that this is a good idea.)
However, before you argue for the redesign
of a subsystem, you should ask yourself
whether or not your proposal will
make it five to ten time better.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2794319"></a>How to Optimize Loops</h3></div></div><div></div></div><p>
Sometimes you'll encounter loops, or recursive functions, that take
a long time to execute and are bottlenecks in your product.
Before you try to
make the loop a little faster, but spend a few minutes considering
if there is a way to remove it entirely.
Would a different algorithm do?
Could you compute that while computing something else?
If you can't find away around it, then you can
optimize the loop.
This is simple; move stuff out. In the end,
this will require not only ingenuity but also an understanding of
the expense of each kind of statement and expression.
Here are some suggestions:
</p><div class="itemizedlist"><ul type="disc"><li><p>
Remove floating point operations.
</p></li><li><p>
Don't allocate new memory blocks unnecessarily.
</p></li><li><p>
Fold constants together.
</p></li><li><p>
Move I/O into a buffer.
</p></li><li><p>
Try not to divide.
</p></li><li><p>
Try not to do expensive typecasts.
</p></li><li><p>
Move a pointer rather than recomputing indices.
</p></li></ul></div><p>
The cost of each of these operations depends on your specific
system. On some systems compilers and hardware do these things
for you. Clear, efficient code is better than code that requires
an understanding of a particular platform.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2794412"></a>How to Deal with I/O Expense</h3></div></div><div></div></div><p>
For a lot of problems, processors are fast compared to the cost of
communicating with a hardware device. This cost is usually
abbreviated I/O, and can include network cost, disk I/O,
database queries, file I/O, and other use of
some hardware not very close to the processor.
Therefore building a fast system is often more a question of improving
I/O than improving the code in some tight loop, or even improving an algorithm.
</p><p>
There are two very fundamental techniques to improving I/O: caching
and representation. Caching is avoiding I/O (generally avoiding
the reading of some abstract value) by storing a copy of that value
locally so no I/O is performed to get the value.
The first key to caching is to make it crystal clear which data
is the <i class="firstterm"> master</i> and which are <i class="firstterm"> copies</i>. There is only one
master---period.
Caching brings with it the danger that the copy is sometimes can't
reflect changes to the master instantaneously.
</p><p>
Representation is the approach of making I/O cheaper by representing
data more efficiently. This is often in tension with other demands, like human readability and portability.
</p><p>
Representations can often be improved by a factor of two or three
from their first implementation. Techniques for doing this
include using a binary representation instead of one that is human readable,
transmitting a dictionary of symbols along with the data so that
long symbols don't have to be encoded, and, at the extreme, things
like Huffman encoding.
</p><p>
A third technique that is sometimes possible is to improve the
locality of reference by pushing the computation closer to the data.
For instance, if you are reading some data from a database and
computing something simple from it, such as a summation, try to
get the database server to do it for you. This is highly dependent
on the kind of system you're working with, but you should explore it.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2794476"></a>How to Manage Memory</h3></div></div><div></div></div><p>
Memory is a precious resource that you can't afford to run out of.
You can ignore it for a while but eventually you will have to
decide how to manage memory.
</p><p>
Space that needs to persist beyond the scope of a single subroutine
is often called <i class="firstterm"> heap allocated</i>.
A chunk of
memory is useless, hence <i class="firstterm"> garbage</i>, when nothing refers to it.
Depending on the system you use,
you may have to explicitly
deallocate memory yourself when it is about to
become garbage.
More often you may be able to use a system
that provides a <i class="firstterm"> garbage collector</i>.
A garbage collector
notices garbage and frees its space without
any action required by the programmer.
Garbage collection is wonderful:
it lessens errors and increases code
brevity and concision cheaply.
Use it when you can.
</p><p>
But even with
garbage collection, you can fill up all memory with garbage. A
classic mistake is to use a hash table as a cache and forget to
remove the references in the hash table.
Since the reference remains,
the referent is noncollectable but useless.
This is called a <i class="firstterm"> memory leak</i>.
You should look for and fix memory leaks early.
If you have long running
systems memory may never be exhausted in testing
but will be exhausted by the user.
</p><p>
The creation of new objects is moderately expensive on any system.
Memory allocated directly in the local variables of a subroutine, however,
is usually cheap
because the policy for freeing it can be very simple.
You should avoid
unnecessary object creation.
</p><p>
An important case occurs when you can define an upper bound on the number
of objects you will need at one time. If these objects all take up the
same amount of memory, you may be able to allocate a single block of memory,
or a buffer, to hold them all. The objects you need can be allocated and
released inside this buffer in a set rotation pattern, so it is sometimes
called a ring buffer. This is usually faster than heap allocation.
</p><p>
Sometimes you have to explicitly free allocated space so it can be
reallocated rather than rely on garbage collection. Then you must apply
careful intelligence to each chunk of allocated memory and design a way
for it to be deallocated at the appropriate time. The method may
differ for each kind of object you create. You must make sure that
every execution of a memory allocating operation is matched by a memory
deallocating operation eventually. This is so difficult that programmers often
simply implement a rudimentary form or garbage collection,
such as reference counting, to do this for them.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2794568"></a>How to Deal with Intermittent Bugs</h3></div></div><div></div></div><p>
The intermittent bug is a cousin of the
50-foot-invisible-scorpion-from-outer-space
kind of bug. This nightmare occurs so rarely that it is hard to observe,
yet often enough that it can't be ignored.
You can't debug because you can't find it.
</p><p>
Although after 8 hours you will start to doubt it,
the intermittent bug has to obey the same laws of logic everything else does.
What makes it hard is that it occurs only under unknown conditions. Try to
record the circumstances under which the bug does occur,
so that you can guess at
what the variability really is. The condition may be related to data values,
such as ‘<span class="quote">This only happens when we enter <span class="emphasis"><em> Wyoming</em></span> as a value.</span>’
If that is not
the source of variability, the next suspect should be
improperly synchronized concurrency.
</p><p>
Try, try, try to reproduce the bug in a controlled way.
If you can't reproduce it, set a trap
for it by building a logging system, a special one if you have to,
that can log what you guess you need when it really does occur.
Resign yourself to that if the bug only occurs
in production and not at your whim, this is may be a long process.
The hints that you get from the log may not provide
the solution but may give you enough information to
improve the logging.
The improved logging system may take a long time to be put into production.
Then, you have to wait for the bug to reoccur to get more information.
This cycle can go on for some time.
</p><p>
The stupidest intermittent bug I ever created was in a multi-threaded
implementation of a functional
programming language for a class project.
I had very carefully
insured correct concurrent evaluation of the functional program,
good utilization of all the CPUs available (eight, in this case).
I simply forgot to synchronize
the garbage collector. The system could run
a long time, often finishing whatever task I began,
before anything noticeable went wrong.
I'm ashamed to admit I
had begun to question the hardware before
my mistake dawned on me.
</p><p>
At work we recently had an intermittent bug that took us several
weeks to find. We have multi-threaded application servers in
<span class="trademark">Java</span>™ behind <span class="trademark">Apache</span>™ web servers.
To maintain fast page turns,
we do all I/O in small set of four separate threads that are different
than the page-turning threads. Every once in a while these would
apparently get ‘<span class="quote">stuck</span>’ and cease doing anything useful, so far as
our logging allowed us to tell, for hours. Since we had four threads,
this was not in itself a giant problem---unless all four got stuck.
Then the queues emptied by these threads would quickly fill up
all available memory and crash our server. It took us about a
week to figure this much out, and we still didn't know what caused
it, when it would happen, or even what the threads where doing when
they got ‘<span class="quote">stuck</span>’.
</p><p>
This illustrates some risk associated with third-party
software. We were using a licensed piece of code that removed
HTML tags from text. Due to its place of origin we affectionately
referred to this as ‘<span class="quote">the French stripper.</span>’ Although we had the
source code (thank goodness!) we had not studied it carefully
until by turning up the logging on our servers we finally realized
that the email threads were getting stuck in the French stripper.
</p><p>
The stripper performed well except on some long and unusual kinds of texts.
On these texts, the code was quadratic or worse. This means
that the processing time was proportional to the square of the length
of the text.
Had these texts occurred commonly, we would have found the bug
right away. If they had never occurred at all, we would never have
had a problem. As it happens, it took us weeks to finally understand
and resolve the problem.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2838857"></a>How to Learn Design Skills</h3></div></div><div></div></div><p>
To learn how to design software, study the action of a mentor by
being physically present when they are designing. Then study
well-written pieces of software. After that, you can read some books on the latest design techniques.
</p><p>
Then you must do it yourself. Start with a small project.
When you are finally done, consider how the design failed or
succeeded and how you diverged from your original conception.
They move on to larger projects, hopefully in conjunction with
other people. Design is a matter of judgment that takes years
to acquire. A smart programmer can learn the basics adequately in
two months and can improve from there.
</p><p>
It is natural and helpful to develop your own style, but remember
that design is an art, not a science. People who write books on
the subject have a vested interest in making it seem scientific.
Don't become dogmatic about particular design styles.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2838894"></a>How to Conduct Experiments</h3></div></div><div></div></div><p>
The late, great Edsger Dijkstra has eloquently explained that Computer Science
is not an experimental science[<span class="citation">ExpCS</span>] and doesn't
depend on electronic computers.
As he puts it referring to the 1960s[<span class="citation">Knife</span>],
</p><div class="blockquote"><blockquote class="blockquote">
...the harm was done: the topic became known as
“<span class="quote">computer science</span>”---which, actually, is like referring to
surgery as “<span class="quote">knife science</span>” --- and it was firmly implanted
in people's minds that computing science is about
machines and their peripheral equipment.
</blockquote></div><p>
Programming ought not to be an experimental science,
but most working programmers do not have the luxury of
engaging in what Dijkstra means by computing science.
We must work in the realm of experimentation, just as some,
but not all, physicists do. If thirty years from now
programming can be performed without experimentation, it
will be a great accomplishment of Computer Science.
</p><p>
The kinds of experiments you will have to perform include:
</p><div class="itemizedlist"><ul type="disc"><li><p>
Testing systems with small examples to verify that they
conform to the documentation or to understand their response
when there is no documentation,
</p></li><li><p>
Testing small code changes to see if they actually fix
a bug,
</p></li><li><p>
Measuring the performance of a system under two
different conditions due to imperfect knowledge of there
performance characteristics,
</p></li><li><p>
Checking the integrity of data, and
</p></li><li><p>
Collecting statistics that may hint at the solution to difficult or hard-to-repeat bugs.
</p></li></ul></div><p>
I don't think in this essay I can explain the design of experiments;
you will have to study and practice. However, I can offer two
bits of advice.
</p><p>
First, try to be very clear about your hypothesis, or the assertion
that you are trying to test. It also helps to write the hypothesis
down, especially if you find yourself confused or are working with
others.
</p><p>
You will often find yourself having to design a series of
experiments, each of which is based on the knowledge gained from
the last experiment. Therefore, you should design your experiments
to provide the most information possible. Unfortunately, this
is in tension with keeping each experiment simple---you will
have to develop this judgment through experience.
</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2839021"></a>Team Skills</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2839027"></a>Why Estimation is Important</h3></div></div><div></div></div><p>
To get a working software system in active use as quickly as possible
requires not only planning the development,
but also planning the documentation,
deployment, marketing.
In a commercial project it also requires sales and finance.
Without predictability of the
development time, it is impossible to plan these effectively.
</p><p>
Good estimation provides predictability.
Managers love it,
as well they should. The fact that it is impossible, both
theoretically and practically, to predict accurately how long it
will take to develop software is often lost on managers.
We are
asked to do this impossible thing all the time, and we must face
up to it honestly. However, it would be dishonest not to admit
the impossibility of this task,
and when necessary, explain it. There is a lot of room for
miscommunication about estimates, as people have a startling
tendency to think wishfully that the sentence:
</p><div class="blockquote"><blockquote class="blockquote">
I estimate that, if I really understand the problem, it
is about 50% likely that we will be done in five weeks
(if no one bothers us during that time).
</blockquote></div><p>
really means:
</p><div class="blockquote"><blockquote class="blockquote">
I promise to have it all done five weeks from now.
</blockquote></div><p>
This common interpretation problem requires that you
explicitly discuss what the estimate means with
your boss or customer as if they were a simpleton.
Restate your assumptions, no matter how obvious they seem to you.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2839075"></a>How to Estimate Programming Time</h3></div></div><div></div></div><p>
Estimation takes practice. It also takes labor. It takes so
much labor it may be a good idea to estimate the time it will
take to make the estimate, especially if you are asked to
estimate something big.
</p><p>
When asked to provide an estimate of something big,
the most honest thing to
do is to stall.
Most engineers are enthusiastic and eager
to please, and stalling certainly will displease the stalled.
But an on-the-spot estimate probably won't be accurate and honest.
</p><p>
While stalling, it may be possible to consider doing or prototyping
the task. If political pressure permits, this is the most accurate
way of producing the estimate, and it makes real progress.
</p><p>
When not possible to take the time for
some investigation, you should first establish the meaning of the
estimate very clearly. Restate that meaning as the first and
last part of your written estimate. Prepare a written
estimate by deconstructing the task into progressively smaller
subtasks until each small task is no more than a day;
ideally at most in length.
The most important thing
is not to leave anything out. For instance, documentation,
testing, time for planning, time for communicating with other
groups, and vacation time are all very important. If you spend
part of each day dealing with knuckleheads, put a line item for
that in the estimate. This gives your boss visibility into what
is using up your time at a minimum, and might get you more time.
</p><p>
I know good engineers who pad estimates implicitly,
but I recommend that you do not. One of the results
of padding is trust in you may be depleted. For instance,
an engineer might estimate three days for a task that
she truly thinks will take one day. The engineer may
plan to spend two days documenting it, or two days working
on some other useful project. But it will be detectable
that the task was done in only one day (if it turns out that way),
and the appearance of slacking or overestimating is born.
It's far better to give proper visibility into what you are
actually doing. If documentation takes twice as long
as coding and the estimate says so, tremendous advantage
is gained by making this visible to the manager.
</p><p>
Pad explicitly instead. If a task will probably take one
day---but might take ten days if your approach doesn't
work---note this somehow in the estimate if you can; if not, at
least do an average weighted by your estimates of the probabilities.
Any risk factor that you can identify and assign an
estimate to should go into the schedule. One person is
unlikely to be sick in any given week. But a large
project with many engineers will have some sick time;
likewise vacation time. And what is the probability of
a mandatory company-wide training seminar? If it can
be estimated, stick it in.
There are of course, unknown unknowns, or <i class="firstterm"> unk-unks</i>.
Unk-unks by definition cannot be estimated individually.
You can try to create a global line item for all unk-unks,
or handle them in some other way that you communicate to your boss.
You cannot, however, let your boss forget that they exist, and it is
devilishly easy for an estimate to become a schedule without
the unk-unks considered.
</p><p>
In a team environment, you should try to have the
people who will do the work do the estimate, and you
should try to have team-wide consensus on estimates.
People vary widely in skill, experience, preparedness,
and confidence. Calamity strikes when a strong programmer
estimates for herself and then weak programmers are held
to this estimate.
The act of having the whole team agree
on a line-by-line basis to the estimate clarifies the team
understanding, as well as allowing the opportunity for
tactical reassignment of resources (for instance, shifting
burden away from weaker team members to stronger).
</p><p>
If there are big risks that cannot be evaluated, it is your
duty to state so forcefully enough that your manager does
not commit to them and then become embarrassed when the risk occurs.
Hopefully in such a case whatever is needed will be done to decrease the risk.
</p><p>
If you can convince your company to use <i class="firstterm"> Extreme Programming</i>, you
will only have to estimate relatively small things, and this is
both more fun and more productive.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2839206"></a>How to Find Out Information</h3></div></div><div></div></div><p>
The nature of what you need to know determines how you should find it.
</p><p>
If you need information <span class="emphasis"><em>about concrete things</em></span> that are
objective and easy to verify, for example the latest
patch level of a software product, ask a large number of people
politely by searching the internet for it or by posting on
a discussion group.
Don't search on the internet for anything that smacks
of either opinion or subjective interpretation:
the ratio of drivel to truth is too high.
</p><p>
If you need <span class="emphasis"><em>general knowledge about something subjective</em></span> the
history of what people have thought about it, go to the library
(the physical building in which books are stored). For example,
to learn about math or mushrooms or mysticism, go to the library.
</p><p>
If you need to know <span class="emphasis"><em>how to do something that is not trivial</em></span> get two
or three books on the subject and read them. You might learn how
to do something trivial, like install a software package, from the
Internet. You can even learn important things, like good programming
technique, but you can easily spend more time searching and sorting
the results and attempting to divine the authority of the results than
it would take to read the pertinent part of a solid book.
</p><p>
If you need <span class="emphasis"><em>information that no one else could be expected to know</em></span>
for example, ‘<span class="quote">does this software that is brand new work on gigantic
data sets?</span>’, you must still search the internet and the library.
After those options are completely exhausted, you may design
an experiment to ascertain it.
</p><p>
If you want an opinion or a value judgment that takes into account
some unique circumstance, talk to an expert.
For instance, if you want
to know whether or not it
is a good idea to build a modern database management system
in LISP, you should talk to a LISP expert and a database expert.
</p><p>
If you want to know <span class="emphasis"><em>how likely it is</em></span> that a faster algorithm for
a particular application exists that has not yet been published,
talk to someone working in that field.
</p><p>
If you want to make a <span class="emphasis"><em>personal decision that only you can make</em></span>
like whether or not you should start a business,
try putting into writing a list of arguments for and against the
idea. If that fails, consider divination.
Suppose you have studied the idea from all angles,
have done all your homework, and worked out all the consequences
and pros and cons in your mind, and yet still remain indecisive.
You now must follow your heart and tell your brain to shut up.
The multitude of available divination techniques are very useful
for determining your own semi-conscious desires, as they each present a complete
ambiguous and random pattern that your own subconscious will assign meaning to.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2791028"></a>How to Utilize People as Information Sources</h3></div></div><div></div></div><p>
Respect every person's time and balance it against your own.
Asking someone a question accomplishes far more than just
receiving the answer. The person learns about you, both by
enjoying your presence and hearing the particular question.
You learn about the person in the same way, and you may
learn the answer you seek. This is usually far more important than your question.
</p><p>
However, the value of this diminishes the more you do it.
You are, after all, using the most precious commodity
a person has: their time.
The benefits of communication
must be weighed against the costs. Furthermore, the
particular costs and benefits derived differ from person
to person. I strongly believe that an executive of 100
people should spend five minutes a month talking to each person
in her organization, which would be about 5%
of their time. But ten minutes might be too much, and five
minutes is too much if they have one thousand employees.
The amount of time you spend talking to each person in your
organization depends on their role (more than their position).
You should talk to your boss more than your boss's boss,
but you should talk to your boss's boss a little. It may
be uncomfortable, but I believe you have a duty to talk a
little bit to all your superiors, each month, no matter what.
</p><p>
The basic rule is that everyone benefits from talking to you a little bit,
and the more they talk to you, the less benefit they derive.
It is your job to provide them this benefit, and to get the benefit
of communicating with them, keeping the benefit in balance with the time spent.
</p><p>
It is important to respect your own time. If talking to
someone, even if it will cost them time, will save you a
great deal of time, then you should do it unless you think
their time is more valuable than yours, to the tribe, by that factor.
</p><p>
A strange example of this is the summer intern. A summer
intern in a highly technical position can't be expected
to accomplish too much; they can be expected to pester the
hell out of everybody there. So why is this tolerated?
Because the pestered are receiving something important from the intern.
They get a chance to showoff a little. They get a chance to hear
some new ideas, maybe; they get a chance to see things from
a different perspective. They may also be trying to recruit
the intern, but even if this is not the case there is much to gain.
</p><p>
You should ask people for a little bit of their wisdom and
judgment whenever you honestly believe they have something to say.
This flatters them and you will learn something and teach them
something. A good programmer does not often need the advice of
a Vice President of Sales, but if you ever do,
you be sure to ask for it. I once asked to listen in on a few sales
calls to better understand the job of our sales staff.
This took no more than 30 minutes but I think that small effort made
an impression on the sales force.
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2791115"></a>How to Document Wisely</h3></div></div><div></div></div><p>
Life is too short to write crap nobody will read;
if you write crap,
nobody will read it.
Therefore a little good documentation is best.
Managers often don't understand this,
because even bad documentation gives them a false sense of security
that they are not dependent on their programmers.
If someone absolutely insists that you write truly useless
documentation, say ``yes'' and quietly begin looking for a better job.
</p><p>
There's nothing quite as effective as putting an accurate estimate
of the amount of time it will take to produce good documentation
into an estimate to slacken the demand for documentation.
The truth is cold and hard: documentation, like testing,
can take many times longer than developing code.
</p><p>
Writing good documentation is, first of all, good writing.
I suggest you find books on writing, study them, and practice.
But even if you are a lousy writer or have poor command of the
language in which you must document, the Golden Rule is all you really need:
``Do unto others as you would have them do unto you.''
Take time to really think about who will be reading your
documentation, what they need to get out of it, and how you
can teach that to them. If you do that, you will be an above
average documentation writer, and a good programmer.
</p><p>
When it comes to actually documenting code itself, as opposed
to producing documents that can actually be read by non-programmers,
the best programmers I've ever known hold a universal sentiment:
write self-explanatory code and only document code in
the places that you cannot make it clear by writing the code itself.
There are two good reasons for this.
First, anyone who needs to see code-level documentation
will in most cases be able to and prefer to read the code anyway.
Admittedly, this seems easier to the experienced programmer than
to the beginner.
More importantly however, is that the code
and the documentation cannot be inconsistent if there is no documentation.
The source code can at worst be wrong and confusing.
The documentation, if not written perfectly, can lie, and that is a thousand times worse.
</p><p>
This does not make it easier on the responsible programmer.
How does one write self-explanatory code? What does that even mean? It means:
</p><div class="itemizedlist"><ul type="disc"><li><p>
Writing code knowing that someone will have to read it;
</p></li><li><p>
Applying the golden rule;
</p></li><li><p>
Choosing a solution that is straightforward,
even if you could get by with another solution faster;
</p></li><li><p>
Sacrificing small optimizations that obfuscate the code;
</p></li><li><p>
Thinking about the reader and spending some of your precious time to make it easier on her; and
</p></li><li><p>
Not ever using a function name like ``foo'',``bar'', or ``doIt''!
</p></li></ul></div><p>
</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2791248"></a>How to Work with Poor Code</h3></div></div><div></div></div><p>
It is very common to have to work with poor quality code
that someone else has written. Don't think too poorly of them,
however, until you have walked in their shoes. They may