golang project exp02

谷歌SRE那本書中所講到一點熔酷,就是搞業(yè)務(wù)運維或說SRE爽室,最頭疼的就是工作量隨著服務(wù)規(guī)模的增長線性增加温自。其實個人覺得這一點放到開發(fā)中也是一樣的帘靡,隨著需求的增加知给,services、views目錄下的文件越來越多描姚,編寫它們的時候都是copy&paste涩赢,維護它們的時候也是一樣的任務(wù)量復(fù)制。
就其根源轩勘,個人覺得就是我們所謂“開發(fā)”對工程規(guī)范的漠視筒扒,導(dǎo)致維護過程中問題的累積。這里也記錄一點過去積累的好的編碼習慣(針對golang而言)

1绊寻,創(chuàng)建一個較為復(fù)雜的對象時花墩,把New函數(shù)參數(shù)可選
比如說

type MyOperation struct {
    keyone string
    valone int
    someConfig bool
    someConfig2 bool
    storage *db.Connection
}

type Opt interface {
    apply(*MyOperation)
}

type optFunc func(o *MyOperation) 

func (f optFunc) apply(o *MyOperation) {
    f(o)
}

func WithStorage(src *db.Connection) Opt {
    return optFunc(func(o *MyOperation) {
        o.storage = src
    }
}

func WithConfig(conf bool) Opt {
    ...
}

func NewOperation(mustKey string, ... Opt) (*MyOperation, error) {
    op := &MyOperation {
        keyone : mustKey,
    }
    for _, optFunc := range Opt {
        optFunc(op)
    }
    return op, nil
}

我剛開始的時候很不理解,把一個NewOperation寫這么有什么好處榛斯。但是后來發(fā)現(xiàn)观游,代碼結(jié)構(gòu)、可讀性是真的非常重要驮俗。特別運維開發(fā)這塊懂缕,國內(nèi)現(xiàn)在就是一個起步過程,運維開發(fā)存在很多任務(wù)都是對之前代碼的重構(gòu)與功能維護王凑。
我相信干過一段時間你就知道閱讀別人代碼的痛苦吧搪柑,可能搞懂邏輯就要花好幾天聋丝,但是寫代碼不過一兩天、兩三天而已工碾。

2弱睦,多寫注釋,如果一個函數(shù)參數(shù)很多渊额,甚至可以給參數(shù)加注釋况木,特別是我們一個操作對象,可能有n多個配置旬迹,如
func someOperation(true, true, false, false, true,...)
并且這個函數(shù)可能會在一個代碼文件中出現(xiàn)多次火惊,可能每次這些布爾配置參數(shù)還不一樣,所以有必要加一點說明
func someOperation(true /* 允許重試/, true, false, false / 不記失敗日志等*/,...)

3奔垦,減少作用域

... 上文中已經(jīng)存在err 錯誤對象屹耐, 這個err可能并不希望被覆蓋掉

if f, err := someOpt(); err != nil {
    return err
}
f.xxx()

4,開關(guān)策略(這條是摘抄來的)
生產(chǎn)環(huán)境上的所有操作都是需要嚴格按照策略進行椿猎,那么就需要添加一個開關(guān)機制惶岭,我之前項目并未應(yīng)用這種機制,確實帶來了不少麻煩犯眠,所以這里可以摘錄一下

package switches


var (
    xxxSwitchManager = SwitchManager{switches: make(map[string]*Switch)}
    
   AsyncProcedure = &Switch{Name: "xxx.msg.procedure.async", On: true}

    // 使能音視頻
    EnableRealTimeVideo = &Switch{Name: "xxx.real.time.video", On: true}

)

func init() {
    xxxSwitchManager.Register(AsyncProcedure, 
    EnableRealTimeVideo)
}


// 具體實現(xiàn)結(jié)構(gòu)和實現(xiàn)方法
type Switch struct {
    Name      string
    On        bool
    listeners []ChangeListener
}

func (s *Switch) TurnOn() {
    s.On = true
    s.notifyListeners()
}

func (s *Switch) notifyListeners() {
    if len(s.listeners) > 0 {
        for _, l := range s.listeners {
            l.OnChange(s.Name, s.On)
        }
    }
}

func (s *Switch) TurnOff() {
    s.On = false
    s.notifyListeners()
}

func (s *Switch) IsOn() bool {
    return s.On
}

func (s *Switch) IsOff() bool {
    return !s.On
}

func (s *Switch) AddChangeListener(l ChangeListener) {
    if l == nil {
        return
    }
    s.listeners = append(s.listeners, l)
}

type SwitchManager struct {
    switches map[string]*Switch
}

func (m SwitchManager) Register(switches ...*Switch) {
    for _, s := range switches {
        m.switches[s.Name] = s
    }
}

func (m SwitchManager) Unregister(name string) {
    delete(m.switches, name)
}

func (m SwitchManager) TurnOn(name string) (bool, error) {
    if s, ok := m.switches[name]; ok {
        s.TurnOn()
        return true, nil
    } else {
        return false, errors.New("switch " + name + " is not registered")
    }
}

func (m SwitchManager) TurnOff(name string) (bool, error) {
    if s, ok := m.switches[name]; ok {
        s.TurnOff()
        return true, nil
    } else {
        return false, errors.New("switch " + name + " is not registered")
    }
}

func (m SwitchManager) IsOn(name string) (bool, error) {
    if s, ok := m.switches[name]; ok {
        return s.IsOn(), nil
    } else {
        return false, errors.New("switch " + name + " is not registered")
    }
}

func (m SwitchManager) List() map[string]bool {
    switches := make(map[string]bool)
    for name, switcher := range m.switches {
        switches[name] = switcher.On
    }
    return switches
}

type ChangeListener interface {
    OnChange(name string, isOn bool)
}


// 這里開始調(diào)用
if switches.AsyncProcedure.IsOn() {
    // do sth
}else{
    // do other sth
}

并且這里可以看到的按灶,switch對象中的name是通過點進行分隔的,這也是SRE中所說的阔逼,所有配置信息都應(yīng)有清晰的命名標準兆衅,并且所有成員都可以了解到這些配置項

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嗜浮,隨后出現(xiàn)的幾起案子羡亩,更是在濱河造成了極大的恐慌,老刑警劉巖危融,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畏铆,死亡現(xiàn)場離奇詭異,居然都是意外死亡吉殃,警方通過查閱死者的電腦和手機辞居,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛋勺,“玉大人瓦灶,你說我怎么就攤上這事”辏” “怎么了贼陶?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我碉怔,道長烘贴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任撮胧,我火速辦了婚禮桨踪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芹啥。我一直安慰自己锻离,他們只是感情好,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布叁征。 她就那樣靜靜地躺著纳账,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捺疼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天永罚,我揣著相機與錄音啤呼,去河邊找鬼。 笑死呢袱,一個胖子當著我的面吹牛官扣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播羞福,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼惕蹄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了治专?” 一聲冷哼從身側(cè)響起卖陵,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎张峰,沒想到半個月后泪蔫,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡喘批,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年撩荣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饶深。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡餐曹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出敌厘,到底是詐尸還是另有隱情台猴,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站卿吐,受9級特大地震影響旁舰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嗡官,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一箭窜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衍腥,春花似錦磺樱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尚骄,卻和暖如春块差,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背倔丈。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工憨闰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人需五。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓鹉动,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宏邮。 傳聞我的和親對象是個殘疾皇子泽示,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容

  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,764評論 0 38
  • 寫在前面的話 代碼中的# > 表示的是輸出結(jié)果 輸入 使用input()函數(shù) 用法 注意input函數(shù)輸出的均是字...
    FlyingLittlePG閱讀 2,743評論 0 8
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,694評論 0 3
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,370評論 0 5
  • 1、隨機數(shù) 不需要隨機數(shù)種子 arc4random()%N + begin:產(chǎn)生begin~begin+N的隨機數(shù)...
    我是小胡胡分胡閱讀 4,144評論 0 2