国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【譯】怎樣避免開發時的深坑

KitorinZero / 2852人閱讀

摘要:但是,在實際開發時仍然障礙重重。我就曾經接受了一個開發任務,就是做一個像劊子手一樣的游戲,但是當我看完需求中所有的規則時,才意識到要做的應該是邪惡的劊子手這是一個深坑。邊界問題僅在極端最大或最小值參數的情況下發生的問題或狀況。

翻譯:瘋狂的技術宅
作者:Valinda Chan
英文標題:10 Steps to Solving a Programming Problem
英文鏈接:https://codeburst.io/10-steps...
本文首發微信公眾號:充實的腦洞

我總是聽到剛入行不久的程序員這樣說:知道自己要實現什么功能,同時處理邏輯和基本語法也都明白,但是就不知道該怎么寫代碼。如果把別人的的代碼給你看,或者有人給你你一些指導,或許你能明白其中的思路。但是,在實際開發時仍然障礙重重。即使語法或邏輯都明白,也很難自己的想法轉化為代碼。在本文中我將會告訴大家我自己是怎么做的,還有一些解決典型問題的方法,希望能夠對大家有所幫助。

1. 把給你的需求反復閱讀三遍以上(或者直到看吐了為止)

如果不能理解給你的需求,也就沒有辦法實現它。 實際的需求和你認為的需求有很大的區別。假設有一個需求,當你閱讀前幾行時非常容易,但是接下來你就會假設其余部分與你曾經看到過的東西類似。比如你要做一個像“劊子手”一樣的游戲,一定要通讀它所有的規則,即便你曾經玩過這個游戲。我就曾經接受了一個開發任務,就是做一個像“劊子手”一樣的游戲,但是當我看完需求中所有的規則時,才意識到要做的應該是“邪惡的劊子手”(這是一個深坑!)。

有時我會試著向一個朋友解釋某個需求,看她對我解釋的理解是否和我的需求一致。如果你不想在開發了一半的時候才發現自己誤解了這個需求,那么在開始的時候多花點時間是值得的。你對問題越了解,就越容易解決它。

假設我們要創建一個簡單的函數selectEvenNumbers,這個函數的參數一個存放整數的數組,返回值evenNumbers 是一個只存在偶數的數組。如果沒有偶數,那么久返回一個空數組。

function selectEvenNumbers() {
  // your code here
}

以下是我思考的問題:

計算機怎樣去判斷是不是偶數? 檢查該數是否能被2整除

我傳給這個函數的參數是什么? 一個數組

數組中保存的內容是什么? 一個或多個整數

數組中元素的數據類型是什么? 整數

這個函數的目的是什么?之行結束后要返回什么? 目標是得到所有偶數,并把它們保存到數組中返回。如果沒有偶數,就返回一個空數組。

2.至少使用三組模擬數據進行手動模擬

找一張草稿紙,人工解決這個問題。至少考慮三組模擬數據,注意要考慮到極端情況和邊界問題。

極端情況:在正常操作參數范圍之外產生的問題或情況。或者是多個變量或條件都在其指定范圍內,但是都同時處于極端的水平的情況。
邊界問題:僅在極端(最大或最小值)參數的情況下發生的問題或狀況。

舉個例子,下面是一些要使用的樣本數據集:

[1]
[1, 2]
[1, 2, 3, 4, 5, 6]
[-200.25]
[-800.1, 2000, 3.1, -1000.25, 42, 600]

在剛開始的時候,很容易忽略這些步驟。

因為你的大腦對于偶數的概念十分清楚,所以只要看到一組數據,就可以從中找到2,4,6這樣的數字,幾乎意識不到自己的大腦是怎么思考的。可以嘗試更多的數據,它會改變你大腦通過觀察來解決問題的習慣。這有利于幫你實現真正有效的算法。

我們來看第一個數組:[1]

查看數組 [1] 中唯一的元素

判斷是否為偶數:嗯,并不是

確定這個數組中沒有其他的元素了

確定在這個數組中沒有偶數

返回一個空數組

接下來看第二個數組:[1, 2]

