您还在调试吗?

调试是“以交互方式运行程序/方法,在每个语句后中断执行流程并显示……的过程。”简而言之,它是一种非常有用的技术……对于一个糟糕的程序员而言。 或仍然在用C编写过程代码的老程序员。面向对象的程序员从不调试其代码-他们编写单元测试。 我的意思是,单元测试是一种完全替代调试的技术。 如果需要调试,则设计很糟糕

%ce%b1%cf%81%cf%87%ce%b5%ce%af%ce%bf-%ce%bb%ce%ae%cf%88%ce%b7%cf%82

The Revenant(2015),作者:Alejandro G.Iñárritu

假设我是一个糟糕的命令式程序程序员,这是我的Java代码:

class FileUtils {public static Iterable<String> readWords(File f) {String text = new String(Files.readAllBytes(Paths.get(f)),"UTF-8");Set<String> words = new HashSet<>();for (String word : text.split(" ")) {words.add(word);}return words;}
}

此静态实用程序方法读取文件内容,然后在其中找到所有唯一的单词。 很简单 但是,如果它不起作用,我们该怎么办? 假设这是文件:

We know what we are,
but know not what we may be.

从中,我们得到以下单词列表:

"We"
"know"
"what"
"we"
"are,\n"
"but"
"not"
"may"
"be\n"

现在,这对我而言似乎不正确……那么下一步是什么? 文件读取无法正常工作或拆分中断。 让我们调试吧? 让我们通过输入为它提供文件,并逐步进行操作,跟踪并观察变量。 我们将找到该错误并进行修复。 但是,当出现类似问题时,我们将不得不再次调试! 这就是单元测试应该避免的

我们应该一次创建一个单元测试,以重现该问题。 然后,我们解决问题并确保测试通过。 这就是我们节省解决问题投资的方式。 我们不会再修复它,因为它不会再发生。 我们的测试将阻止它的发生。

如果您认为调试变得更快,更轻松,请考虑一下代码的质量

但是,只有在创建单元测试很容易的情况下,所有这些方法才有效。 如果困难的话,我会懒得做。 我将调试并解决问题。 在此特定示例中,创建测试是相当昂贵的过程。 我的意思是单元测试的复杂度会很高。 我们必须创建一个临时文件,用数据填充它,运行该方法,然后检查结果。 为了弄清楚到底发生了什么,以及漏洞在哪里,我必须创建一些测试。 为了避免代码重复,我还必须创建一些补充实用程序来帮助我创建该临时文件并用数据填充它。 这是很多工作。 好吧,也许不是“很多”,而是经过了数分钟的调试。

因此,如果您认为调试更快,更轻松,请考虑一下代码的质量。 我敢打赌,它有很多重构的机会,就像上面示例中的代码一样。 这是我将如何修改它。 首先,我将其转换为一个类,因为实用程序静态方法是一种不好的做法 :

class Words implements Iterable<String> {private final File file;Words(File src) {this.file = src;}@Overridepublic Iterator<String> iterator() {String text = new String(Files.readAllBytes(Paths.get(this.file)),"UTF-8");Set<String> words = new HashSet<>();for (String word : text.split(" ")) {words.add(word);}return words.iterator();}
}

看起来已经更好了,但是复杂性仍然存在。 接下来,我将其分解为较小的类:

class Text {private final File file;Text(File src) {this.file = src;}@Overridepublic String toString() {return new String(Files.readAllBytes(Paths.get(this.file)),"UTF-8");}
}
class Words implements Iterable<String> {private final String text;Words(String txt) {this.text = txt;}@Overridepublic Iterator<String> iterator() {Set<String> words = new HashSet<>();for (String word : this.text.split(" ")) {words.add(word);}return words.iterator();}
}

您现在怎么看? 为Words类编写测试是一项非常简单的任务:

import org.junit.Test;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
public class WordsTest {@Testpublic void parsesSimpleText() {assertThat(new Words("How are you?"),hasItems("How", "are", "you"));}
}

那花了多少时间? 少于一分钟。 我们不需要创建一个临时文件并向其中加载数据,因为Words类对文件没有任何作用。 它只是解析输入的字符串并在其中找到唯一的单词。 现在,由于测试很小,我们可以轻松创建更多测试,因此很容易修复。 例如:

import org.junit.Test;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
public class WordsTest {@Testpublic void parsesSimpleText() {assertThat(new Words("How are you?"),hasItems("How", "are", "you"));}@Testpublic void parsesMultipleLines() {assertThat(new Words("first line\nsecond line\n"),hasItems("first", "second", "line"));}
}

