欢迎来到防御性设计!
在本章中,我们将探讨程序员如何确保软件具有健壮性 (Robust)。一个健壮的程序即使在使用者出错或发生意外情况时,也不会崩溃或出现异常行为。你可以把它想象成是为你的代码穿上“防弹衣”!
我们将学习如何防止使用者破坏我们的程序,以及如何编写易于阅读的代码。如果刚开始觉得有点技术性,别担心——这其实只是关于如何更有条理地准备工作!
1. 什么是防御性设计?
想象你在设计一辆汽车。你不能假设驾驶员是一个完美的专业人士,所以你会安装安全带、安全气囊,并在车门未关好时提供警示灯。防御性设计 (Defensive Design) 的概念也是一样,只是它是针对计算机程序。它是一种预先考虑并防止问题发生的实践。
预期错误使用 (Anticipating Misuse)
程序员必须预期错误使用。这意味着要思考:“使用者在使用我的程序时,可能会做出什么最愚蠢或最危险的事情?”
使用者可能会:
- 当程序要求输入数字时,却输入了文字。
- 将必填栏位留空。
- 尝试猜想密码 1,000 次(这被称为暴力破解攻击 (Brute-force attack))。
- 尝试输入系统无法处理的超长数据。
重点复习:防御性设计旨在使程序保持健壮性,从而确保它能在不崩溃的情况下处理错误。
2. 输入验证 (Input Validation)
输入验证是一种防御性设计技术,程序会在处理数据之前,检查使用者输入的数据是否符合特定规则。如果数据“无效”(错误),程序应拒绝接收并要求使用者重新输入。
常见的验证检查:
- 类型检查 (Type Check):输入的数据类型是否正确?(例如:是数字而不是文字吗?)
- 范围检查 (Range Check):数字是否在特定限制内?(例如:年龄必须介于 0 到 120 之间)。
- 存在性检查 (Presence Check):使用者是否有输入数据,还是留空了?
- 格式检查 (Format Check):格式是否正确?(例如:邮政编码是否由正确的字母和数字组合而成?)
- 长度检查 (Length Check):输入是否太短或太长?(例如:密码必须至少 8 个字符)。
类比:想象给幼儿玩的“形状分类玩具”。如果你试图将方形积木放入圆形孔洞中,它是放不进去的。这就是物理上的验证!
关键总结:验证检查的是规则,而不是真实性。如果程序询问你的生日,而你输入了一个符合格式但虚假的日期,程序仍然会接受。它只是确保数据是合情合理的。
3. 身份验证 (Authentication)
身份验证是用来确认使用者身份的过程。这关乎确保使用者确实是他们所声称的那个人。
最常见的方式是使用用户名和密码。
- 步骤 1:使用者输入他们的凭据。
- 步骤 2:程序将其与存储的数据库进行比对。
- 步骤 3:如果符合,则授予访问权限;如果不符合,则拒绝访问。
专业提示:为了让身份验证更具“防御性”,程序员可能会限制失败的登录尝试次数,以防止黑客猜想密码。
4. 可维护性 (Maintainability)
一个“健壮”的程序不只是不会崩溃,它还必须让其他程序员能够在未来理解并进行修正。这被称为可维护性。如果你写出杂乱的代码,找出并修复程序错误(Bug)将会非常困难!
为了保持代码的可维护性,我们可以使用这四个技巧(记忆口诀:S.I.N.C.):
1. 子程序 (Sub-programs)
不要写成一片巨大的“代码墙”,而应该将其分解成更小、易于管理的部分,称为子程序 (Functions and Procedures)。
类比:与其写一份超长的五道菜菜谱,不如为前菜、主菜和甜点分别写一份菜单。
2. 缩进 (Indentation)
这意味着当代码位于循环或“if 条件式”内时,需要向右缩进。这能让代码的结构一目了然。
示例:在 Python 中,如果你不缩进,程序甚至无法运行!
3. 命名规范 (Naming Conventions)
为变量和子程序使用描述性名称。
- 坏习惯:x = 50
- 好习惯:user_score = 50
描述性名称能准确地告诉阅读代码的人这些数据的用途。
4. 注释 (Commenting)
程序员会在代码中加入注释(以 # 或 // 等符号开头),计算机会忽略这些注释。这些是为了让人类阅读者理解代码特定部分的作用。
示例:# 此函数用于计算包含税项后的总价
重点复习箱:
- 子程序:将代码分块。
- 缩进:标示代码块的开始与结束。
- 命名:使用清晰、合理的变量名称。
- 注释:向其他人解释逻辑。
常见错误需避免
- 混淆验证 (Validation) 与核对 (Verification):验证检查的是数据是否被允许(例如:这是一个数字吗?);核对检查的是数据是否正确(例如:两次输入密码以确保没有打错)。
- 认为“健壮”意味着“快速”:一个健壮的程序执行速度可能会稍慢一点,因为它需要处理所有额外的检查,但它安全性更高!
- 忘记写注释:你可能会认为自己记得为什么写这行代码,但三个月后,如果没有注释,你(或你的队友)将会感到非常困惑!
总结:防御性设计的目的是通过验证和身份验证来保护程序免受使用者的错误影响,并通可维护性来保护代码,避免未来产生混乱。