About Smoke: 防御性編程與契約式編程

Smoke 與契約式给涕、防御性編程

Smoke 是我寫的一個給Dto做Validation 的小工具(https://github.com/eltonZhong/smoke)。 起因很簡單,之前我在寫Http client的時候, 覺得在很多地方都要對同一個對象進(jìn)行驗(yàn)證比較麻煩(防御性編程)迅腔。 有個注解形式聲明, 在最初的地方對對象進(jìn)行一次驗(yàn)證, 就可以在編碼時假設(shè)數(shù)據(jù)是OK的了。注解形式的validation是聲明式的, 減少了程序員對數(shù)據(jù)是否符合規(guī)范的恐懼靠娱。

想想, 如果這個東西是命令式的, 即你在第一次拿到這個對象的時候, 對它進(jìn)行了基本的驗(yàn)證, 但是到后面的dal 層, service 層, 往往你還會對這個數(shù)據(jù)進(jìn)行再一次的重復(fù)的驗(yàn)證, 才去執(zhí)行自己的業(yè)務(wù)邏輯沧烈。

防御性編程給我們帶來的好處是系統(tǒng)的錯誤盡早發(fā)現(xiàn)處理, 而不是在很后面拋出一個NPE, 到時候造成的損失可能是難以估量的。 而這又帶來一個重復(fù)代碼的問題, 代碼到處驗(yàn)證, 十分臃腫像云。

所以很多人采用約定式的編程, 即我假設(shè)你傳過來的數(shù)據(jù)是符合我的規(guī)范的, 出事怪你锌雀。 我個人覺得這個簡直太可怕了, 就算自己寫的代碼, 我自己也難以信任, 更何況是別人的? 所以, 有個這么一個annotation聲明在類上面, 就像是一個契約文檔迅诬。 我去調(diào)用類的方法, 可以大概知道哪些field是安全的腋逆。 這個是對契約性編程的一種補(bǔ)充。

當(dāng)然, 這遠(yuǎn)遠(yuǎn)不能達(dá)到 保證數(shù)據(jù)一定是安全的 需求侈贷。 那我們?nèi)绾巫瞿兀?/p>

  • 保證Dto(或者bean)是immutable 的
  • 在每一次對類修改, 都進(jìn)行驗(yàn)證

以上兩個條件滿足其一即可惩歉。

當(dāng)然上面都是我個人的一些看法, 看了一些防御性編程與進(jìn)攻性編程, 覺得他們有部分都沒有講清楚(或者是小弟愚昧看不明白),所以我強(qiáng)行理解了一波, 給出的感觸可能是這樣的。

寫Smoke的感觸

Smoke 不是一個玩具俏蛮。 它是我利用業(yè)余時間寫的, 并在我日常工作上已經(jīng)有應(yīng)用的小工具(或者說框架)撑蚌。

當(dāng)初因?yàn)関alidation重復(fù)代碼太多的問題, 上網(wǎng)找了一些解決方案, 比如hibernate的validator, 還有命令式的, 最終決定針對自己需求寫一個。

剛開始信心滿滿,發(fā)布到j(luò)center, 自己想了好幾個feature, 雖然用不到也實(shí)現(xiàn)了, 然后后面發(fā)現(xiàn)實(shí)在無人問津,就沒再管了搏屑。 留了個VRule沒有實(shí)現(xiàn), 差不多一個月過去了, 今天還是決定把它弄完, 雖然沒有星星, 做事還是要有始有終争涌。 (誰叫我feature沒做好先把readme寫好了。睬棚。承諾過的feature, 浪費(fèi)周末也要搞完第煮。)

當(dāng)然除了在我自己的工作中用到之外也不是全無收獲, 搞了個travis自動test、publish到j(luò)center, 還踩了一對java庫發(fā)布的坑(fucking java)抑党。之前欠了好多技術(shù)債,一個一個慢慢還包警。

下面是Smoke的文檔~

Smoke [圖片上傳失敗...(image-c07683-1546516134945)]

A declarative validator framework for dtos, beans, or just objects.

Install [圖片上傳失敗...(image-6dbbef-1546516134945)]

Get the latest version at Jcenter

// For gradle
repositories {
    jcenter()
}

dependencies {
    compile 'com.ez.tools:smoke:5.0.0'
}

Basic Usage

class UserDto {
    @VString(shouldBe = {"John1", "John2"})
    @VNotNull
    String name = null;
}

// Will throw java.lang.IllegalStateException when field name is null
com.ez.tools.validator.Smoke.validate(new UserDto())