先看數組[1, 2]中的第一個元素

數字是1

判斷是否為偶數:不是

看數組中的下一個元素

數字是2

判斷是否為偶數:是的

創建一個數組evenNumbers ,并把數字2添加到其中

確定數組中沒有其他元素了

返回的數組evennumbers[ 2 ]

再多看幾遍。請注意處理[1]的步驟和[ 1, 2 ]略有不同。這就是為什么我要嘗試多種不同的組合。在這些數據中,有的只存在一個元素;有些是浮點數,而不是整數;有些是一個元素中有多個數字,有些是負數。

3.簡化并優化你的步驟

尋找模式,找到概括問題的方法,看看能不能減少無用或重復的步驟。

創建一個函數selectEvenNumbers

創建一個保存數據的空數組evenNumbers

檢查數組[1, 2]中的每個元素

找到第一個元素

判斷它是否可以被2整除。如果是,就加到evennumbers

找到下一個元素

重復步驟4

重復步驟5和步驟4,一直到數組中沒有任何其他元素

返回數組evenNumbers ,不管它是不是空數組

這個方法可能會讓你想起數學歸納法:

證明當 n = 1, n = 2, ... 的情況下成立

假設當 n = k 時成立

證明當 n = k + 1 時成立

4. 寫出偽代碼


偽代碼

我們已經有了處理步驟,接下來就要編寫出偽代碼了,偽代碼可以轉換成真實的代碼,這有助于定義代碼的結構,并使編碼變得更加容易。您可以在紙上寫偽代碼,也可以在代碼編輯器中用注釋的形式來寫。如果你在電腦上做會分心,我建議你用紙和筆來完成。

通常偽代碼并沒有什么特定的規則,不過有的時候我可能會使用自己熟悉的某種語言的語法。所以不要被語法所糾纏。把精力放在邏輯和步驟上。

對于我們所面對的問題,可以有很多不同的方法。 例如,您可以使用filter,但是為了盡可能簡單地說明前面的例子,我們現在將使用一個基本的for循環(但是當我們重構代碼時,將會使用filter )。

下面是一個偽代碼的例子,它有比較多的語言描述:

function selectEvenNumbers
create an array evenNumbers and set that equal to an empty array
for each element in that array
  see if that element is even
    if element is even (if there is a remainder when divided by 2)
      add to that to the array evenNumbers
return evenNumbers

下面這段偽代碼比較簡潔:

function selectEvenNumbers
evenNumbers = []
for i = 0 to i = length of evenNumbers
  if (element % 2 === 0) 
    add to that to the array evenNumbers
return evenNumbers

只要你能把它逐行地寫出來,并且理解每一行的邏輯,用哪種方式并不重要。

最后還要回顧一下,確保自己沒有走偏。

5. 把偽代碼翻譯成真正的代碼并進行調試

當偽代碼被準備好之后,就可以把每一行偽代碼用自己正在使用的語言實現了。在這個例子中我們將使用JavaScript。

如果你把偽代碼寫在了紙上,那么就把它作為注釋輸入到自己的代碼編輯器中,之后再替換為代碼中的每一行。

然后我調用這個函數,并給它一些我們之前使用過的樣本數據集。可以用它們來檢查代碼執行的結果是否和預期一致。還可以編寫測試用例來檢查實際的輸出是否符合預期。

selectEvenNumbers([1])
selectEvenNumbers([1, 2])
selectEvenNumbers([1, 2, 3, 4, 5, 6])
selectEvenNumbers([-200.25])
selectEvenNumbers([-800.1, 2000, 3.1, -1000.25, 42, 600])

我通常在每個變量或者每一行后面都使用console.log()。這將會幫助我檢查變量值和代碼是否符合預期。通過這種方法,可以很容易的發現代碼中的問題。下面的例子是我在運行時會檢查哪東西。在我所有的代碼中都會這樣做。

function selectEvenNumbers(arrayofNumbers) {
  let evenNumbers = []
  console.log(evenNumbers) // I remove this after checking output
  console.log(arrayofNumbers) // I remove this after checking output
}

