自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

幾個(gè)祖?zhèn)鞔a不遵守就想罵的代碼規(guī)范

開(kāi)發(fā) 后端
本文介紹幾個(gè)Go語(yǔ)言里比較容易堅(jiān)持執(zhí)行下去且能有助于我們減少BUG的編碼規(guī)范。

今天說(shuō)幾個(gè)我曾經(jīng)在管理項(xiàng)目和團(tuán)隊(duì)要求的基本編碼規(guī)范。實(shí)際執(zhí)行下來(lái)成本比較低,長(zhǎng)期堅(jiān)持下來(lái)的確有助于項(xiàng)目的維護(hù)。

雖然是幾個(gè)非常基本的代碼規(guī)范,但我們只在團(tuán)隊(duì)比較穩(wěn)定的時(shí)候堅(jiān)持下來(lái)過(guò),后來(lái)隨著人員更迭,懂得都懂。 這里也不是吐槽誰(shuí)的代碼習(xí)慣不好, 我也干過(guò)復(fù)制舊代碼過(guò)來(lái)就能用,媽呀真香,趕緊上線吧這種事情。

數(shù)據(jù)表和Model的命名規(guī)范

類型

規(guī)則

正確示例

錯(cuò)誤示例

數(shù)據(jù)表名

使用SnakeCase 命名法多個(gè)單詞用下劃線 _ 分割使用單詞的復(fù)數(shù)形式命名

vip_members

vipMembers   vipMember vip_member

數(shù)據(jù)表字段名

使用SnakeCase 命名法多個(gè)單詞用下劃線 _ 分割

user_name

userName UserName  _user_name

數(shù)據(jù)表在代碼中的Model 名

使用CamelCase命名 單詞使用單數(shù)形式

VipMember  vipMember

VipMembers  Members  vip_member

關(guān)于為啥數(shù)據(jù)表用復(fù)數(shù),Model用單數(shù),我的理解是Model代表的是這類東西,在英語(yǔ)里應(yīng)該用復(fù)數(shù)。

下面說(shuō)幾個(gè)Go語(yǔ)言里比較容易堅(jiān)持執(zhí)行下去且能有助于我們減少BUG的編碼規(guī)范。其他語(yǔ)言像Java的話,看阿里出的《阿里巴巴Java手冊(cè)》就可以,里面要求的比較細(xì)致。

Go語(yǔ)言編碼規(guī)范

1.函數(shù)簽名要避免歧義

函數(shù)名、參數(shù)名、參數(shù)類型、返回值類型要表達(dá)清楚要做的事情,避免產(chǎn)生歧義。這一條,感覺(jué)說(shuō)簡(jiǎn)單非常簡(jiǎn)單,但是實(shí)際項(xiàng)目開(kāi)發(fā)中,總是有不少人直接copy類似的函數(shù),名字也不按使用場(chǎng)景去調(diào)整,讓看代碼的人就很難受。

錯(cuò)誤案例:

func handleSomething(delay int) {
  for {
    // ...
    time.Sleep(time.Duration(delay) * time.Millisecond)
  }
}
poll(10) // delay參數(shù)定義成int 每次加的延遲是10毫秒還是10秒,還需要看poll函數(shù)的實(shí)現(xiàn)才知道

正確案例:

func handleSomething(delay time.Duration) {
  for {
    // ...
    time.Sleep(delay)
  }
}
poll(10 * time.Second) //delay參數(shù)定義成time.Duration類型, 調(diào)用時(shí)根據(jù)需求傳遞執(zhí)行任務(wù)時(shí)要延遲的時(shí)間段
 
 
// 或者用參數(shù)名,明確告訴調(diào)用者,傳遞要延遲的秒數(shù)
func handleSomething(delaySeconds int) {
  for {
    // ...
    time.Sleep(delaySeconds * time.Second)
  }
}

2.禁止使用硬編碼的魔術(shù)數(shù)字或字符串進(jìn)行邏輯判斷

在邏輯判斷里使用類似判斷屬性值是否等于某個(gè)硬編碼的值時(shí)會(huì)使得代碼晦澀難懂,應(yīng)該使用更能從字面上看明白含義的常量來(lái)代替這些邏輯判斷里硬編碼的值。

錯(cuò)誤案例

if prize.Type != 1 && prize.Type != 2{
    ......
}

正確案例:

const (
  PRIZE_TYPE_COUPON = 1
  PRIZE_TYPE_MONEY = 2
  PRIZE_TYPE_VIPSCORE = 3
)

if prize.Type != PRIZE_TYPE_COUPON && prize.Type != PRIZE_TYPE_MONEY {
    ......
}

3.避免在init中修改已初始化好的數(shù)據(jù)

注意程序的完全確定性,不要依賴init執(zhí)行的順序?qū)崿F(xiàn)功能,比如在后執(zhí)行的init函數(shù)中對(duì)前面已初始化后的全局變量進(jìn)行更改。

4.slice、map、chan、struct指針使用前必須先初始化

未初始化的map 默認(rèn)值是nil , 可以對(duì)nil map進(jìn)行讀取,但是寫(xiě)入會(huì)直接panic:

   var aMap map[string]string


aMap["foo"] = "bar" // panic

未初始化的slice,可以進(jìn)行讀取和append操作,但不做初始化遇到接口中要返回的某個(gè)字段查不到數(shù)據(jù)直接返回,該字段在JSON里會(huì)用null表示而不是[], 有一定幾率造成前端錯(cuò)誤。

