2019年12月4日 星期三

讀書心得 - Clean Code - Chapter 4

Chapter 4 - 註解

不要替糟糕的程式碼寫註解 - 重寫它


    註解為必要之惡,用來彌補我們用程式碼表達意圖失敗的狀況。註解在絕大多數的情況無法跟著程式演進,導致過時且偏離當初的程式碼解釋。最後的真相只會存於程式碼。

有益的註解

    法律型的註解
    // Copyright 2011-2019 The Bootstrap Authors
    // Copyright 2011-2019 Twitter, Inc.
    資訊型註解
    資訊型註解提供一些基本資訊,但還是很容易被好的程式碼命名給取代
     // Returns an instance of the Responder being tested.
     protected abstract Responder responderInstance();
    對意圖的解釋
     // This is our best attempt to get a race condition
     // by creating large number of threads.
    對後果的告誡
     // Don't run unless you
     // have some time to kill

     // SimpleDateFormat is not thread safe,
     // so we need to create each instance independently

上一篇:
讀書心得 - Clean Code - Chapter 3 (2)
下一篇:
讀書心得 - Clean Code - Chapter 5

2019年12月3日 星期二

讀書心得 - Clean Code - Chapter 3 (2)

Chapter 3 - 函式 - 2

使用具描述能力的名稱


    不要害怕名字過長,若取了有性質的函式名稱就較能符合「當每個你看到的函式,執行結果都與你想的差不多代表為 Clean Code」。

函式的參數


    函式的參數越少越好,因為參數的存在也會影響著你對函式的預期,所以最理想的情況為 0 參數。
    一個參數
  1. 與這個參數有關的問題  - boolean fileExits("Myfile")
  2. 對這個參數做某種操作,然後回傳 - InputStream fileOpen("Myfile")
  3. 事件,利用參數去修改系統狀態 - passwordAttemptFailedNtimes(int attempts)
    第三種命名要特別小心,要明確的表示出此函式為事件。若參數為 flag 那你要知道此為很爛的作法,flag 就代表 True 要做一件事,False 要做一件事,違反了只做一件事的原則。
    兩 ~ 三個參數
    兩個參數影響函式的預期就更多,所以可以轉成一個參數就好好利用。
    物件型態的參數、參數串列
    利用物件型態或陣列去減少參數個數是不錯的方法
    Circle makeCircle(double x, double y, double radius);
    Circle makeCircle(point center, double radius);

指令和查詢的分離


    如果函式除了做某件事情後,還回傳了某個問題的答案,就等於做兩件事
    public boolean set(String attribute, String value);
    if(set("username", "unclebob"))...
    所以讀者看到此段 if 會容易產生誤解且疑惑,所以要將查詢與指令分開
    if(attributeExists("username")){
        setAttribute("username", "unclebob");
        ...
    }
    利用例外處理取代回傳錯誤碼
    錯誤處理本身就是一件事

Don't Repeat Yourself


   n 個重複的程式碼,代表修改要花 n 倍時間。

上一篇:
讀書心得 - Clean Code - Chapter 3 (1)
下一篇:
讀書心得 - Clean Code - Chapter 4

2019年12月2日 星期一

讀書心得 - Clean Code - Chapter 3 (1)

Chapter 3 - 函式 - 1

首要準則 - 簡短!!


    即使現今編輯器能讓你在一行塞入 150 個英文字母,現今螢幕能讓你顯示 100 行,你也不該塞好塞滿。越短越好,3 ~ 4 行,每個函式都透漏著本身的意圖且帶領著你至下個函式。
    區塊 ( Blocks ) 和縮排 ( Indenting )
    If、else、while 都應該只有 1 行,而那行通常會是個命名不錯的函式。

只做一件事


    只做一件事很難下定義,以下提出兩種
  1. 透過觀察函式中進而提煉出一個新的函式來
  2. 函式裡有明顯的段落 ( 宣告區、初始區、過濾區... )

只有一層抽象概念


    為了確保只做一件事,就必須確保函式裡都是同一層次的概念。
  • getHtml()      - 高層次
  • parsePath()    - 中層次
  • .append("\n")  - 低層次
    降階準則
    閱讀程式碼通常都是由上而下,所以層次也該從上到下

Switch 敘述


    switch 要簡短很困難且很容易跟上述規則牴觸,作者這裡是利用 Polymorphism ( 多型 ) 將 switch 壓到低的層次且不會被重複利用。

2019年11月26日 星期二

MySQL 筆數查詢、分頁查詢

N 筆資料查詢

    SELECT * FROM 成績單 LIMIT 3    // 取成績單前三筆資料
    SELECT * FROM 成績單 ORDER BY 分數 DESC LIMIT 3 // 取分數前三名的資料
    SELECT * FROM 成績單 ORDER BY 分數 DESC LIMIT 3, 7 // 取第四名到第十名的資料

分頁查詢

     隨著查詢筆數越來越多,網站可能就會需要用分頁來表示查詢結果。
     這裡會出現一個問題 Offset ( LIMIT 的第1個參數 ) 越大,查詢速度越慢。
    SELECT * FROM 成績單 LIMIT  100000, 1         // 大 Offset
     Google 的結果是 InnoDB 會有的情況,InnoDB 會掃 100001 筆資料,然會再把 100000 筆資料給捨棄,導致查詢速度越來越慢。所以解決方法為先只掃索引。
    SELECT * FROM 成績單 WHERE id >= (SELECT id FROM 成績單 LIMIT 100000, 1) LIMIT 1

2019年11月15日 星期五

