35,99 €
Discover the foundations of software engineering with this easy and intuitive guide In the newly updated second edition of Beginning Software Engineering, expert programmer and tech educator Rod Stephens delivers an instructive and intuitive introduction to the fundamentals of software engineering. In the book, you'll learn to create well-constructed software applications that meet the needs of users while developing the practical, hands-on skills needed to build robust, efficient, and reliable software. The author skips the unnecessary jargon and sticks to simple and straightforward English to help you understand the concepts and ideas discussed within. He also offers you real-world tested methods you can apply to any programming language. You'll also get: * Practical tips for preparing for programming job interviews, which often include questions about software engineering practices * A no-nonsense guide to requirements gathering, system modeling, design, implementation, testing, and debugging * Brand-new coverage of user interface design, algorithms, and programming language choices Beginning Software Engineering doesn't assume any experience with programming, development, or management. It's plentiful figures and graphics help to explain the foundational concepts and every chapter offers several case examples, Try It Out, and How It Works explanatory sections. For anyone interested in a new career in software development, or simply curious about the software engineering process, Beginning Software Engineering, Second Edition is the handbook you've been waiting for.
Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 1396
Veröffentlichungsjahr: 2022
COVER
TABLE OF CONTENTS
TITLE PAGE
INTRODUCTION
WHAT IS SOFTWARE ENGINEERING?
WHY IS SOFTWARE ENGINEERING IMPORTANT?
WHO SHOULD READ THIS BOOK?
APPROACH
WHAT THIS BOOK COVERS (AND WHAT IT DOESN'T)
WHAT TOOLS DO YOU NEED?
CONVENTIONS
ERRATA
IMPORTANT URLs
CONTACTING THE AUTHOR
DISCLAIMER
PART I: Software Engineering Step-by-Step
1 Software Engineering from 20,000 Feet
REQUIREMENTS GATHERING
HIGH-LEVEL DESIGN
LOW-LEVEL DESIGN
DEVELOPMENT
TESTING
DEPLOYMENT
MAINTENANCE
WRAP-UP
EVERYTHING ALL AT ONCE
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
2 Before the Beginning
DOCUMENT MANAGEMENT
HISTORICAL DOCUMENTS
CODE
CODE DOCUMENTATION
APPLICATION DOCUMENTATION
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
3 The Team
TEAM FEATURES
TEAM ROLES
TEAM CULTURE
INTERVIEWS
PHYSICAL ENVIRONMENT
COLLABORATION SOFTWARE
OUTSOURCING
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
4 Project Management
EXECUTIVE SUPPORT
PROJECT MANAGEMENT
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
5 Requirements Gathering
REQUIREMENTS DEFINED
REQUIREMENT CATEGORIES
GATHERING REQUIREMENTS
REFINING REQUIREMENTS
RECORDING REQUIREMENTS
VALIDATION AND VERIFICATION
CHANGING REQUIREMENTS
DIGITAL TRANSFORMATION
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
6 High-Level Design
THE BIG PICTURE
WHAT TO SPECIFY
UML
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
7 Low-Level Design
DESIGN APPROACHES
OO DESIGN
DATABASE DESIGN
WHEN TO OPTIMIZE
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
8 Security Design
SECURITY GOALS
SECURITY TYPES
CYBERSECURITY
SHIFT-LEFT SECURITY
MALWARE MENAGERIE
PHISHING AND SPOOFING
SOCIAL ENGINEERING ATTACKS
CRAPWARE
PASSWORD ATTACKS
USER ACCESS
COUNTERMEASURES
CYBER INSURANCE
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
9 User Experience Design
DESIGN MINDSET
DESIGN GUIDELINES
FORM DESIGN
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
10 Programming
TOOLS
ALGORITHMS
TOP-DOWN DESIGN
PROGRAMMING TIPS AND TRICKS
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
11 Algorithms
ALGORITHM STUDY
ALGORITHMIC APPROACHES
ALGORITHM CHARACTERISTICS
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
12 Programming Languages
THE MYTH OF PICKING A LANGUAGE
LANGUAGE GENERATIONS
LANGUAGE FAMILIES
THE BEST LANGUAGE
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
13 Testing
TESTING GOALS
REASONS BUGS NEVER DIE
LEVELS OF TESTING
TESTING TECHNIQUES
TESTING HABITS
HOW TO FIX A BUG
ESTIMATING NUMBER OF BUGS
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
14 Deployment
SCOPE
THE PLAN
CUTOVER
DEPLOYMENT TASKS
DEPLOYMENT MISTAKES
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
15 Metrics
WRAP PARTY
DEFECT ANALYSIS
SOFTWARE METRICS
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
16 Maintenance
MAINTENANCE COSTS
TASK CATEGORIES
TASK EXECUTION
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
PART II: Process Models
17 Predictive Models
MODEL APPROACHES
PREREQUISITES
PREDICTIVE AND ADAPTIVE
WATERFALL
WATERFALL WITH FEEDBACK
SASHIMI
INCREMENTAL WATERFALL
V-MODEL
SOFTWARE DEVELOPMENT LIFE CYCLE
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
18 Iterative Models
ITERATIVE VS. PREDICTIVE
ITERATIVE VS. INCREMENTAL
PROTOTYPES
SPIRAL
UNIFIED PROCESS
CLEANROOM
COWBOY CODING
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
19 RAD
RAD PRINCIPLES
JAMES MARTIN RAD
AGILE
XP
SCRUM
LEAN
CRYSTAL
FEATURE-DRIVEN DEVELOPMENT
DISCIPLINED AGILE DELIVERY
DYNAMIC SYSTEMS DEVELOPMENT METHOD
KANBAN
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
PART III: Advanced Topics
20 Software Ethics
ETHICAL BEHAVIOR
RESPONSIBILITY
THOUGHT EXPERIMENTS
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
21 Future Trends
SECURITY
UX/UI
CODE PACKAGING
CLOUD TECHNOLOGY
SOFTWARE DEVELOPMENT
ALGORITHMS
TECH TOYS
SUMMARY
WHAT YOU LEARNED IN THIS CHAPTER
APPENDIX: Solutions to Exercises
CHAPTER 1
CHAPTER 2
CHAPTER 3
CHAPTER 4
CHAPTER 5
CHAPTER 6
CHAPTER 7
CHAPTER 8
CHAPTER 9
CHAPTER 10
CHAPTER 11
CHAPTER 12
CHAPTER 13
CHAPTER 14
CHAPTER 15
CHAPTER 16
CHAPTER 17
CHAPTER 18
CHAPTER 19
CHAPTER 20
CHAPTER 21
GLOSSARY
INDEX
COPYRIGHT
ABOUT THE AUTHOR
ABOUT THE TECHNICAL EDITOR
ACKNOWLEDGMENTS
END USER LICENSE AGREEMENT
Chapter 4
TABLE 4.1: Tasks for a zombie apocalypse bunker
TABLE 4.2: Classes and modules for
World of Z-Craft
Chapter 6
TABLE 6.1: Office supply purchasing sequence
TABLE 6.2: Class diagram visibility symbols
TABLE 6.3: Class diagram multiplicity indicators
TABLE 6.4: Activity diagram symbols
Chapter 7
TABLE 7.1: Weapons training signup sheet
TABLE 7.2: Ordered signup sheet
TABLE 7.3: Signup sheet with times
TABLE 7.4: Signup sheet with explicitly listed weapons
TABLE 7.5: Camp games schedule
TABLE 7.6: Counselors' favorite books
Chapter 15
TABLE 15.1: Attributes for projects Ruction and Fracas
TABLE 15.2: Normalized metrics for projects Ruction and Fracas
TABLE 15.3: CAV ratings
TABLE 15.4: Sample CAV ratings
TABLE 15.5: Number of programmers
TABLE 15.6: Lines of code and bugs
TABLE 15.7: Project Hydra progress
Chapter 19
TABLE 19.1: Release schedule for a three-month project
TABLE 19.2: FDD milestones
Appendix
TABLE A.1: Properties shared by ClassyDraw classes
TABLE A.2: Complexity adjustment factors for WordPad
TABLE A.3: Complexity adjustment factors for Microsoft Word
TABLE A.4: Normalized LOC and bugs
TABLE A.5: Percentage of LOC and time for previous projects
TABLE A.6: Percentage of LOC and time for project Hydra
Chapter 1
FIGURE 1.1: The circles represent possible mistakes at different stages of d...
Chapter 4
FIGURE 4.1: Each task's card should hold its name, duration, and predecessor...
FIGURE 4.2: Initially only the Start task is in the Ready pile.
FIGURE 4.3: After one round, the Start task is positioned and tasks A, F, an...
FIGURE 4.4: After two rounds, the Start task and tasks A, F, and H are posit...
FIGURE 4.5: After three rounds, the Start task and tasks A, F, H, and B are ...
FIGURE 4.6: After four rounds, only the Finish task is still in the Pending ...
FIGURE 4.7: This PERT chart shows the paths of execution of the project's ta...
FIGURE 4.8: The total time for each task is its expected time plus the large...
FIGURE 4.9: Task I's largest time predecessor is task B, so task I has a tot...
FIGURE 4.10: The complete zombie apocalypse bunker project has a total time ...
FIGURE 4.11: A Gantt chart shows task durations, start times, end times, and...
Chapter 5
FIGURE 5.1: The Mr. Bones application is a hangman word game for smartphones...
Chapter 6
FIGURE 6.1: An application can directly hold its own data.
FIGURE 6.2: In a two-tier architecture, the client is separate from the serv...
FIGURE 6.3: A three-tier architecture separates clients and servers with a m...
FIGURE 6.4: In a component-based architecture, components help decouple piec...
FIGURE 6.5: A data flow diagram shows how data such as a customer order flow...
FIGURE 6.6: Complicated data flows may take different paths depending on cir...
FIGURE 6.7: A class diagram describes the properties and methods of classes....
FIGURE 6.8: The relationship in this class diagram indicates that 1 student ...
FIGURE 6.9: A class diagram indicates inheritance with a hollow arrowhead.
FIGURE 6.10: An activity diagram is a bit like a flowchart showing how work ...
FIGURE 6.11: A use case diagram shows actors and the tasks they perform (pos...
FIGURE 6.12: This state machine diagram represents reading a floating-point ...
FIGURE 6.13: A sequence diagram shows the timing of messages between collabo...
FIGURE 6.14: A communication diagram emphasizes the objects participating in...
Chapter 7
FIGURE 7.1: People are naturally good at building inheritance hierarchies.
FIGURE 7.2: This hierarchy focuses on behavioral differences between classes...
FIGURE 7.3: Generalization creates the
Drawable
parent class.
FIGURE 7.6: This design is in first normal form (1NF). Lines connect related...
FIGURE 7.7: Moving the data that doesn't depend on
all
the table's key field...
FIGURE 7.8: Moving non-key fields that depend on other non-key fields into a...
Chapter 8
FIGURE 8.1: MFA is a conversation between a user and an application.
Chapter 9
FIGURE 9.1: Word's ribbon assumes the user is an eternal beginner.
FIGURE 9.2: Word uses verbose tooltips because the ribbon already includes d...
FIGURE 9.3: Visual Studio assumes the user is at least intermediate and poss...
Chapter 11
FIGURE 11.1: A decision tree represents combinations of decisions.
FIGURE 11.2: An algorithm can use backtracking to move back up a tree to exp...
FIGURE 11.3: The recursive Fibonacci calculation repeats the same calls many...
FIGURE 11.4: Dynamic programming removes many nodes from the call tree.
FIGURE 11.5: You can use a state diagram to model a login process.
FIGURE 11.6: Drawing a Mandelbrot set is embarrassingly parallel.
Chapter 13
FIGURE 13.1: When you're in the “getting close to zero” part of the graph, y...
Chapter 14
FIGURE 14.1: This schedule takes 11 workdays to migrate all 20 users to Adve...
Chapter 15
FIGURE 15.1: An Ishikawa (or fishbone) diagram shows causes leading to effec...
FIGURE 15.2: The exact format of an Ishikawa diagram doesn't matter as long ...
FIGURE 15.3: This graph shows the relationship between hours of code review ...
Chapter 17
FIGURE 17.1: In the waterfall model, each step follows the one before in a s...
FIGURE 17.2: In the waterfall with feedback model, you can go back to the pr...
FIGURE 17.3: In the sashimi model, development phases overlap.
FIGURE 17.4: In the incremental waterfall model, a series of waterfall casca...
FIGURE 17.5: This incremental waterfall project uses a series of sashimi wat...
FIGURE 17.6: In V-model, each of the tasks on the left corresponds to a task...
FIGURE 17.7: In the software development life cycle, project phases feed int...
Chapter 18
FIGURE 18.1: Iterative models use a series of development efforts to increme...
FIGURE 18.2: Different development approaches add features and increase fide...
FIGURE 18.3: The spiral process uses four phases.
FIGURE 18.4: In this project, the major risks were requirements, design, and...
FIGURE 18.5: In the Unified Process, construction takes more time and effort...
FIGURE 18.6: In the Unified Process, the amounts of different kinds of work ...
Chapter 19
FIGURE 19.1: In James Martin RAD, the user design and construction phases it...
FIGURE 19.2: In test-driven development, you write a test for each function ...
FIGURE 19.3: A project burndown chart shows the amount of work remaining for...
FIGURE 19.5: In FDD, the last two phases repeat for each feature iteration. ...
FIGURE 19.6: The DSDM life cycle includes four stages: study, functional mod...
FIGURE 19.7: The kanban board lets everyone see the status of the project's ...
Appendix
FIGURE A.1: Microsoft Word has revision-tracking tools that let you see who ...
FIGURE A.2: Google Docs also has revision-tracking tools that let you see wh...
FIGURE A.3: This PERT chart includes tasks needed to build a small part of a...
FIGURE A.4: The critical path for this piece of the zombie apocalypse game i...
FIGURE A.5: This Gantt chart shows this piece of the zombie apocalypse game ...
FIGURE A.6: GanttProject uses task data to generate a Gantt chart.
FIGURE A.7: Enter predecessor information on the Predecessors tab.
FIGURE A.8: This state machine diagram shows how a program could read a floa...
FIGURE A.9: This inheritance hierarchy represents shape classes in the Class...
FIGURE A.10: This inheritance hierarchy represents business classes.
FIGURE A.11: A hierarchy that combines the
Salaried
,
Manager
, and
VicePresid
...
FIGURE A.13: This Ishikawa diagram shows possible causes for New Hampshire n...
FIGURE A.16: This graph shows percent of LOC versus percent of elapsed time ...
FIGURE A.17: Project Hydra is generating code slowly compared to the previou...
FIGURE A.18: This flowchart shows the states through which most bugs pass.
FIGURE A.19: Users play a large role as requirements are created and refined...
FIGURE A.20: This diagram shows how waterfall tasks match up with Unified Pr...
Cover
Table of Contents
Title Page
Copyright
About the Author
Acknowledgments
Introduction
Begin Reading
Appendix: Solutions to Exercises
Glossary
Index
End User License Agreement
v
xxvii
xxviii
xxix
xxx
xxxi
xxxii
xxxiii
xxxiv
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
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
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
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
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
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
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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
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
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
425
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
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
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
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
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
vi
vii
ix
686
Second Edition
Rod Stephens
CHAPTER 1:
Software Engineering from 20,000 Feet
CHAPTER 2:
Before the Beginning
CHAPTER 3:
The Team
CHAPTER 4:
Project Management
CHAPTER 5:
Requirements Gathering
CHAPTER 6:
High-Level Design
CHAPTER 7:
Low-Level Design
CHAPTER 8:
Security Design
CHAPTER 9:
User Experience Design
CHAPTER 10:
Programming
CHAPTER 11:
Algorithms
CHAPTER 12:
Programming Languages
CHAPTER 13:
Testing
CHAPTER 14:
Deployment
CHAPTER 15:
Metrics
CHAPTER 16:
Maintenance
Software and cathedrals are much the same. First we build them, then we pray.
—Samuel Redwine
In principle, software engineering is a simple two-step process: (1) Write a best-selling program, and then (2) buy expensive toys with the profits. Unfortunately, the first step can be rather difficult. Saying “write a best-selling program” is a bit like telling an author, “Write a best-selling book,” or telling a baseball player “triple to left.” It's a great idea, but knowing the goal doesn't actually help you achieve it.
To produce great software, you need to handle a huge number of complicated tasks, any one of which can fail and sink the entire project. Over the years people have developed a multitude of methodologies and techniques to help keep software projects on track. Some of these, such as the waterfall and V-model approaches, use detailed requirement specifications to exactly define the desired results before development begins. Others, such as Scrum and agile techniques, rely on fast-paced incremental development with frequent feedback to keep a project on track. Still other techniques, such as cowboy coding and extreme programming, sound more like action-adventure films than software development techniques. (I'll say more about these in Part II, “Process Models.”)
Different development methodologies use different approaches, but they all perform roughly the same tasks. They all determine what the software should do and how it should do it. They generate the software, remove bugs from the code (some of the bugs, at least), make sure the software does more or less what it should, and deploy the finished result.
NOTE I call these basic items “tasks” and not “stages” or “steps” because different software engineering approaches tackle them in different ways and at different times. Calling them “stages” or “steps” would probably be misleading because it would imply that all projects move through the stages in the same predictable order and that's not true.
The chapters in the first part of this book describe those basic tasks that any successful software project must handle in some way. They explain the main steps in software development and describe some of the myriad ways a project can fail to handle those tasks. (The second part of the book explains how different approaches such as waterfall and agile handle those tasks.)
The first chapter in this part of the book provides an overview of software development from a high level. The subsequent chapters explain the pieces of the development process in greater detail.
If you fail to plan, you are planning to fail.
—Benjamin Franklin
There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. The other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.
—C.A.R. Hoare
What You Will Learn in This Chapter:
The basic steps required for successful software engineering
Ways in which software engineering differs from other kinds of engineering
How fixing one bug can lead to others
Why it is important to detect mistakes as early as possible
In many ways, software engineering is a lot like other kinds of engineering. Whether you're building a bridge, an airplane, a nuclear power plant, or a new and improved version of Sudoku, you need to accomplish certain tasks. For example, you need to make a plan, follow that plan, heroically overcome unexpected obstacles, and hire a great band to play at the ribbon-cutting ceremony.
The following sections describe the steps you need to take to keep a software engineering project on track. These are more or less the same for any large project, although there are some important differences that are specific to software engineering. Later chapters in this book provide a lot more detail about these tasks.
No big project can succeed without a plan. Sometimes a project doesn't follow the plan closely, but every big project must have a plan. The plan tells project members what they should be doing, when and how long they should be doing it, and most important, what the project's goals are. They give the project direction.
One of the first steps in a software project is figuring out the requirements. You need to find out what the customers want and what the customers need. Depending on how well-defined the user's needs are, this chore can be time-consuming.
Sometimes, it's easy to tell who the customer is. If you're writing software for another part of your own company, it may be obvious who the customers are. In that case, you can sit down with them and talk about what the software should do.
In other cases, you may have only a vague notion of who will use the finished software. For example, if you're creating a new online card game, it may be hard to identify the customers until after you start marketing the game.
Sometimes, you may even be the customer. I write software for myself all the time. This has a lot of advantages. For example, I know exactly what I want (usually) and I know more or less how hard it will be to provide different features. (Unfortunately, I also sometimes have a hard time saying no to myself, so projects can drag on for a lot longer than they should.)
In any project, you should try to identify your customers and interact with them as much as possible so that you can design the most useful application possible.
After you determine the customers' wants and needs (which are not always the same), you can turn them into requirements documents. Those documents tell the customers what they will be getting, and they tell the project members what they will be building.
NOTE I refer to requirements a lot in this book. In general, when I say requirements, I mean the officially sanctioned requirements as recorded in the requirements documents and later carved in marble on the project's memorial. Anything else (such as customer suggestions, developer complaints, and management wishful thinking) are not part of the requirements until they are approved by the powers that be.
Throughout the project, both customers and team members can refer to the requirements to see if the project is heading in the right direction. If someone suggests that the project should include a video tutorial, you can see if that was included in the requirements. If this is a new feature, you might allow that change if it would be useful and wouldn't mess up the rest of the schedule. If that request doesn't make sense, either because it wouldn't add value to the project or you can't do it with the time you have, then you may need to defer it for a later release.
Although there are some similarities between software and other kinds of engineering, the fact that software doesn't exist in any physical way means there are some major differences as well. Because software is so malleable, users frequently ask for new features up to the day before the release party. They ask developers to shorten schedules and request last-minute changes such as switching database platforms or even hardware platforms. (Yes, both of those have happened to me.) “The program is just 0s and 1s,” they reason. “The 0s and 1s don't care whether they run on an Android tablet or an iPhone, do they?”
In contrast, a company wouldn't ask an architectural firm to move a new convention center across the street at the last minute; a city transportation authority wouldn't ask the builder to add an extra lane to a freeway bridge right after it opens; and no one would try to insert an atrium level at the bottom of a newly completed 90-story building.
After you know the project's requirements, you can start working on the high-level design. The high-level design includes such things as decisions about what platform to use (such as desktop, laptop, tablet, or phone), what data design to use (such as direct access, 2-tier, or 3-tier), and what interfaces with other systems to use (such as external purchasing systems or a payroll system hosted in the cloud).
The high-level design should also include information about the project architecture at a relatively high level. You should break the project into the large chunks that handle the project's major areas of functionality. Depending on your approach, this may include a list of the modules that you need to build or a list of families of classes.
For example, suppose you're building a system to manage the results of ostrich races. You might decide the project needs the following major pieces:
Database (to hold the data)
Classes (for example, Race, Ostrich, Jockey, and Wager classes)
User interfaces (to enter Ostrich and Jockey data, enter race results, calculate odds, produce result reports, and create new races)
External interfaces (to send information and spam to participants and fans via email, text message, voicemail, pager, carrier pigeon, and anything else we can think of)
You should make sure the high-level design covers every aspect of the requirements. It should specify what the pieces do and how they should interact, but it should include as few details as possible about how the pieces do their jobs.
At this point, fans of extreme programming, Scrum, and other incremental development approaches may be rolling their eyes, snorting in derision, and muttering about how they don't need high-level designs.
Let's defer this argument until Chapter 6, “High-Level Design,” which talks about high-level design in greater detail. For now, I'll just claim that every design methodology needs design, even if it doesn't come in the form of a giant written design specification carved into a block of marble.
After your high-level design breaks the project into pieces, you can assign those pieces to groups within the project so they can work on low-level designs. The low-level design includes information about how that piece of the project should work. The design doesn't need to give every last nitpicky detail necessary to implement the project's major pieces, but it should give enough guidance to the developers who will implement those pieces.
For example, the ostrich racing application's database piece would include an initial design for the database. It should sketch out the tables that will hold the race, ostrich, and jockey information using proper first, second, and third normal forms. (You can argue about whether it needs higher levels of normalization.)
At this point you will also discover interactions between the different pieces of the project that may require changes here and there. For example, while working on the ostrich project's external interfaces, you may decide to add a new table to hold email, text messaging, and other information for fans. Or you may find that the printing module will be easier if you add a new stored procedure to the database design.
After you've created the high- and low-level designs, it's time for the programmers to get to work. (Actually, the programmers should have been hard at work gathering requirements, creating the high-level designs, and refining them into low-level designs, but development is the part that many programmers enjoy the most, so that's often where they think the “real” work begins.) The programmers continue refining the low-level designs until they know how to implement those designs in code.
(In fact, in one of my favorite development techniques, you basically just keep refining the design to give more and more detail until it would be easier to just write the code instead. Then you do exactly that.)
As the programmers write the code, they test it to make sure it doesn't contain any bugs.
At this point, any experienced developers should be snickering if not actually laughing out loud. It's a programming axiom that no nontrivial program is completely bug-free. So let me rephrase the previous paragraph.
As the programmers write the code, they test it to find and remove as many bugs as they reasonably can.
Effectively testing your own code is extremely hard. If you just wrote the code, you obviously didn't insert bugs intentionally. If you knew there was a bug in the code, you would have fixed it before you wrote it. That idea often leads programmers to assume their code is correct (I guess they're just naturally optimistic), so they don't always test it as thoroughly as they should.
Even if a particular piece of code is thoroughly tested and contains no (or few) bugs, there's no guarantee that it will work properly with the other parts of the system.
One way to address both of these problems (developers don't test their own code well and the pieces may not work together) is to perform different kinds of tests. First developers test their own code. Then testers who didn't write the code test it. After a piece of code seems to work properly, it is integrated into the rest of the project, and the whole thing is tested to see if the new code broke anything.
Any time a test fails, the programmers dive back into the code to figure out what's going wrong and how to fix it. After any repairs, the code goes back into the queue for retesting.
At this point you may wonder why you need to retest the code. After all, you just fixed it, right?
Unfortunately, fixing a bug often creates a new bug. Sometimes the bug fix is incorrect. Other times it breaks another piece of code that depended on the original buggy behavior. In that case, the known bug hides an unknown bug.
Still other times the programmer might change some correct behavior to a different correct behavior without realizing that some other code depended on the original correct behavior. (Imagine if someone switched the arrangement of your hot- and cold-water faucets. Either arrangement would work just fine, but you may get a nasty surprise the next time you take a shower.)
Anytime you change the code, whether by adding new code or fixing old code, you need to test it to make sure everything works as it should.
Unfortunately, you can never be certain that you've caught every bug. If you run your tests and don't find anything wrong, that doesn't mean there are no bugs; it just means you haven't found them. As programming pioneer Edsger W. Dijkstra said, “Testing shows the presence, not the absence of bugs.” (This issue can become philosophical. If a bug is never detected, is it still a bug?)
The best you can do is test and fix bugs until they occur at an acceptably low rate. If bugs don't bother users too frequently or too severely when they do occur, then you're ready to move on to deployment.
Suppose requirements gathering, high-level design, low-level design, and development works like this: Every time you make a decision, the next task in the sequence includes two more decisions that depend on the first one. For example, when you make a requirements decision, the high-level design includes two decisions that depend on it. (This isn't exactly the way it works, but it's not as ridiculous as you might wish.)
Now suppose you made a mistake during requirements gathering. (The customer said the application had to support 30 users with a 5-second response time, but you heard 5 users with a 30-second response time.)
If you detect the error during the requirements gathering phase, you need to fix only that one error. But how many incorrect decisions could depend on that one mistake if you don't discover the problem until after development is complete?