我的观点是,当编写单元测试的时间远远大于单击那些“ Trace-In / Trace-Out”按钮所花费的时间时,必须进行调试。 这是合乎逻辑的。 我们都很懒惰,想要快速简便的解决方案。 但是调试会浪费时间并浪费能量。 它可以帮助我们发现问题,但并不能阻止它们再次出现。

当我们的代码是需要调试的程序和算法,当代码是所有的目标应该如何实现的,而不是我们的目标是什么 。 再次参见上面的示例。 第一个静态方法是关于我们如何读取文件,解析文件以及查找单词的所有方法。 它甚至被命名为readWords() (一个动词 )。 相反,第二个例子是关于将要实现的。 它可以是文件的Text ,也可以是TextWords (都是名词 )。

我相信在干净的面向对象编程中没有调试的地方。 只有单元测试!

翻译自: https://www.javacodegeeks.com/2016/11/are-you-still-debugging.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351939.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RESTful规范

本文目录 什么是RESTful RESTful API设计 基于Django实现 什么是RESTful REST与技术无关&#xff0c;代表的是一种软件架构风格&#xff0c;REST是Representational State Transfer的简称&#xff0c;中文翻译为“表征状态转移”REST从资源的角度类审视整个网络&#xff0c;它…

反向输出dna序列_蛋白质序列反向(逆向)翻译成DNA序列-在线工具

请粘贴蛋白质序列&#xff0c;如果需要输入多个序列&#xff0c;请以fasta格式输入&#xff0c;输入总长度不超过2万个字符。>testACDEFGHIKLMNPQRSTVWY*推荐使用IE 8.0以上、chrome或者Firefox等浏览器。请输入该蛋白来源物种的密码子使用表(GCG格式)&#xff0c;下表示大肠…

子函数的指针释放问题

C语言中遇到一个这样的问题&#xff1a;子函数中malloc了一个指针存储数据&#xff0c;作为该子函数的返回值&#xff0c;return到主函数。那么这个指针应该在哪里释放呢&#xff1f;显然不能在子函数里释放&#xff0c;否则返回值没有意义。这样就应该在主函数里释放&#xff…

利用cookie模拟登陆知乎

我们知道一些网站是需要账号密码才可以登陆的&#xff0c;例如知乎。而利用requests库里的get方法的headers参数可以达到这个目的 首先在知乎的网页上登陆自己的知乎账号&#xff0c;利用chrome的开发者工具&#xff08;F12&#xff09;可以捕获我们的get方法向浏览器提供的coo…

linux中fork()函数详解(原创!!实例讲解)

一、fork入门知识 一个进程&#xff0c;包括代码、数据和分配给进程的资源。fork&#xff08;&#xff09;函数通过系统调用创建一个与原来进程几乎完全相同的进程&#xff0c;也就是两个进程可以做完全相同的事&#xff0c;但如果初始参数或者传入的变量不同&#xff0c;两个进…

C++ vector的释放

项目上用到vector容器&#xff0c;没有手动释放&#xff0c;总是会在这里出现内存分配不成功的问题&#xff0c;因此对vector的释放了解了一下。初始代码如下&#xff1a; vector <float*> dets(nTotalLayers); //dets : 记录每层图像的 Hessian 行列式&#xff1b; for …

设计模式 工厂方法_使用工厂方法模式设计最佳实践

设计模式 工厂方法在前面的“设计模式”示例中&#xff0c;我们解释了当今常用的“工厂”模式。 在本节中&#xff0c;我们将了解具有更多抽象的更高级的解决方案。 该模式称为工厂方法设计模式。 定义&#xff1a; Factory方法模式提供了一种用于创建对象的方法&#xff0c;…

C Programming Language

代做module作业、代做C/C编程设计作业、代写Programming Language作业、代做C/C课程设计作业C Programming LanguageContribution to module (weighting: 20 %)1st Semester 2018-2019Out: WED. 5th Dec. 2018 Due: 18:00[GMT], WED. 19th Dec. 2018Main objective of the assi…

python修改列表中字典内的值_python修改字典内key对应值的方法

python学习笔记&#xff1a;字典python版本&#xff1a;Python 2.6.6系统环境&#xff1a;CentOS release 6.2 x86_64本文参考了互联网上前辈的一些文章一、字典是python中最灵活的内置数据结构类型&#xff0c;如果把列表看作是有序的对象集合&#xff0c;那么字典就是无序的集…