英文歌詞翻譯 Gryffin, Elley Duhé - Tie Me Down




Don't lie, I know you've been thinking it
別說謊了,我知道你一直很渴望
And two times, you let it slip from your lips
兩次了,你那不想讓人聽見的低語
You've got too much pride to make any promises
你有太多不必要的驕傲以致做不出任何承諾
Thinking that we got time, and you want to keep it in
覺得我們還有時間,想著先保留

I want you out in the pouring rain
想要你在傾盆大雨中
I want you down on your knees
想要你跪下雙膝
Prayin' to God that I feel the same
祈禱著我跟你一樣愛著彼此
I'm right here, baby, so please
我就在這寶貝,所以請

Hold me up, tie me down
抱起我,綁住我
'Cause I never wanna leave your side
因為我永遠不想離開你
Swear to never let you down
發誓永遠不會讓你失望
And it's been eatin' me alive
這份想法正把我身吞活剝
You can take me home
你可以把我帶回家
You can never let me go
你也可以讓我永遠不離開
Hold me up, hold me up
所以抱起我,抱起我
And tie me, tie me down, down (down)
And tie me, tie me down, down
And tie me, tie me down, down (down)
And tie me, tie me down, down
綁住我

Nine lives until you fall at my feet
不顧一切直到你倒在我腳下
Don't hide, you're wasting your energy
別躲了,你是在浪費力氣
You're not shy, so baby, it's useless
你又不害羞,所以寶貝別躲了
So don't try, 'cause you'll end up losin' it
別再嘗試了,最後也只會敗在我手下

Hold me up, tie me down
抱起我,綁住我
'Cause I never wanna leave your side
因為我永遠不想離開你
Swear to never let you down
發誓永遠不會讓你失望
And it's been eatin' me alive
這份想法正把我身吞活剝
You can take me home
你可以把我帶回家
You can never let me go
你也可以讓我永遠不離開
Hold me up, hold me up
所以抱起我,抱起我
And tie me, tie me down, down (down)
And tie me, tie me down, down
And tie me, tie me down, down (down)
And tie me, tie me down, down
綁住我

So wrap your arms around my chest
用你的手抱住我吧
And I'll put my hands around your neck
我也會用我的抱住你的
'Cause nobody wins these waiting games
這場等待的遊戲是不會有贏家的
You push and you pull, but you should stay
你一下推又一下拉的,但你真正該做的是留下
Stay
留下

Nine lives - Myth to typically describe cats or humans that survive shit that should have otherwise killed them. Narrowly escaping death time after time.
經過九死一生後

2019年11月14日 星期四

Python UnitTest

Unit Test


     單元測試有一個通用模式 AAA原則,理解了就可以開始實作
  • Arrange   : 初始化物件、要用到的參數
  • Act   : 呼叫要測試的方法
  • Assert   : 驗證測試結果

Python Unit Test


     unittest — Unit testing framework,下面是官方給的範例
import unittest

class TestStringMunittestethods(unittest.TestCase):

     def test_upper(self):
          self.assertEqual('foo'.upper(), 'FOO')

     def test_isupper(self):
          self.assertTrue('FOO'.isupper())
          self.assertFalse('Foo'.isupper())

     def test_split(self):
          s = 'hello world'
          self.assertEqual(s.split(), ['hello', 'world'])
          # check that s.split fails when the separator is not a string
          with self.assertRaises(TypeError):
               s.split(2)

if __name__ == '__main__':
     unittest.main()
     unittest.main() 會執行所有 test_ 開頭的 function,主要判斷的 function 是 assert
  • assertEqual - 確認是否符合期望的值
  • assertTrue、assertFalse -  確認是否符合期望的判斷
  • assertRaise - 確認是否有特定 exception raise
     接著就是執行以上這 python 檔
D:\temp\JunYe\MyPython\Python3\LeetCode\UnitTest>python3 UnitTest.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

D:\temp\JunYe\MyPython\Python3\LeetCode\UnitTest>
     然後就是我自己的實作,拿 LeetCode - 0736 當範例
import unittest
import Solution

class TestMethods(unittest.TestCase):

     def test_case1(self):
          # Arrange 
          testclass = Solution.Solution()
          spec = '(add 1 2)'

          # Act & Assert
          self.assertEqual(testclass.evaluate(spec), 3)

     def test_case2(self):
          # Arrange 
          testclass = Solution.Solution()
          spec = '(mult 3 (add 2 3))'

          # Act & Assert
          self.assertEqual(testclass.evaluate(spec), 15)
     
     def test_case3(self):
          # Arrange 
          testclass = Solution.Solution()
          spec = '(let x 2 (mult x 5))'

          # Act & Assert
          self.assertEqual(testclass.evaluate(spec), 10)

if __name__ == '__main__':
     unittest.main()



參考資料 : 

  1. https://docs.python.org/3/library/unittest.html
  2. http://www.codedata.com.tw/python/python-tutorial-the-6th-class-1-unittest

2019年11月13日 星期三

Python List.pop(0)

Python list.pop(0)


     python 的 list 為 dynamic array,python.pop() default 值為 -1
  • python.pop()     # 時間複雜度 : O()
  • python.pop(0)   # 時間複雜度 : O(n)

Python deque.popleft()


     deque = double - ended - queue,deque.popleft() 的時間複雜度為 O(1)

     所以當變數為 list 且頻繁地操作 pop(0),不妨考慮
     tokens = collections.deque(mylist)
     x = tokens.popleft()


參考資料 : https://stackoverflow.com/questions/32543608/deque-popleft-and-list-pop0-is-there-performance-difference

Popular Posts