编程方法论 - 快速指南
编程方法论 - 引言
当开发程序来解决现实生活中的问题,例如库存管理、工资处理、学生入学、考试成绩处理等时,这些程序往往庞大而复杂。分析此类复杂问题、规划软件开发和控制开发过程的方法称为编程方法论。
编程方法论的类型
软件开发者中流行着许多类型的编程方法论:
过程式编程
问题被分解成过程或代码块,每个代码块执行一项任务。所有过程合在一起构成整个程序。它只适用于复杂程度低的较小程序。
示例 - 对于一个执行加法、减法、乘法、除法、平方根和比较的计算器程序,这些操作中的每一个都可以开发成单独的过程。在主程序中,每个过程都将根据用户的选择被调用。
面向对象编程
在这里,解决方案围绕构成问题一部分的实体或对象展开。该解决方案处理如何存储与实体相关的数据,实体如何运行以及它们如何相互交互以提供一个具有凝聚力的解决方案。
示例 - 如果我们必须开发一个工资管理系统,我们将拥有员工、工资结构、休假规则等实体,解决方案必须围绕这些实体构建。
函数式编程
在这里,问题或所需的解决方案被分解成函数单元。每个单元执行自己的任务并且是自给自足的。然后将这些单元缝合在一起以形成完整的解决方案。
示例 - 工资处理可以具有员工数据维护、基本工资计算、总工资计算、休假处理、贷款偿还处理等功能单元。
逻辑编程
在这里,问题被分解成逻辑单元而不是功能单元。示例:在学校管理系统中,用户具有非常明确的角色,例如班主任、科任老师、实验助理、协调员、学术负责人等。因此,软件可以根据用户角色划分为单元。每个用户可以拥有不同的界面、权限等。
软件开发人员可以选择一种或多种这些方法的组合来开发软件。请注意,在讨论的每种方法中,都必须将问题分解成更小的单元。为此,开发人员可以使用以下两种方法中的一种:
- 自顶向下方法
- 自底向上方法
自顶向下或模块化方法
问题被分解成更小的单元,这些单元可以进一步分解成更小的单元。每个单元称为一个模块。每个模块都是一个自给自足的单元,它拥有执行其任务所需的一切。
下图显示了一个示例,说明如何在开发工资处理程序时遵循模块化方法来创建不同的模块。
自底向上方法
在自底向上方法中,系统设计从最低级别的组件开始,然后将这些组件互连以获得更高级别的组件。此过程持续进行,直到生成所有系统组件的层次结构。但是,在现实场景中,一开始很难知道所有最低级别的组件。因此,自底向上方法仅用于非常简单的问题。
让我们看一下计算器程序的组件。
理解问题
典型的软件开发过程遵循以下步骤:
- 需求收集
- 问题定义
- 系统设计
- 实施
- 测试
- 文档
- 培训和支持
- 维护
前两步帮助团队理解问题,这是获得解决方案最重要的第一步。负责收集需求、定义问题和设计系统的人员称为系统分析师。
需求收集
通常,客户或用户无法清楚地定义他们的问题或需求。他们对想要什么只有一个模糊的想法。因此,系统开发人员需要收集客户需求以了解需要解决的问题或需要交付什么。只有首先了解正在开发解决方案的业务领域,才能对问题进行详细的理解。一些有助于理解业务的关键问题包括:
- 正在做什么?
- 它是如何完成的?
- 任务的频率是多少?
- 决策或交易的数量是多少?
- 遇到了什么问题?
一些有助于收集这些信息的技巧包括:
- 访谈
- 问卷调查
- 研究现有系统文档
- 分析业务数据
系统分析师需要创建清晰简洁但全面的需求文档,以便识别SMART(具体、可衡量、已商定、现实且基于时间)需求。未能做到这一点会导致:
- 问题定义不完整
- 程序目标不正确
- 为向客户交付所需成果而进行的返工
- 成本增加
- 交付延迟
由于需要深入的信息,需求收集也被称为详细调查。
问题定义
收集需求并对其进行分析后,必须清楚地陈述问题陈述。问题定义应明确说明需要解决哪些问题。拥有清晰的问题陈述对于:
- 定义项目范围
- 保持团队专注
- 使项目保持正轨
- 验证在项目结束时是否达到了预期的结果
确定解决方案
通常,编码被认为是任何软件开发过程中最关键的部分。但是,编码只是该过程的一部分,如果系统设计正确,实际上可能只需要最少的时间。在设计系统之前,必须为手头的问题确定一个解决方案。
首先要注意的是,在设计系统时,系统分析师最初可能会提出多个解决方案。但是,最终解决方案或产品只能是一个。在需求收集阶段收集到的数据的深入分析可以帮助找到独特的解决方案。正确定义问题对于找到解决方案也至关重要。
面对多个解决方案的问题时,分析师会使用流程图、数据流图、实体关系图等视觉辅助工具来深入了解每个解决方案。
流程图绘制
流程图绘制是通过符号和图表来说明系统中的工作流程和数据流的过程。它是帮助系统分析师确定问题解决方案的重要工具。它直观地描绘了系统的组件。
以下是流程图绘制的优点:
可视化表示有助于理解程序逻辑
它们充当实际程序编码的蓝图
流程图对于程序文档很重要
流程图是程序维护过程中的重要辅助工具
以下是流程图绘制的缺点:
复杂的逻辑无法使用流程图来描述
如果逻辑或数据/工作流发生任何更改,则必须完全重新绘制流程图
数据流图
数据流图或DFD是通过系统或子系统的数据流的图形表示。每个过程都有其自身的数据流,并且存在数据流图的级别。第0级显示整个系统的输入和输出数据。然后将系统分解成模块,第1级DFD分别显示每个模块的数据流。如果需要,可以将模块进一步分解成子模块并绘制第2级DFD。
伪代码
系统设计完成后,将其移交给项目经理进行实施,即编码。程序的实际编码是用编程语言完成的,只有接受过该语言培训的程序员才能理解这种语言。但是,在实际编码发生之前,程序的基本操作原理、工作流程和数据流是用类似于将要使用的编程语言的符号编写的。这种符号称为伪代码。
这是一个C++伪代码的示例。程序员只需要将每个语句转换成C++语法即可获得程序代码。
识别数学运算
所有对计算机的指令最终都作为机器级别的算术和逻辑运算来实现。这些运算很重要,因为它们:
- 占用内存空间
- 需要时间执行
- 决定软件效率
- 影响整体软件性能
系统分析师在确定手头问题的唯一解决方案时,会尝试识别所有主要的数学运算。
应用模块化技术
现实生活中的问题复杂且庞大。如果开发了整体解决方案,则会产生以下问题:
难以编写、测试和实施一个大型程序
交付最终产品后几乎不可能进行修改
程序维护非常困难
一个错误可能会使整个系统停止运行
为了克服这些问题,应将解决方案分解成较小的部分,称为模块。为了便于开发、实施、修改和维护,将一个大型解决方案分解成较小模块的技术称为编程或软件开发的模块化技术。
模块化编程的优点
模块化编程具有以下优点:
由于每个模块都可以并行开发,因此可以加快开发速度
模块可以重复使用
由于每个模块都需要独立测试,因此测试速度更快且更可靠
更容易调试和维护整个程序
模块较小且复杂程度较低,因此易于理解
识别模块
识别软件中的模块是一项令人费解的任务,因为没有一种正确的方法可以做到这一点。以下是一些识别模块的提示:
如果数据是系统中最重要的元素,则创建处理相关数据的模块。
如果系统提供的服务多种多样,则将系统分解成功能模块。
如果其他方法都失败了,则根据您在需求收集阶段对系统的理解,将系统分解成逻辑模块。
在编写代码时,为了方便编程,每个模块都必须再次分解成更小的模块。这可以使用上面分享的三个技巧结合具体的编程规则来实现。例如,对于像 C++ 和 Java 这样的面向对象编程语言,每个类及其数据和方法可以构成一个模块。
分步解决方案
要实现模块,必须分步骤描述每个模块的流程。可以使用算法或伪代码来开发分步解决方案。提供分步解决方案具有以下优点:
任何阅读解决方案的人都能够理解问题和解决方案。
程序员和非程序员都能同样理解。
在编码过程中,只需要将每个语句转换为程序语句。
它可以作为文档的一部分,并有助于程序维护。
标识符名称、所需的操作等微观细节会自动确定。
让我们来看一个例子。
控制结构
正如你在上面的例子中看到的,程序逻辑并不一定顺序执行。在编程语言中,控制结构根据给定的参数决定程序的流程。它们是任何软件中非常重要的元素,必须在任何编码开始之前识别出来。
算法和伪代码帮助分析人员和程序员识别需要控制结构的地方。
控制结构有以下三种类型:
决策控制结构
当要执行的下一步取决于某个条件时,使用决策控制结构。这个条件通常是一个或多个必须评估的布尔表达式。布尔表达式总是计算结果为“真”或“假”。如果条件为“真”,则执行一组语句;如果条件计算结果为“假”,则执行另一组语句。例如,if 语句。
选择控制结构
当程序序列取决于特定问题的答案时,使用选择控制结构。例如,一个程序为用户提供了许多选项。接下来要执行的语句将取决于选择的选项。例如,switch语句、case语句。
重复/循环控制结构
当需要多次重复一组语句时,使用重复控制结构。重复的次数可能在开始之前就知道,也可能取决于表达式的值。例如,for语句、while语句、do while语句等。
正如你在上图中看到的,选择结构和决策结构在流程图中的实现方式类似。选择控制只不过是一系列按顺序执行的决策语句。
以下是一些来自程序的例子,展示这些语句是如何工作的:
编写算法
必须遵循的一组有限步骤来解决任何问题称为算法。算法通常在实际编码之前开发。它使用类似英语的语言编写,即使是非程序员也能轻松理解。
有时算法使用伪代码编写,即类似于将要使用的编程语言的语言。编写用于解决问题的算法具有以下优点:
促进团队成员之间的有效沟通
能够分析手头的问题
作为编码的蓝图
协助调试
成为软件文档的一部分,以便在维护阶段将来参考
以下是良好且正确的算法的特征:
有一组输入
步骤是唯一定义的
有有限数量的步骤
产生所需的输出
算法示例
让我们首先以现实生活中的例子来创建算法。以下是去市场购买钢笔的算法。
此算法中的步骤 4 本身就是一个完整的任务,可以为此编写单独的算法。现在让我们创建一个算法来检查数字是正数还是负数。
流程图元素
流程图是程序逻辑步骤序列的图解表示。流程图使用简单的几何形状来描述过程,并使用箭头来显示关系和过程/数据流。
流程图符号
这是一个图表,其中包含一些绘制流程图中常用的符号。
符号 | 符号名称 | 用途 |
---|---|---|
开始/停止 | 用于算法的开头和结尾,以显示程序的开始和结束。 | |
过程 | 表示诸如数学运算之类的过程。 | |
输入/输出 | 用于表示程序输入和输出。 | |
决策 | 代表程序中的决策语句,答案通常是“是”或“否”。 | |
箭头 | 显示不同形状之间的关系。 | |
页面内连接符 | 连接流程图的两个或多个部分,这些部分位于同一页面上。 | |
页面外连接符 | 连接分布在不同页面上的流程图的两个部分。 |
开发流程图的指导原则
在开发流程图时,需要记住以下几点:
流程图只能有一个开始符号和一个停止符号
页面内连接符用数字引用
页面外连接符用字母引用
过程的总体流程是从上到下或从左到右
箭头不应交叉
流程图示例
以下是去市场购买钢笔的流程图。
以下是计算两个数字平均值的流程图。
使用清晰的指令
众所周知,计算机本身没有智能;它只是遵循用户给出的指令。指令是计算机程序以及软件的构建块。给出清晰的指令对于构建成功的程序至关重要。作为程序员或软件开发人员,你应该养成编写清晰指令的习惯。以下有两种方法可以做到这一点。
表达式的清晰度
程序中的表达式是运算符和操作数的序列,用于进行算术或逻辑计算。以下是一些有效表达式的示例:
- 比较两个值
- 定义变量、对象或类
- 使用一个或多个变量进行算术计算
- 从数据库检索数据
- 更新数据库中的值
编写明确的表达式是每个程序员都必须培养的一项技能。编写此类表达式时,请记住以下几点:
明确的结果
表达式的计算必须给出一个明确的结果。例如,应谨慎使用一元运算符。
避免复杂的表达式
不要试图在一个表达式中完成许多事情。一旦事情开始变得复杂,就将其分解成两个或多个表达式。
指令的简洁性
不仅对于计算机,你还需要编写清晰的指令。稍后阅读程序的任何人(甚至你自己!)都应该能够理解指令试图实现的目标。程序员在一段时间后重新访问自己的程序时无法理解自己的程序的情况非常普遍。这表明此类程序的维护和修改将非常困难。
编写简单的指令有助于避免此问题。以下是一些编写简单指令的技巧:
避免巧妙的指令——如果没有人能够正确理解,巧妙的指令以后可能看起来并不那么巧妙。
每个指令执行一个任务——试图一次做多件事会使指令复杂化。
使用标准——每种语言都有其标准,请遵循它们。记住,你并不是独自一人从事该项目;请遵循项目的编码标准和指南。
正确的编程技术
在本章中,我们将介绍如何编写良好的程序。但在我们这样做之前,让我们看看良好程序的特征:
可移植性——程序或软件应该在所有相同类型的计算机上运行。相同类型是指为个人计算机开发的软件应该在所有 PC 上运行。或者为平板电脑编写的软件应该在所有具有正确规格的平板电脑上运行。
效率——快速完成指定任务的软件被称为高效软件。代码优化和内存优化是提高程序效率的一些方法。
有效性——软件应该有助于解决手头的问题。能够做到这一点的软件被称为有效的软件。
可靠性——程序应该在每次给定相同输入集时都给出相同的输出。
用户友好性——程序界面、可点击的链接和图标等应该用户友好。
自文档化——任何程序或软件,由于使用了明确的名称,其标识符名称、模块名称等都可以描述自身。
以下是一些编写良好程序的方法。
正确的标识符名称
标识任何变量、对象、函数、类或方法的名称称为标识符。使用正确的标识符名称可以使程序自文档化。这意味着对象的名称将说明它做什么或存储什么信息。让我们来看一下这个 SQL 指令的例子
看看第 10 行。它告诉任何阅读程序的人都需要选择学生的 ID、姓名和学号。变量的名称使这一点不言自明。以下是一些创建正确的标识符名称的技巧:
使用语言指南
不要羞于使用长名称来保持清晰
使用大写和小写字母
即使语言允许,也不要给两个标识符赋予相同的名称
即使标识符具有互斥的作用域,也不要给多个标识符赋予相同的名称
注释
在上图中,看看第 8 行。它告诉读者接下来的几行代码将检索需要生成成绩单的学生列表。此行不是代码的一部分,而只是为了使程序更用户友好。
程序中未被编译,而是作为程序员注释或解释的表达式称为注释。请看以下程序段中的注释。注释以 // 开头。
注释可以插入到:
程序的序言部分,解释其目的
逻辑或功能块的开头和/或结尾
记录特殊情况或异常
应避免添加多余的注释,因为这可能会适得其反,在阅读代码时打断代码流程。编译器可能会忽略注释和缩进,但读者往往会阅读每一个注释。
缩进
文本距离左右边距的距离称为缩进。在程序中,缩进用于分隔逻辑上分开的代码块。这是一个缩进程序段的示例
如您所见,缩进的程序更容易理解。从for循环到if以及返回for的控制流程非常清晰。缩进在控制结构中尤其有用。
插入空格或空行也是缩进的一部分。以下是一些您可以也应该使用缩进的情况:
程序中逻辑或功能代码块之间的空行
运算符周围的空格
新控制结构开头的制表符
编程方法 - 调试
识别并从程序或软件中删除错误的过程称为调试。调试理想情况下是测试过程的一部分,但在实际中,它在编程的每个步骤中都会进行。程序员应该在继续之前调试他们最小的模块。这减少了在测试阶段出现的错误数量,并显著减少了测试时间和工作量。让我们来看一下程序中可能出现的错误类型。
语法错误
语法错误是程序中的语法错误。每种语言都有自己的一套规则,例如创建标识符、编写表达式等,用于编写程序。当违反这些规则时,这些错误被称为语法错误。许多现代集成开发环境可以在您键入程序时识别语法错误。否则,将在您编译程序时显示。
在这个程序中,变量 prod 没有声明,编译器会抛出此错误。
语义错误
语义错误也称为逻辑错误。语句没有语法错误,因此它将被正确编译和运行。但是,它不会给出预期的输出,因为逻辑不正确。让我们来看一个例子。
看第 13 行。在这里,程序员想要检查除数是否为 0,以避免被 0 除。但是,使用了赋值运算符 =,而不是比较运算符 ==。现在,每次“if 表达式”都将计算为 true,程序将输出“您不能除以 0”。肯定不是预期的结果!!
逻辑错误无法被任何程序检测到;当未达到预期输出时,程序员必须自己识别它们。
运行时错误
运行时错误是在执行程序时发生的错误。这意味着程序没有语法错误。程序可能会遇到的一些最常见的运行时错误包括:
- 无限循环
- 被 '0' 除
- 用户输入错误的值(例如,输入字符串而不是整数)
代码优化
任何修改代码以提高其质量和效率的方法都称为代码优化。代码质量决定了代码的寿命。如果代码可以长期使用和维护,从一个产品延续到另一个产品,则其质量被认为是高的,并且具有更长的寿命。相反,如果一段代码只能短期使用和维护,例如直到某个版本有效,则其质量被认为是低的,并且寿命较短。
代码的可靠性和速度决定了代码效率。代码效率是确保软件高性能的重要因素。
代码优化有两种方法:
基于直觉的优化 (IBO) - 程序员尝试根据自身的技能和经验来优化程序。这可能适用于小型程序,但随着程序复杂性的增加,它会惨败。
基于证据的优化 (EBO) - 使用自动化工具找出性能瓶颈,然后相应地优化相关部分。每种编程语言都有自己的一套代码优化工具。例如,PMD、FindBug 和 Clover 用于优化 Java 代码。
代码针对执行时间和内存消耗进行了优化,因为时间是稀缺的,而内存是昂贵的。两者之间必须取得平衡。如果时间优化增加了内存负载,或者内存优化使代码变慢,则优化的目的将丢失。
执行时间优化
优化代码的执行时间对于向用户提供快速服务是必要的。以下是一些执行时间优化的技巧:
使用具有内置执行时间优化的命令
使用 switch 代替 if 条件
最大限度地减少循环结构中的函数调用
优化程序中使用的数据结构
内存优化
如您所知,数据和指令会消耗内存。当我们说数据时,它也指表达式结果的中间数据。我们还需要跟踪有多少指令构成程序或我们尝试优化的模块。以下是一些内存优化技巧:
使用具有内置内存优化的命令
最大限度地减少需要存储在寄存器中的变量的使用
避免在多次执行的循环内声明全局变量
避免使用 CPU 密集型函数,例如 sqrt()
程序文档
任何书面文本、插图或视频,用于向用户描述软件或程序,都称为程序或软件文档。用户可以是任何人,从程序员、系统分析师和管理员到最终用户。在不同的开发阶段,可能会为不同的用户创建多个文档。事实上,软件文档是整个软件开发过程中一个关键的流程。
在模块化编程中,文档变得更加重要,因为软件的不同模块由不同的团队开发。如果开发团队以外的任何人想要或需要理解某个模块,良好且详细的文档将使任务更容易。
以下是一些创建文档的指导原则:
文档应该从读者的角度出发
文档应该明确无误
不应该有重复
应该使用行业标准
文档应该始终保持更新
任何过时的文档都应在记录淘汰后逐步淘汰
文档的优点
以下是提供程序文档的一些优点:
跟踪软件或程序的所有部分
更容易维护
开发人员以外的程序员可以理解软件的所有方面
提高软件的整体质量
协助用户培训
确保知识分散,如果人员突然离开系统,可以降低成本和工作量
文档示例
软件可以有许多类型的文档与之相关联。一些重要的文档包括:
用户手册 - 它描述了最终用户使用软件的不同功能的说明和步骤。
操作手册 - 它列出并描述了所有正在执行的操作及其相互依赖关系。
设计文档 - 它概述了软件并详细描述了设计元素。它记录了诸如数据流图、实体关系图等细节。
需求文档 - 它列出了系统的所有需求,以及对需求可行性的分析。它可以包含用例、现实场景等。
技术文档 - 它是实际编程组件(如算法、流程图、程序代码、功能模块等)的文档。
测试文档 - 它记录测试计划、测试用例、验证计划、验证计划、测试结果等。测试是软件开发中需要大量文档的一个阶段。
已知错误列表 - 每个软件都有无法删除的错误或错误,因为它们要么发现得太晚,要么是无害的,要么纠正它们需要比必要的工作量和时间更多。这些错误与程序文档一起列出,以便以后可以删除它们。它们还可以帮助用户、实施人员和维护人员激活错误。
程序维护
程序维护是在交付后修改软件或程序的过程,以实现以下任何结果:
- 纠正错误
- 提高性能
- 添加功能
- 删除过时的部分
尽管普遍认为维护是用来修复软件上线后出现的错误,但实际上,大部分维护工作都涉及向现有模块添加次要或主要功能。例如,向报告中添加一些新数据,向输入表单中添加新字段,修改代码以合并更改的政府法规等。
维护类型
维护活动可以分为四个类别:
纠正性维护 - 在现场实施后出现的错误在这里得到修复。错误可能是由用户自己指出的。
预防性维护 - 为避免将来出现错误而进行的修改称为预防性维护。
适应性维护 - 工作环境的变化有时需要对软件进行修改。这称为适应性维护。例如,如果政府教育政策发生变化,则必须对学校管理软件的学生成绩处理模块进行相应的更改。
完善性维护 - 对现有软件进行更改以合并来自客户的新要求称为完善性维护。目标是始终使用最新的技术。
维护工具
软件开发人员和程序员使用许多工具来协助他们进行软件维护。以下是一些最广泛使用的工具:
程序切片器 - 选择程序中将受更改影响的部分
数据流分析器 - 跟踪软件中所有可能的数据流
动态分析器 - 追踪程序执行路径
静态分析器 - 允许对程序进行一般查看和总结
依赖性分析器 - 协助理解和分析程序不同部分的相互依赖性