Go to package com.ez.tools.validator.annotations to find other features.

Advance features

Smoke 5.0 focused on the following topics:

  • Field validation, with built-in constraints: @VString, @VInt, @VNotNull.
  • Getter method validation, contraints can be put on method with no arguments, when validating, the getter method will be called, and the value returned will be validated.
  • @VRule on class level, validate this kind of object using additional rule.

VString

The regex feature has been released! Use regex:

class UserDto {

    @VString(shouldMatch = {Regexps.EMAIL})
    String email;

    // Custom regex: Name should match all values in should match
    // And name should not match any values in should not match
    @VString(shouldMatch = {".+", "..."})
    @VString(shouldNotMatch = {"..."})
    String name;

    @VString(...)
    public void get***() {
    }
}

VRule

Use additional rules to validate your dto.

Add additional rule:

com.ez.tools.validator.Smoke.validate(new UserDto(), IRule...rules)

or:

/**
* Add your rule class
**/
@VRule(com.ez.tools.validator.core.rules.AllFieldsShouldNotBeNull.class)
class UserDto {}

// Will validate using the rule specified in VRule value.
com.ez.tools.validator.Smoke.validate(new UserDto())

Also you can write Additional rules:

class YourRule implements IRule {
    @Override
    public void validate(Object o) {
        if (!o instanceof UserDto) {
            throw new IllegalArgumentException();
        }
        UserDto dto = (UserDto) o;
        if(dto.name == "elton" && dto.age > 100) {
            throw new Exception("Elton is dead after at 99 years old.")
        }
    }
}

// Use it in your common interface:
@VRule(YourRule.class)
interface SatisfyYourRule {}

// Implements the interface:
class YourDto implements SatisfyYourRule {}

// When validate your dto, the rule will be invoked. And as rule above, Exception("Elton is dead after at 99 years old.") will be thrown
Smoke.validate(new UserDto("elton", 100))

VRecursive

Wanna validate details of a field with smoke? Try VRecursive:

class UserDto {
    @VRecursive
    AddressDto address = new AddressDto(this);
}

@VRule(AllFieldsShouldNotBeNull.class)
class AddressDto {
    public AddressDto(UserDto dto) {
        user = dto;
    }

    String a = null;

     @VString(shouldMatch = {Regexps.EMAIL})
    String getEmail() {
        return "123@qq.com";
    }

    @VRecursive
    UserDto user = null;
}

// Will validate userDto's address, with respect to rules and other annotation con
// And don't worry that it might cause stackoverflow exception:
// smoke will not validate same object twice.
com.ez.tools.validator.Smoke.validate(new UserDto())

Remeber! When field is null, smoke will ignore this field's validation.

You can use VNotNull to handle this situation

class UserDto {
    @VString(shouldMatch = "^elton.+")
    String name = null;
}

// Will not validate when name is null. If you want to, add @VNotNull annotation constraints.
com.ez.tools.validator.Smoke.validate(new UserDto())
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市底靠,隨后出現(xiàn)的幾起案子害晦,更是在濱河造成了極大的恐慌,老刑警劉巖暑中,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壹瘟,死亡現(xiàn)場離奇詭異,居然都是意外死亡鳄逾,警方通過查閱死者的電腦和手機(jī)稻轨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雕凹,“玉大人殴俱,你說我怎么就攤上這事政冻。” “怎么了线欲?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵明场,是天一觀的道長。 經(jīng)常有香客問我李丰,道長苦锨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任趴泌,我火速辦了婚禮舟舒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘踱讨。我一直安慰自己魏蔗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布痹筛。 她就那樣靜靜地躺著,像睡著了一般廓鞠。 火紅的嫁衣襯著肌膚如雪帚稠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天床佳,我揣著相機(jī)與錄音滋早,去河邊找鬼。 笑死砌们,一個胖子當(dāng)著我的面吹牛杆麸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浪感,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼昔头,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了影兽?” 一聲冷哼從身側(cè)響起揭斧,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎峻堰,沒想到半個月后讹开,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捐名,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年旦万,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镶蹋。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡成艘,死狀恐怖赏半,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情狰腌,我是刑警寧澤除破,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站琼腔,受9級特大地震影響瑰枫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丹莲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一光坝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧甥材,春花似錦盯另、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叠萍,卻和暖如春芝发,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苛谷。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工辅鲸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腹殿。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓独悴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锣尉。 傳聞我的和親對象是個殘疾皇子刻炒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

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