最后使每一行偽代碼都有對應的真實代碼。//后面是偽代碼,其它部分是用JavaScript實現的真實代碼。

// function selectEvenNumbers
function selectEvenNumbers(arrayofNumbers) {
  // evenNumbers = []
  let evenNumbers = []
  // for i = 0 to i = length of evenNumbers
  for (var i = 0; i < arrayofNumbers.length; i++) {
    // if (element % 2 === 0) 
    if (arrayofNumbers[i] % 2 === 0) {
      // add to that to the array evenNumbers
      evenNumbers.push(arrayofNumbers[i])
    }
  }
  // return evenNumbers
  return evenNumbers
}

為了避免混淆,我去掉了偽代碼。

function selectEvenNumbers(arrayofNumbers) {
  let evenNumbers = []
  for (var i = 0; i < arrayofNumbers.length; i++) {
    if (arrayofNumbers[i] % 2 === 0) {
      evenNumbers.push(arrayofNumbers[i])
    }
  }
  return evenNumbers
}

有時候,初級開發人員會被語法所困擾,導致難以繼續前進。記住:語法會隨著時間的推移而逐漸熟練起來。在編碼的時候因為語法問題去翻參考材料并不丟人。

6. 簡化并優化你的代碼

你可能已經注意到,簡化和優化是經常性的話題。

“簡單性是可靠性的先決條件。”
——荷蘭計算機科學家Edsger W. Dijkstra,計算科學研究領域的先驅

在這個例子中,優化的方法之一就是通過使用filter 返回一個新數組來過濾原來數組中的項。這樣我們就不用再去定義另外一個變量evenNumbers,因為filter 將返回一個新的數組,其中包含與過濾器匹配的元素并復制一個新的數組。 這樣就不會改變原來的數組。我們也不用使用for循環來進行遍歷。過濾器將會遍歷每個項,如果在數組中的元素符合條件就返回true,否則就返回false將其忽略。

function selectEvenNumbers(arrayofNumbers) {
  let evenNumbers = arrayofNumbers.filter(n => n % 2 === 0)
  return evenNumbers
}

簡化和優化代碼可能需要迭代多次,以確定進一步簡化和優化代碼的方法。

這里有一些需要牢記的問題:

簡化和優化的目標是什么?目標會被你的團隊風格或個人喜好所左右。是盡可能地壓縮代碼還是使代碼更易閱讀? 如果是后者,你可能會用多帶帶的代碼行來定義變量或計算某些變量,而不是試圖在一行中做這些事。

怎樣做才能使代碼容易閱讀?

還有沒有多余的步驟可以去掉?

有沒有變量或函數始終沒有被用到過?

是不是存在重復的步驟?看能不能在另外一個函數中定義它們。

有沒有更好的處理邊界問題的辦法?

編寫程序的本意是為了供人閱讀,只是順便讓計算機能夠執行它。
——“計算機程序的結構與解釋”作者Gerald Jay Sussman和Hal Abelson

7.調試

這一步應該貫穿始終。在調試的過程中,您會很容易發現邏輯上的錯誤或漏洞。要充分利用集成開發環境(IDE)和調試器。當我遇到bug時,會逐行跟蹤代碼,來檢查是否存在不符合預期地方。以下是我使用的一些技巧:

實用控制臺可以查看錯誤信息,有時候它會告訴我需要檢查哪一行,這就給了我一個大概的思路:從哪里開始。盡管有時候問題并不在提示給出的那一行。

注釋掉某些代碼塊或者行,并輸出調試信息,來檢查剩余的代碼是否能正常運行。可以根據實際情況對代碼進行注釋。

使用不同的測試數據,看看代碼是否仍然可以工作。以此來檢查是否存在我沒有想到的情況。

如果想要嘗試另外一種完全不同的方法,可以保存不同版本的文件。我可不想在恢復原來代碼的時候后悔莫及!

最有效的調試工具是仔細的思考,再加上輸出清晰的調試信息。
——普林斯頓大學計算機科學教授Brian W. Kernighan

