编程的智慧总结笔记
編程的智慧總結筆記
編程的智慧——王垠
http://www.yinwang.org/blog-cn/2015/11/21/programming-philosophy
反復推敲代碼
回頭去提煉和反思自己的代碼
寫優雅的代碼,樹狀結構的
if 語句幾乎總是有兩個分支
if (...) {if (...) {...} else {...} } else if (...) {... } else {... }寫模塊化的代碼,邏輯意義上的
避免寫太長的函數
制造小的工具函數
每個函數只做一件簡單的事情
// bad void foo() {if (getOS().equals("MacOS")) {a();} else {b();}c();if (getOS().equals("MacOS")) {d();} else {e();} }// good void fooMacOS() {a();c();d(); } void fooOther() {b();c();e(); }// bad void foo() {a();b()c();if (getOS().equals("MacOS")) {d();} else {e();} }// good void preFoo() {a();b()c(); } void fooMacOS() {preFoo();d(); } void fooOther() {preFoo();e(); }避免使用全局變量和類成員(class member)來傳遞信息,盡量使用局部變量和參數
// badclass A {String x;void findX() {...x = ...;}void foo() {findX();...print(x);}}// goodString findX() {...x = ...;return x;}void foo() {String x = findX();print(x);}寫可讀的代碼
使用有意義的函數和變量名字
局部變量應該盡量接近使用它的地方,局部變量的本質就是電路里的導線,變量定義離用的地方越近,導線的長度就越短
局部變量名字應該簡短
// bad boolean successInDeleteFile = deleteFile("foo.txt"); if (successInDeleteFile) {... } else {... }// good boolean success = deleteFile("foo.txt"); if (success) {... } else {... }不要重用局部變量
// bad String msg; if (...) {msg = "succeed";log.info(msg); } else {msg = "failed";log.info(msg); }// good if (...) {String msg = "succeed";log.info(msg); } else {String msg = "failed";log.info(msg); }把復雜的邏輯提取出去,做成“幫助函數”
把復雜的表達式提取出去,做成中間變量
// bad Pizza pizza = makePizza(crust(salt(), butter()),topping(onion(), tomato(), sausage()));// good Crust crust = crust(salt(), butter()); Topping topping = topping(onion(), tomato(), sausage()); Pizza pizza = makePizza(crust, topping);在合理的地方換行
寫簡單的代碼
避免使用自增減表達式
永遠不要省略花括號
合理使用括號,不要盲目依賴操作符優先級
避免使用continue和break
如果出現了continue,你往往只需要把continue的條件反向,就可以消除continue。
如果出現了break,你往往可以把break的條件,合并到循環頭部的終止條件里,從而去掉break。
有時候你可以把break替換成return,從而去掉break。
如果以上都失敗了,你也許可以把循環里面復雜的部分提取出來,做成函數調用,之后continue或者break就可以去掉了。
// bad List<String> goodNames = new ArrayList<>(); for (String name: names) {if (name.contains("bad")) {continue;}goodNames.add(name);... }只需要把continue的條件反向
// good List<String> goodNames = new ArrayList<>(); for (String name: names) {if (!name.contains("bad")) {goodNames.add(name);...} } // bad while (condition1) {...if (condition2) {break;} }只需要把這個條件合并到循環頭部
// good while (condition1 && !condition2) {... }// bad public boolean hasBadName(List<String> names) {boolean result = false;for (String name: names) {if (name.contains("bad")) {result = true;break;}}return result; }// bad public boolean hasBadName(List<String> names) {boolean result = false;for (String name: names) {if (name.contains("bad")) {result = true;break;}}return result; }使用return來代替break
// good public boolean hasBadName(List<String> names) {for (String name: names) {if (name.contains("bad")) {return true;}}return false; }寫直觀的代碼
// bad if (action1() || action2() && action3()) {... }// good if (!action1()) {if (action2()) {action3();} }寫無懈可擊的代碼,覆蓋所有可能出現的情況
// bad String s = ""; if (x < 5) {s = "ok"; }// good String s; if (x < 5) {s = "ok"; } else {s = ""; }正確處理錯誤
正確處理null指針
盡量不要產生null指針
不要catch NullPointerException
不要把null放進“容器數據結構”里面
函數調用者:明確理解null所表示的意義,盡早檢查和處理null返回值,減少它的傳播
函數作者:明確聲明不接受null參數,當參數是null時立即崩潰
防止過度工程
先把眼前的問題解決掉,解決好,再考慮將來的擴展問題。
先寫出可用的代碼,反復推敲,再考慮是否需要重用的問題。
先寫出可用 , 簡單 , 明顯沒有bug的代碼 , 再考慮測試的問題 。
總結
- 上一篇: 深度学习框架Caffe学习笔记(6)-测
- 下一篇: 第五课 程小奔之巡线