About Smoke: 防御性编程与契约式编程

Smoke 与契约式、防御性编程

Smoke 是我写的一个给Dto做Validation 的小工具(https://github.com/eltonZhong/smoke)。 起因很简单,之前我在写Http client的时候, 觉得在很多地方都要对同一个对象进行验证比较麻烦(防御性编程)。 有个注解形式声明, 在最初的地方对对象进行一次验证, 就可以在编码时假设数据是OK的了。注解形式的validation是声明式的, 减少了程序员对数据是否符合规范的恐惧。

想想, 如果这个东西是命令式的, 即你在第一次拿到这个对象的时候, 对它进行了基本的验证, 但是到后面的dal 层, service 层, 往往你还会对这个数据进行再一次的重复的验证, 才去执行自己的业务逻辑。

防御性编程给我们带来的好处是系统的错误尽早发现处理, 而不是在很后面抛出一个NPE, 到时候造成的损失可能是难以估量的。 而这又带来一个重复代码的问题, 代码到处验证, 十分臃肿。

所以很多人采用约定式的编程, 即我假设你传过来的数据是符合我的规范的, 出事怪你。 我个人觉得这个简直太可怕了, 就算自己写的代码, 我自己也难以信任, 更何况是别人的? 所以, 有个这么一个annotation声明在类上面, 就像是一个契约文档。 我去调用类的方法, 可以大概知道哪些field是安全的。 这个是对契约性编程的一种补充。

当然, 这远远不能达到 保证数据一定是安全的 需求。 那我们如何做呢?

  • 保证Dto(或者bean)是immutable 的
  • 在每一次对类修改, 都进行验证

以上两个条件满足其一即可。

当然上面都是我个人的一些看法, 看了一些防御性编程与进攻性编程, 觉得他们有部分都没有讲清楚(或者是小弟愚昧看不明白),所以我强行理解了一波, 给出的感触可能是这样的。

写Smoke的感触

Smoke 不是一个玩具。 它是我利用业余时间写的, 并在我日常工作上已经有应用的小工具(或者说框架)。

当初因为validation重复代码太多的问题, 上网找了一些解决方案, 比如hibernate的validator, 还有命令式的, 最终决定针对自己需求写一个。

刚开始信心满满,发布到jcenter, 自己想了好几个feature, 虽然用不到也实现了, 然后后面发现实在无人问津,就没再管了。 留了个VRule没有实现, 差不多一个月过去了, 今天还是决定把它弄完, 虽然没有星星, 做事还是要有始有终。 (谁叫我feature没做好先把readme写好了。。承诺过的feature, 浪费周末也要搞完。)

当然除了在我自己的工作中用到之外也不是全无收获, 搞了个travis自动test、publish到jcenter, 还踩了一对java库发布的坑(fucking java)。之前欠了好多技术债,一个一个慢慢还。

下面是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())
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容