您还在调试吗?
調(diào)試是“以交互方式運(yùn)行程序/方法,在每個(gè)語(yǔ)句后中斷執(zhí)行流程并顯示……的過(guò)程。”簡(jiǎn)而言之,它是一種非常有用的技術(shù)……對(duì)于一個(gè)糟糕的程序員而言。 或仍然在用C編寫過(guò)程代碼的老程序員。面向?qū)ο蟮某绦騿T從不調(diào)試其代碼-他們編寫單元測(cè)試。 我的意思是,單元測(cè)試是一種完全替代調(diào)試的技術(shù)。 如果需要調(diào)試,則設(shè)計(jì)很糟糕 。
The Revenant(2015),作者:Alejandro G.I?árritu
假設(shè)我是一個(gè)糟糕的命令式程序程序員,這是我的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;} }此靜態(tài)實(shí)用程序方法讀取文件內(nèi)容,然后在其中找到所有唯一的單詞。 很簡(jiǎn)單 但是,如果它不起作用,我們?cè)撛趺崔k? 假設(shè)這是文件:
We know what we are, but know not what we may be.從中,我們得到以下單詞列表:
"We" "know" "what" "we" "are,\n" "but" "not" "may" "be\n"現(xiàn)在,這對(duì)我而言似乎不正確……那么下一步是什么? 文件讀取無(wú)法正常工作或拆分中斷。 讓我們調(diào)試吧? 讓我們通過(guò)輸入為它提供文件,并逐步進(jìn)行操作,跟蹤并觀察變量。 我們將找到該錯(cuò)誤并進(jìn)行修復(fù)。 但是,當(dāng)出現(xiàn)類似問(wèn)題時(shí),我們將不得不再次調(diào)試! 這就是單元測(cè)試應(yīng)該避免的 。
我們應(yīng)該一次創(chuàng)建一個(gè)單元測(cè)試,以重現(xiàn)該問(wèn)題。 然后,我們解決問(wèn)題并確保測(cè)試通過(guò)。 這就是我們節(jié)省解決問(wèn)題投資的方式。 我們不會(huì)再修復(fù)它,因?yàn)樗粫?huì)再發(fā)生。 我們的測(cè)試將阻止它的發(fā)生。
如果您認(rèn)為調(diào)試變得更快,更輕松,請(qǐng)考慮一下代碼的質(zhì)量
但是,只有在創(chuàng)建單元測(cè)試很容易的情況下,所有這些方法才有效。 如果困難的話,我會(huì)懶得做。 我將調(diào)試并解決問(wèn)題。 在此特定示例中,創(chuàng)建測(cè)試是相當(dāng)昂貴的過(guò)程。 我的意思是單元測(cè)試的復(fù)雜度會(huì)很高。 我們必須創(chuàng)建一個(gè)臨時(shí)文件,用數(shù)據(jù)填充它,運(yùn)行該方法,然后檢查結(jié)果。 為了弄清楚到底發(fā)生了什么,以及漏洞在哪里,我必須創(chuàng)建一些測(cè)試。 為了避免代碼重復(fù),我還必須創(chuàng)建一些補(bǔ)充實(shí)用程序來(lái)幫助我創(chuàng)建該臨時(shí)文件并用數(shù)據(jù)填充它。 這是很多工作。 好吧,也許不是“很多”,而是經(jīng)過(guò)了數(shù)分鐘的調(diào)試。
因此,如果您認(rèn)為調(diào)試更快,更輕松,請(qǐng)考慮一下代碼的質(zhì)量。 我敢打賭,它有很多重構(gòu)的機(jī)會(huì),就像上面示例中的代碼一樣。 這是我將如何修改它。 首先,我將其轉(zhuǎn)換為一個(gè)類,因?yàn)閷?shí)用程序靜態(tài)方法是一種不好的做法 :
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();} }看起來(lái)已經(jīng)更好了,但是復(fù)雜性仍然存在。 接下來(lái),我將其分解為較小的類:
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();} }您現(xiàn)在怎么看? 為Words類編寫測(cè)試是一項(xiàng)非常簡(jiǎn)單的任務(wù):
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"));} }那花了多少時(shí)間? 少于一分鐘。 我們不需要?jiǎng)?chuàng)建一個(gè)臨時(shí)文件并向其中加載數(shù)據(jù),因?yàn)閃ords類對(duì)文件沒(méi)有任何作用。 它只是解析輸入的字符串并在其中找到唯一的單詞。 現(xiàn)在,由于測(cè)試很小,我們可以輕松創(chuàng)建更多測(cè)試,因此很容易修復(fù)。 例如:
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"));} }我的觀點(diǎn)是,當(dāng)編寫單元測(cè)試的時(shí)間遠(yuǎn)遠(yuǎn)大于單擊那些“ Trace-In / Trace-Out”按鈕所花費(fèi)的時(shí)間時(shí),必須進(jìn)行調(diào)試。 這是合乎邏輯的。 我們都很懶惰,想要快速簡(jiǎn)便的解決方案。 但是調(diào)試會(huì)浪費(fèi)時(shí)間并浪費(fèi)能量。 它可以幫助我們發(fā)現(xiàn)問(wèn)題,但并不能阻止它們?cè)俅纬霈F(xiàn)。
當(dāng)我們的代碼是需要調(diào)試的程序和算法,當(dāng)代碼是所有的目標(biāo)應(yīng)該如何實(shí)現(xiàn)的,而不是我們的目標(biāo)是什么 。 再次參見上面的示例。 第一個(gè)靜態(tài)方法是關(guān)于我們?nèi)绾巫x取文件,解析文件以及查找單詞的所有方法。 它甚至被命名為readWords() (一個(gè)動(dòng)詞 )。 相反,第二個(gè)例子是關(guān)于將要實(shí)現(xiàn)的。 它可以是文件的Text ,也可以是Text的Words (都是名詞 )。
我相信在干凈的面向?qū)ο缶幊讨袥](méi)有調(diào)試的地方。 只有單元測(cè)試!
翻譯自: https://www.javacodegeeks.com/2016/11/are-you-still-debugging.html
總結(jié)
- 上一篇: iPhone 15系列官宣搭载A17 P
- 下一篇: iPhone 15系列四款机型配置区别