MATLAB使用技巧

1、ctrl c 或者 ctrl break 强行中断程序运行 2、变量X 右键save as为DX后&#xff0c;再次使用时load有区别&#xff1a;load(DX.mat) 得到的是X这个变量&#xff0c;直接出现在workspace里&#xff1b;Xnew load(DX.mat)得到的是一个名称为Xnew的结构体&#xff0c;里面包含…

Beta 冲刺 (2/7)

团队信息 队名&#xff1a;爸爸饿了组长博客&#xff1a;here作业博客&#xff1a;here组员情况 组员1&#xff08;组长&#xff09;&#xff1a;王彬 过去两天完成了哪些任务 完成考试确定历史记录页面与排行榜页面的前端页面风格接下来的计划 & 还剩下哪些任务 各个食堂平…

您真的需要instanceof吗?

使用instanceof是一种代码味道。 我认为我们可能对此表示同意。 每当我看到这样的构造时&#xff0c;我肯定会出现问题。 也许有人只是在进行更改时没有注意到问题&#xff1f; 也许有一个主意&#xff0c;但是它太复杂了&#xff0c;以至于需要太多的精力或时间才能让开发人员…

python 累积正态分布函数_Python编程基础—Python语句书写规范

Python语句中没有专门的“结束符”。Python解释器不是根据"结束符"来判断语句是否结束,而是根据语法的完整性来判断。一、Python语句编写规则①通常是一行一句x1 1 x2 2 x3 3 print(x1,x2,x3)②也可以一行多句&#xff0c;用语句分隔符“;”对两个语句进行标识x1 …

MATLAB批量改变图片大小

%2018年6月28日11:07:15 %把一个目录下的图片缩放到指定大小 clc clear ratio 0.2;%缩放比例 cd(F:\数据集\crumpled clothes\cloth3\original image\);%不加这句话找不到图片 dpath F:\数据集\crumpled clothes\cloth3\original image\*.JPG;%找到路径下所有格式为.JPG的文件…

基于Libevent的HTTP Server

简单的Http Server 使用Libevent内置的http相关接口&#xff0c;可以很容易的构建一个Http Server&#xff0c;一个简单的Http Server如下&#xff1a; #include <event2/event.h> #include <event2/buffer.h> #include <event2/http.h> #include <Winso…

python写入数据的一种措施_Python 文件数据读写的具体实现

文件数据读写读写文件&#xff0c;本质上是请求操作系统打开一个文件对象&#xff0c;然后&#xff0c;通过操作系统提供的接口从这个文件对象中读取数据(读文件)&#xff0c;或者把数据写入这个文件对象(写文件)。文件读取使用 Python 内置 open() 函数&#xff0c;以 rt 的模…

MATLAB的dir函数

1、作用获得指定文件夹下的所有子文件夹和文件,并存放在在一种文件结构体数组中. 2.使用方法dir(.)列出当前目录下所有子文件夹和文件dir(G:\Matlab)列出指定目录下所有子文件夹和文件dir(G:\Matlab\*.jpg)列出当前目录下符合正则表达式的文件夹和文件3.例如&#xff1a;列出文…

libevent简介和使用

libevent是一个基于事件触发的网络库&#xff0c;memcached底层也是使用libevent库&#xff0c;今天学习下。总体来说&#xff0c;libevent有下面一些特点和优势&#xff1a;* 统一数据源&#xff0c; 统一I/O事件&#xff0c;信号和定时器这三种事件&#xff1b;* 可移植&…

qr码生成_从Java程序生成QR码图像

qr码生成如果您精通技术和小工具&#xff0c;则必须了解QR码。 这些天&#xff0c;到处都可以找到它-在博客&#xff0c;网站&#xff0c;甚至在某些公共场所。 这在移动应用程序中非常流行&#xff0c;在移动应用程序中&#xff0c;您可以使用QR Code扫描仪应用程序扫描QR Cod…

jracdrive变频器说明书580_jracdrive变频器err02

A&#xff1a;高性能密封型变频器-防粉尘、防水、防油污、防腐蚀此款高性能变频器&#xff0c;因为其具有防粉尘、防水、防油污、防腐蚀性能&#xff0c;适用于化工厂、印染厂、化纤厂、纺织厂、输送带、机床、水泥厂、制*厂、食品厂等环境恶劣的场合。变频器硬件特点&#xff…