8.添加有效的注釋

很有可能在一個月之后你會忘記自己的代碼都是什么意思,使用你代碼的其他人可能也不知道。這就是為什么要添加有效的注釋的原因:為了讓你在回頭看這些代碼時節省時間。

不要這樣去注釋:

// 這是一個數組,并且遍歷它

// 這是一個變量

我試著做一些簡要、高級的注釋,在出問題的時候可以幫我搞明白這段代碼到底是起到什么作用。尤其是在處理更復雜的問題時非常有用。它有助于理解某個特定功能在做什么以及為什么這樣做。通過使用清晰的變量名、函數名和注釋,你(和其他人)應該能夠理解:

這段代碼是做什么用的?

它是怎樣工作的?

9.通過代碼評審獲得反饋

從你的團隊成員、教授和其他開發者那里得到反饋。檢查堆棧是否會溢出。看別人如何解決這個問題并從中吸取教訓。有時解決問題的方法有好幾種。把它們都找出來,這樣你進步會很快。

別在意你寫出良好風格的代碼會花費多少時間,因為一旦你寫出了糟糕的代碼,那將會更慢。
——Bob Martin,軟件工程師,敏捷宣言的合著者之一

10.實踐,不停的實踐

哪怕是經驗再豐富的開發人員也總是在不停的實踐與學習。如果你得到了有用的建議,那么就要去照著做。重復做相同或類似的事情,不停的鞭策自己。隨著一個又一個的問題的解決,最終你會成長起來。在每一次成功之后,一定要對問題進行回顧。記住,編程和任何事一樣,會隨時間的推移變得更加簡單、更加自然而然。

歡迎掃描二維碼關注微信公眾號:充實的腦洞,第一時間推送我翻譯的國外最新技術文章。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87282.html

相關文章

  • 2017-08-15 前端日報

    摘要:前端日報精選變量聲明與賦值值傳遞淺拷貝與深拷貝詳解淺談自適應學習比你想象的要簡單常見排序算法之實現世界萬物誕生記中文深入理解筆記與異步編程譯不可變和中的知乎專欄譯怎樣避免開發時的深坑瘋狂的技術宅在翻譯網格布局掘金詳解改變模糊度亮 2017-08-15 前端日報 精選 ES6 變量聲明與賦值:值傳遞、淺拷貝與深拷貝詳解淺談web自適應學習 React.js 比你想象的要簡單常見排序算法之...

    xinhaip 評論0 收藏0
  • 怎樣處理 Safari 移動端對圖片資源的限制

    摘要:可能部分限制已經不再適用。當移動端的瀏覽器加載了到的圖片數據后,就會停止加載其他圖片,甚至瀏覽器還會崩潰。大多數網站都不會受到這條限制的影響,因為保持頁面合理的大小通常是一種很聰明的做法。替換掉屬性后,舊的圖片數據最終得到了釋放。 原文作者:Thijs van der Vossen 本文翻譯自《How to work around the Mobile Safari image res...

    Astrian 評論0 收藏0
  • 】你可能不需要派生狀態

    摘要:所有派生狀態導致的問題無異于兩種無條件的根據來更新無論和是否匹配來更新。派生狀態最常見的錯誤就是將這兩者混和在一起。因此通常被用于性能優化而不是來判斷派生狀態的正確性。我們可以使用派生狀態來存儲過濾列表這種方式避免了重新計算。 原文鏈接:https://reactjs.org/blog/2018... 翻譯這篇文章的起因是因為在一次需求迭代中錯誤的使用了getDerivedState...

    dinfer 評論0 收藏0
  • 】this 是什么?JavaScript 對象的內部工作原理

    摘要:關鍵字會實例化一個新的對象實例,并在執行構造函數時將指向該實例。原文鏈接譯是什么對象的內部工作原理 原文鏈接:What is this? The Inner Workings of JavaScript Objects (需要梯子) 原文作者:Eric Elliott 譯文永久鏈接:【譯】什么是 this?JavaScript 對象的內部工作原理 譯者:士心 翻譯目的:函數動...

    Hwg 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<