type Person struct {
    Friends []string
}
 
 
func main() {
    var f1 []string
    f2 := make([]string, 0)
 
    json1, _ := json.Marshal(Person{f1})
    json2, _ := json.Marshal(Person{f2})
    fmt.Printf("%s\n", json1)
 
    fmt.Printf("%s\n", json2)
}
 
 
{"Friends":null}
 
{"Friends":[]}

向未初始化的nil chan 寫(xiě)入會(huì)造成goroutine阻塞,程序最終會(huì)死鎖:

func main() {
   //fmt.Println("Called heapAnalysis", heapAnalysis())
   var achan chan struct{}
   achan <- struct{}{} // fatal error: all goroutines are asleep - deadlock!
 
}

struct指針默認(rèn)為nil , 未初始化直接使用,假如程序邏輯里是查不到數(shù)據(jù)就不對(duì)指針指向的struct進(jìn)行復(fù)制,后續(xù)邏輯代碼再使用指針引用struct里的字段進(jìn)行判斷時(shí)會(huì)因?yàn)閲L試對(duì)nil pointer 解引用直接panic

func QueryData(a int) (data *Data, err error) {
    // data 返回值直接使用時(shí),默認(rèn)是nil
    // 確保安全應(yīng)該先對(duì)data 進(jìn)行初始化 data = new(Data)
    data, err := querySomeData()
    if errors.IsNotFoundErr(err) {
        return;
    }
}
 
 
func main() {
    dataP, err := QueryData()
    if err != nil {
        return err
    }
 
 
    if dataP.State == STATE_ACTIVE { // 此處有可能嘗試對(duì)nil pointer進(jìn)行解引用,會(huì)造成空指針問(wèn)題程序崩潰。
        // active logic
 
    }
}

5.代碼邏輯要盡量減少嵌套

代碼應(yīng)通過(guò)盡可能先處理錯(cuò)誤情況/特殊情況并盡早返回或繼續(xù)循環(huán)來(lái)減少嵌套。減少嵌套多個(gè)級(jí)別的代碼的代碼量。

錯(cuò)誤案例:

for _, v := range data {
  if v.F1 == 1 {
    v = process(v)
    if err := v.Call(); err == nil {
      v.Send()
    } else {
      return err
    }
  } else {
    log.Printf("Invalid v: %v", v)
  }
}

正確案例:

for _, v := range data {
  if v.F1 != 1 {
    log.Printf("Invalid v: %v", v)
    continue
  }
 
  v = process(v)
  if err := v.Call(); err != nil {
    return err
  }
  v.Send()
}

6.減少不必要的else代碼塊

注意下面兩種寫(xiě)法的直觀感受:

var a int
if b {
  a = 100
} else {
  a = 10
}
 
 
// 減少了不必要的else塊
// 如果在 if 和 else 兩個(gè)分支中都設(shè)置了變量,則可以將其替換為單個(gè) if。
a := 10
if b {
  a = 100
}

7.盡量避免使用map[string]interface{} 類型的參數(shù)

在函數(shù)的參數(shù)中盡量不使用map[string]interface{}, map[string][string]這種類型的參數(shù),IDE沒(méi)法幫助提示這些參數(shù)的內(nèi)部結(jié)構(gòu),這讓其他人使用這個(gè)代碼時(shí)就會(huì)很苦惱,還需要先看看函數(shù)實(shí)現(xiàn)里具體用到了字典的哪些鍵。

針對(duì)比較復(fù)雜的代表一類事物的參數(shù),應(yīng)該先定義結(jié)構(gòu)體,然后使用結(jié)構(gòu)體指針或者結(jié)構(gòu)體指針切片作為參數(shù)。

錯(cuò)誤案例:

func AuthenticateUser(input map[string]interface{}) error {
    name, _ := input[name].(string)
    password, _ := input[name].(string)
    findUser(input["name"], input["password"])
    ...
}

正確案例:

type UserAuth struct{
  Name     string
  Age      int32
  Password string
}
func AuthenticateUser(input *UserAuth) error {
    findUser(input.Name, input.Password)
    ...
}
責(zé)任編輯:趙寧寧 來(lái)源: 網(wǎng)管叨bi叨
相關(guān)推薦

2021-11-01 07:21:46

代碼同事碼農(nóng)

2009-01-19 14:20:33

ASP.NET編碼編碼規(guī)范命名

2012-09-18 09:17:34

Java規(guī)范代碼代碼

2011-07-14 11:27:50

java

2022-01-26 10:52:21

代碼Python數(shù)據(jù)庫(kù)

2025-03-31 01:45:00

2021-07-25 20:01:50

程序員AI開(kāi)發(fā)

2020-05-25 11:14:59

代碼程序開(kāi)發(fā)

2014-02-19 10:34:48

JavaScript代碼規(guī)范

2024-01-12 09:35:30

Java代碼開(kāi)發(fā)

2020-11-12 09:45:16

前端開(kāi)發(fā)代碼

2020-08-17 08:49:06

北極程序員開(kāi)源

2010-08-03 10:59:14

Flex代碼規(guī)范

2011-12-02 10:32:23

Java

2010-08-31 13:32:12

CSS

2022-08-28 10:08:53

前端代碼前端

2013-04-09 10:23:08

編碼規(guī)范編程語(yǔ)言

2023-09-04 13:55:44

分支masterhotfix

2009-09-01 10:37:51

C#項(xiàng)目代碼C#代碼規(guī)范

2021-09-26 16:08:23

CC++clang_forma
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)