设计杂谈(0x01)——配置文件的起源与矛盾

设计杂谈(0x01)——配置文件的起源与矛盾

7 个月前 · 来自专栏 设计杂谈

在“设计杂谈”系列,主要会讲述设计相关的问题与思考。本文将主要针对配置的起源与实际面对的问题进行必要的讲述,以求为读者建立一个初步的概念。

话不多说,开始。

由静态到动态

首先,我们来看这样一个需求:

设计一个程序,输入一个图片,并将其进行一系列处理,其中包括:
1、翻转(flip) 2、旋转(rotate) 3、裁剪(crop)

很简单对吧,那不妨先脑洞一波,来看看一般的做法会是怎样的。

写脚本时的硬编码

首先,我们来看看一种最简单的情况。比如,现在需要把一个或者一批图片,按照既定的操作来进行处理。你打算写一个脚本来完成这项工作,使用PIL包进行处理,大概会是这样的一个画风

from PIL import Image

image = Image.open('test_pic.png')
new_image: Image.Image = image

# flip operation, left_right or top_bottom
new_image = new_image.transpose(Image.FLIP_TOP_BOTTOM)

# rotate, 0-360, from x-axis to y-axis
new_image = new_image.rotate(45)

# crop, x1, y1, x2, y2
width, height = new_image.size
new_image = new_image.crop((width / 4, height / 4, width * 3 / 4, height * 3 / 4))

而运行结果则是这样的(此处使用matplotlib展示图片,下文同)

运行结果,左图为原图,右图为转换后的图

既定的效果实现了,效果十分令人满意,一切都没啥问题。

写轮子时的函数化

而接下来,由于这个脚本在越来越多的地方被用到,所以需要将其进行一个封装,使之不再依赖于特定的图片,也不再依赖于固定的流程,可以被任意调用以实现图片的处理。

一番思索后,你进行了封装,于是画风变成了这个样子

from PIL import Image



def processes(image: Image.Image, ops) -> Image.Image:
    cur_image = image
    for op in ops:
        op_type, *op_vals = op
        if op_type == 'flip':
            cur_image = cur_image.transpose(op_vals[0])
        elif op_type == 'rotate':
            cur_image = cur_image.rotate(op_vals[0])
        elif op_type == 'crop':
            cur_image = cur_image.crop(op_vals)
        else:
            raise ValueError(f'Unknown operation - {repr(op_type)}.')

    return cur_image



if __name__ == '__main__':
    image_ = Image.open('test_pic.png')
    width, height = image_.size
    new_image = processes(
        image_,
        [
            ('flip', Image.FLIP_TOP_BOTTOM),
            ('rotate', 45),
            ('crop', width / 4, height / 4, width * 3 / 4, height * 3 / 4),
        ]
    )

直接运行时,可以获得和之前程序等价的效果。此后,对图片的三种操作正式被封装为了轮子,并在项目中被广泛使用。

写工具时的配置化

然而没过多久,随着处理过程的越发复杂,又开始有了新的需求。具体来说,你希望可以以一种更加黑盒的形态来对图片进行处理,并且考虑到很多时候处理的流程都是相对固定的,因此如果对图片进行处理时可以不必编写Python源代码那才是最好的。

你思来想去,决定使用yaml这样的“配置文件”,来表达图片处理的流程逻辑。结合之前的函数化轮子,再一次封装后,画风又变了。首先是配置文件config.yaml ,如下所示

processes:
  - type: flip
    direction: top_bottom
  - type: rotate
    angle: 45
  - type: crop
    x1: 100
    y1: 100
    x2: 500
    y2: 500

即呈现这样的结构

config.yaml呈现的层次结构

而后运行命令(该脚本已经经过重构,此处由于并非问题重点,因而不作详细展示)

python process.py config.yaml test_pic.png

也同样得到了上述的结果,并且这一过程中对于使用者而言,并无需关注process.py的具体内容。

配置文件

基本特性

诸如上面的“故事”,相比各位都非常熟悉,常做开发的人应该都会日常遇到。当一个业务逻辑需要往通用化方向发展时,就会产生“轮子”这一形态;而当“轮子”需要被进一步黑盒化、工具化时,则需要引入“配置”这一概念,也就是上面所使用的config.yaml

对于“配置文件”,稍作观察不难发现其特性:

  1. 多为树状结构(JSON、YAML、conf等均是如此)
  2. 表达唯一且明确的语义(即配置本身不该含有歧义)
  3. 可移植,不依赖具体的语言或环境(并无绝对界限,能满足实际需要即可)

现实存在的问题

针对上述的第1和第2点,我们可以推测出以下的事实:

  • 意味着其经常需要处理多层次的配置数据,表达嵌套的语义
  • 意味着配置需要能精确表达其语义,展示其所有信息以确保对配置解析器而言能解读出唯一含义。 这样一来,在配置的设计上就会存在一个不可避免的问题——绝对完备且嵌套的语义,必然导致配置文件可能变得极为冗长。例如上述的图片处理,如果处理的阶段再多上一些,尤其是剪裁(crop)操作要是较多的话,则可以形成一个极长无比的配置文件。

也许你可能还是对配置的复杂性没有概念,那么容我们再看一个更复杂些的例子

更复杂的例子

其实说不复杂也不复杂,就是上面图片处理的plus版。更具体来说,就是对一系列的图片,进行带有一定随机性的处理。这个操作常应用于深度学习领域,被称为数据增强(Data Augmentation),定义如下:

Data augmentation in data analysis are techniques used to increase the amount of data by adding slightly modified copies of already existing data or newly created synthetic data from existing data. It acts as a regularizer andhelps reduce overfitting when training a machine learning model.

举个例子,你需要训练一个用于识别“手掌”图片的模型,然而你收集到的数据大都是左手,就像这样的

训练过模型的都知道,如果直接将这样的数据作为训练集,则很可能会出现针对“左手”的过拟合情况,通俗来说,就是会让模型只认识左手,而不认识右手

而为了解决这一问题,我们需要对原本的图片数据进行“增强”,也就是随机转换生成一些新的数据,其中比较常见的四种转换分别为(均基于torchvision):

例如,对于上面那只左手,可以经过一系列随机转换后,形成如下的效果

左上图为原图,其余八张图为转换后的结果

有了这些数据,则可以很大程度上解决掉“无法识别右手”的情况,也大概不怎么会再因为光线之类的问题而导致识别出错了。

交代了完了这个问题,如果我们也需要将“数据增强”这一过程,封装为与上文类似的配置形态,则会变得极为复杂且混乱。比如,我们来随便挑一个配置看看,下面这个是RandomCrop的输入数据格式(完整版在此

torchvision.transforms.RandomCrop官方文档截图

一共五个参数,其中有三个是带有结构化数据的。而与之类似的还有RandomRotation,相比之下RandomVerticalFlipRandomHorizontalFlip要简单不少。

我们可以尝试用YAML格式写一下由上述四类增强转换组合形成的流水线,画风则很可能是这样的

processes:
  - type: random_vertial_flip
    p: 0.5
  - type: random_horizontal_flip
    p: 0.5
  - type: random_rotation
    degrees:
      - -180
      - 180
    interpolation: nearest
    expand: true
    center:
      - 100
      - 100
    fill: 0
  - type: random_crop
    size:
      - 300
      - 300
    padding:
      - 3
      - 5
    pad_if_needed: true
    fill:
      - 255
      - 128
      - 0
    padding_mode: constant

即呈现这样的结构

包含四种转换组合的配置文件层次结构

这还仅仅只是每种类型仅添加了一次,如果次数更多的话,结构还会更加复杂。不仅如此,序列形式的结构化数据在树状结构的配置文件中的表意也并不足够清晰。

设计上的矛盾点

以上的问题,在配置文件的实际使用中是广泛存在的,而且由于实际应用中还会涉及到多模块,以及多种不同的结构化数据格式,因此还可能存在更加冗长的内容,以及层数更深的嵌套。

而这个问题实际上根源在于配置灵活性和易用性的矛盾。例如,在上述数据增强的例子中,RandomCropRandomRotation均有较多的参数,但是实际应用中会被使用的只是一少部分。而若要覆盖此类操作的全部潜在功能,则又必须设立如此复杂的各类参数。于是矛盾就是这样形成的。这也正是为什么常见的配置文件往往都比较冗长的原因。

鉴于这样的情况,为了更好地设计配置文件格式,使之便于编写和查阅,则是一个值得讨论的问题。实际上,在设计领域已经有比较成功的实践,且适合于配置文件的设计,这便是——“约定大于配置”原则。具体内容,将在下一篇中作详细讨论,敬请期待。

编辑于 2022-07-12 08:30
如何以“我穿越过来时,故事已经接近尾声”开头写一个故事?
满目山河依旧
我穿越过来时,故事已经接近尾声,而我,穿越成了自己书里的人物。连炮灰都算不上, NPC 一个,名叫展羽霁,在我这本《大齐风华》里,笔墨不超过三章,描写不超过两百个字。我的男宠是可以随时干掉我的大佬,而这位男宠,是我小说的主人公——谢琛,狂炫酷霸拽的起点文逆袭大男主,我在文中给他开了无数金手指,令他在众叛亲离的情况下,仅用十年就从锒铛入狱的罪臣之子登临帝位。而现在时间线是文章末期,男主的势力差不多构建完毕,但出了点小状况,他设计截杀大将周冲时,被流矢射中,落入河中。这在文里当然不是什么大问题,但为了剧情紧凑情节波折,我当时脑子一抽,让昏迷的男主被不长眼的长平侯府小世子抢回府里。要命的是,这位小世子硬要男主当他的男宠。谢琛在我笔下是个脾气不好但城府颇深、喜怒不形于色的货色,他周旋良久,等到手下找来,就直接将长平侯府屠了个满门。当时我的评论区下面全是读者在嚎——「好爽!」「特么的这才是真·爽文啊!」「就该杀他丫的,也太侮辱人了」单章评论首次过千,我身为作者亲妈笑得美滋滋。而现在,当我听到侯爷喊我「羽霁」时,我只恨我为什么要手贱写这本破文!02我想,我还能抢救一下。只要男主还没出现,我就绝不往那条河边凑!「世子,那个关在柴房的男宠……该如何处置?」我眼前一黑,险些晕了过去。论如何从小说后期已成长为大佬的男主手下活过三章?我想哭。我为什么不把男主写得弱一点呢?我脑内千回百转,思考了上百种方法,终于还是哭丧着脸道:「带我去见他。」我打了个寒颤,又嘱咐道:「……嘴上把门,对他尊敬点,别再叫他男宠了。」03第一次见到自己笔下的人物实体化,我心里「卧槽」了一句。不愧是我写的男主,端方君子,温润矜雅,即便肩膀受了重伤,也不减风华半分。谢琛一双波光潋滟的眼看着我:「见过世子。不知世子意欲何为?」其实说起来,小世子也没做啥——只是上来就不分青红皂白,关人一顿不给吃的,美其名曰「磨磨锐气」,是炮灰脑残 NPC 的通常套路。写这段是为了跟之后的打脸形成鲜明对照。「赤水交战,江城府尹下令,有异常情况及时上报。重赏之下必有冤案,最近不少外地人无辜被冤枉成叛军,悬尸于城墙之上。我担心公子被人发现,不得已将公子藏于此处,公子的伤可还要紧?我已经派人去找我姑姑,她懂医术,一会儿便能为公子处理伤口。」电光火石之间,我已经为自己编好了一个剧本。不愧是我!写过五本朝堂升级流爽文的勤劳码字工!「世子就不怕我真的是叛军?」谢琛不动声色地笑。他肩上是贯穿伤,已经被他自己简单处理过了,但在水里泡了几个时辰,又被关在柴房昏了一上午,如此体力不支、情形不明的状况下他仍能镇定自若……不愧是我笔下人气最高的男主!「公子说笑了,你未披铠甲未执兵锐,手无寸铁,怎么会是叛军呢?」我说道。算是给双方一个合理的借口。我只求能尽快送走这尊大佛,别把自己的命给送了就行。04其实也不是不能杀了男主。毕竟我给男主的设定,是智力值 MAX,武力值中等,多找几个身强力壮的护卫,压也能压得死他。但我舍不得。毕竟是陪伴了我两年的亲儿子,我心里默念:大佬思考别过脑,我好你好大家好。「伤得不轻呀。」展羽霁的小姑是个久居江南的女子,一口吴音软语,替他包扎处理,「痛得话就说一下。」谢琛除去额角出了细汗,神色依旧如常,温和笑道:「没事,展姑娘不用顾忌我。」我沉迷于男主的美色,后知后觉品出这话的意思。我从头到尾都没提「展」家,谢琛却直呼展羽霁姑姑为「展姑娘」,很明显他知道这是哪儿!不过这也不难推导,赤水下游的江城,侯府就也这么一家。但我没想到谢琛的记性能好到这个程度——我的设定里,江城从来不是主要交战区,而长平侯府更是没什么实权的破落家族,作为统筹大局的男主,根本不需要记这些东西的!他最多也就扫了眼情报。那那那那他知道,展羽霁这个小世子,好男色吗???05小姑走后,就我和谢琛在房里。我方了,很方。谢琛靠在我侧房的软塌上,侧脸在灯火下犹如玉雕,赤裸的上身白皙劲瘦,软塌较短,他的长腿只能半屈,对一个伤患来说体验肯定不会太好。可从他面上看不出分毫。他彬彬有礼地对我说:「多谢世子相救。近来城中氛围很紧张吗?」「那是当然,仗都打到家门口了,也不知道什么时候是个头。」我愁眉不展。他安抚般笑道:「想必快了。江城不会被波及的,放心。」我不敢和这尊大佬单独呆太久,尽管严格来说,我是他的作者爸爸。我把放在一旁的长袍递给他,斟酌道:「那公子好好休息。」我正准备离去,听到谢琛悠悠问我:「世子似是对我避之不及,也没有过多亲近之举,是敏之入不了世子法眼吗?」敏之是谢琛的字。我:???我愣了三秒,才懂谢琛的意思。他娘的果然是听说过「长平侯府世子好男色有一堆男宠」的传闻,见我老老实实规规矩矩,在这试探+调戏我呢。我果断关上门,夺路而逃。身后一声隐约轻笑,苏得人头皮发麻。气死了,爸爸没有你这么叛逆的儿子!06气虽气,我还是要操心男主的伤情。他接下来有场攻入皇城的硬仗要打,在原文里,神医林征虽然医好了男主,但春季潮湿,谢琛还是留下了病根——反正是文章结尾,我一笔带过了。读者不知道,我却清楚,谢琛之后每到梅雨季节,肩膀的旧伤都要痛上几个月。我板着脸:「公子多加注意,箭伤不是说笑的。」谢琛把玩着我送来的药,唇边噙着抹笑:「劳烦世子关心。」谢琛在府上养了三天,就告辞离去。离去前,他低下头,在我耳边道:「多谢世子隐而未报,日后再见,琛必有重谢。」我以一个老父亲的心态想:儿砸,做父母的不需要报答。07展羽霁养了三个男宠,风姿各异,性格迥然。但都有一个特点。脸美。我这段时间闲来无事,就宅在府上,看看美人磕磕颜,偶尔听小厮聊八卦。他们说,叛军赤水大捷之后又一路东进,快要打到皇城望都了。又过了两个月,望都被攻下,昏庸无道的皇帝人头落地。百官皆降,簇拥着谢琛坐上皇位。展羽霁他爹摸了摸我狗头,说道:「儿子啊,这世道变得太快了,还好我们不待在望都,天高皇帝远的,当个土地主多舒服。」我感叹刚当别人爸爸没几次,就成了儿子。虽然我还是觉得不怎么真切,毕竟严格来说,这些人都是我创造出来的纸片人,这个世界是我构想出的世界。但眼前这老头子还是挺真实的,于是我咧了咧嘴,笑着点了点头。心想如果这么有闲有钱度完一辈子,倒也不错。可惜这老头儿嘴巴开了光。他说完这句话第二天,望都就来了一道圣旨。新皇点名道姓,让长平侯府小世子速来望都,进宫面圣。我愁眉不展,拍了拍惊恐不定的老侯爷肩膀,心说,我也没给您老设定个乌鸦嘴啊。我就这么被叫去望都了。有个男宠哭兮兮地抱我大腿,非要跟我走——说小世子不在,老侯爷八成要赶他们出府。我最见不得美人落泪,干脆把他们三个都捎了过去。我还制作了一副麻将,四个人刚好凑个整。他们对新奇的牌局很感兴趣,一路上都聚在马车里打麻将,我乐呵呵地给他们喂牌,输了算我的,赢了算他们的。心下却有些愁:谢琛叫我过去,到底是做啥呢?我一时片刻竟揣摩不透儿子的想法了。作为老父亲,十分发愁。马车摇摇晃晃半个月,终于到了京城。前来接见的是个太监,从他嘴角硕大的美人痣,我认出这是我笔下人气很高的魏公公。——这货有一颗月老心,喜欢给男主物色美人,燕环肥瘦,都得先经过他老人家的眼。男主设定是个黑心芝麻汤圆,但家族破灭前,也是个世家公子。要不是为了复仇,他性格称得上温润淡然,于男欢女爱上,兴趣值基本为 0。但起点那群老色批们,又非得让男主收后宫……为了不崩人设,我只得设计了魏公公这么个角色。唯一目的就是网罗来各色美人,苦口婆心地说「陛下您该纳妃」了。我和魏公公大眼瞪小眼,不明白这位肥圆成球的胖公公,非得揽这种出来接人的累活干啥。中秋还未到,秋老虎恼人得很,您看您这满头大汗的。魏公公有些尴尬地咳嗽了声,对我道:「世子爷,您这边请——」他带我去了一座宅邸,说是谢琛暂赐我住下的。「世子爷救了陛下,可谓是从龙之功呀,陛下为人重情重义,必定会有重赏的。」魏公公笑得见牙不见眼,「咱家再给您拨几个奴才伺候着,您就安心等陛下的赏赐吧!」下人们高兴地不行,等魏公公走后,我却高兴不起来。因为我记得,这是一处凶宅。08我瞪着府邸上发旧的匾额出神,对站在我旁边敷粉的某位男宠发愁:「你说,他把谢家的旧宅给我住,葫芦里卖啥药?」大齐背景类似魏晋,男子化妆不足为奇。可这宣平之,实在是太爱惜自己的容貌了,对这些化妆品了解得比小世子的丫鬟都多。再加上这位兄台略娘,我总是在心里叫他 Tony 老师。「哎呀,这说明新皇器重世子爷嘛~您看,除了老旧的匾额未动,这里都修缮一新了,一点也看不出来荒废了快十年的样子。」 宣平之翘着兰花指说道,「谢家的老宅子,可是陛下小时候长大的地方。除了您,这京城里谁有这份殊荣?」我却越过匾额,看到那深黑的房梁。谢琛的母亲就是在这根房梁上吊死的——在谢家被抄家的那晚。在房梁上晃动的惨白色身影,是谢琛见到他母亲的最后一面。把主角的背景写惨点,来个先抑后扬,好让读者更有打脸升级的爽快感是一回事。亲自深入其中,见到真实的现场,又是一回事。我仿佛看到了十二岁的谢琛,在哭泣中无能为力被拖走的样子。不知怎的,我心脏有点疼,针戳了似的。我拍了拍宣平之的肩膀,说道:「你脚下当年说不定就摆了具谢家仆人的尸体。」宣平之「哎呀」一声跳开,差点扭伤脚,被我轻轻揽住了腰。「小心。」我扶稳他。他红着脸:「谢世子爷。」然后使劲往我身上蹭。我:「……」这几个月来,三个人或试探或有意,总是往我眼前凑。我敬谢不敏。俩大老爷们,我有的你也有,硬梆梆的,哪里有软妹子抱起来舒服?我斟酌道:「平之,等这边接完赏,安定下来,我就给你们三个每人一笔银两和一处地契,你们去做自己喜欢的事儿吧。」宣平之哭丧着脸:「平之只想一辈子伺候世子爷。」他娘是青楼女子,他也无一技傍身,留在侯府当个男宠,是最好的选择。自力更生对另两位来说比较简单,对他来说还挺难。于是我让步道,「你如果实在不想走,也随你意,反正侯府多养一个人,还是没问题的。」他这才哭哭啼啼地走远,估计是跑去和另外两位控诉了。我抬头望天,发愁地想:「可是剩下两位都是被强抢来的,恨不得早点逃脱,你去倒苦水,他俩得像看傻子一样看你。」我想还是要介绍一下,小世子这三个除了脸俊外风姿各异的男宠。我按照身高给他们排了个序。一号估摸着有 190cm+,是个武林中人,真名不详,只知道姓娄,因为额角有块月牙形刀疤,小世子就唤他娄月。宽肩窄腰大长腿,搁现在很有做模特的潜质,随身揣着把弯银刀,反正我有点怵这位兄台。毕竟当初小世子是从衙门里带他回来的——娄月牵扯进了一桩杀人案。纨绔世子爷当天衙门一日游,看到娄月样貌,就心痒痒地把人给要来了。杀人犯也敢上,我只能说展羽霁你是个人物。二号选手 185cm 肯定是有的,名为秦臻远。书香门第出身,但家道中落,在钱庄帮忙算账,筹备科举考试时,被前去换银两的展羽霁瞧上了。这人有点文人特有的清冷孤傲,眉眼又冷然,估计很合展羽霁的胃口。就是我瞅着这比我还高五六厘米的身高差,心里嘀咕。这秦臻远不像娄月,娄月有点无所谓的吊儿郎当和痞气,秦臻远却明显是受不得欺辱的那种性格。于是我第一次对这位世子爷的属性,产生了怀疑。三号就是这位 Tony 老师宣平之了,175cm。还是有人比我矮的。果不其然,次日宣平之哭哭啼啼地又跑了回来,说秦臻远骂他有病。我只得一边等谢琛召见,一边生无可恋地安慰多愁善感的 Tony 老师。谢琛应该很忙,刚当上皇帝,一堆繁琐政事需要他操心。直到中秋时,他才邀请我去宫中赴宴。09谢琛不喜奢华,宴席也办得从简。我目不转睛地盯着为首的那些大臣,从外貌性格辨别他们是我笔下的谁。丞相、谢琛的老师、大将军、兵部侍郎。怪新奇的。比自己的作品被影视化了还新鲜。宴席结束,谢琛在御书房单独召见了我。他换了件青衣,冠冕旒珠换为紫玉冠,端的是潇潇君子。见我行礼,他温声道:「免礼,世子坐吧。这望都一个月,住的可还习惯?」「挺好的,这里酒楼饭馆我都尝了个遍,九歌楼的酒配上东坡肉,味道绝佳。」我眼神不住地瞟谢琛搁在书案上的手。骨节如竹,修长白皙,可惜左手大拇指指骨有些凹陷。那是在西陵一战时,留下的旧伤。当时怎么没把这些副本,设定简单得一些呢?我心想,一笔带过的伤,在这里却是会伴随他一生的啊。谢琛没忍住笑了,道:「世子倒是性格洒脱。」「奴婢给陛下和世子爷奉茶。」魏公公适时出现,给我俩一人奉了一杯热茶,说是解解腻。他那喜庆如弥勒佛的脸上,一双眼实在是显小,我得费劲巴拉地才能发现,他在打量我。我想:看啥看,我又不是皇帝潜在的后宫,用得着这么把关似地盯着我吗?「不敢,陛下谬赞。」我道。我端起茶盏来凑到嘴边,就听到谢琛悠悠问道:「对了,世子府上那三位公子,近来可好?」我差点没一口茶水喷出去。不是,儿砸,你打听这三个男宠干什么???你不会看上哪位了吧???我惊疑不定,飞快想了圈剧情,悲伤地意识到,直至小说结尾,男主虽然被魏公公塞了一大堆后宫,但的确没有临幸任何一位妃子。我:「……」我强作镇定:「劳烦陛下挂心,他们三位在望都住得习惯。」「世子不必紧张。」谢琛似乎看出我的不安,「只是听礼部尚书常大人提到过,最近有个白衣公子,与京中文人交谈颇深,文采斐然得众人推崇。」我头疼:「……陛下说的是秦臻远吧?」事实上,除了 Tony 老师安分点,那个江湖客娄月也好,还是一心想着考科举的秦臻远也好,一天到晚都不见人影。要不是谢琛提起,我真不知道他们在干啥。谢琛但笑不语。这眼神我熟——表示我话说一半,你尽量猜。 我硬着头皮解释:「臣本想见过陛下后,就遣散他们三人,再归江城的。他们三位闲散惯了,做事没什么规矩,还请……」「世子可能还需在望都住上一段时日。」谢琛放下茶盏,似笑非笑地打断我,「论功行赏,也得在年节大祀之后,望都的春景也堪称一绝,世子大可等春末再回。」掐指一算,现在八月中秋,距离明年末春还有七个月。我就算再后知后觉,也能意识到谢琛这是有意困我在京城。反正不管怎么样,这个年我在这过定了。等谢琛命魏公公送我出宫时,我还是有点懵。就塞了块银锭子给魏公公,试探道:「在望都还得待几个月,我这心里实在挂念父亲,却拿不准陛下意图,公公可知晓?」魏公公果断推拒:「哎哟,世子爷,您可真是折煞老奴了,使不得使不得。陛下这是喜欢您呐!想留您多住些时日,您就尽管安心吧!驿站的信使,世子爷都可使唤,也好给侯爷报个平安。」尽管知道魏公公说的喜欢不是那个意思,但我还是打了个哆嗦。10论功行赏虽在之后,这次入宫我也不是空手而归,还是有些赏赐被搬回了谢家老宅。手头闲钱多了,我动了提前打发三个男宠离开的心思。出乎意料的是,宣平之不想走就算了,娄月和秦臻远也当下拒绝。娄月抱刀靠在门侧,道:「懒得走,江湖啊也就那样,刀光剑影命悬剑刃上,待久了没意思,想找个地儿养老。长平侯府就挺适合的,世子爷应该不会赶我走吧?还是说世子爷嫌我伺候得不舒服?」我看着他那把弯刀,服软:「……不会。」秦臻远嗓音清冷,清俊的一张脸有拒人千里之外的冷漠:「暂且还得倚仗世子,叨扰。」我:「???」我对他这「求人」态度无奈,抚额:「……无事。」至于宣平之,他本来就不想走。此次谈判宣告破裂。当晚回到房间,沐着月色我给自己斟了杯谢琛赐的酒。不对劲。我凭着自己的记忆,开始复盘这件事。按照谢琛的性格,不会行无用之功,那他软禁我在望都,定有他的理由。其实谢琛当时屠了长平侯满门,是有些 OOC(人设崩坏)的。谢琛早年以罪臣之子身份入朝堂,沉浮过四五年,为了给他刷经验刷脸熟,各个部门我都让他转了一圈。他为人温润和沐,风评极佳,收拢了大波人心。后来,他率兵入望都时,这些文武百官都老老实实投降——因为见识过他的能力和为人,心服口服。既然如此,谢琛不太可能在他刚登帝位,势力不稳之时,就将侯府三百多人全都杀个干净。这太容易落人口舌。但小说快结尾有些疲软,追更人少了大半,订阅也跟不上,我为了吸引读者眼球,只好设置了这么一个小高潮。「如果……小说能够自行补足逻辑缺漏的 bug 呢?」我不知不觉,将一壶酒都喝完。如果谢琛毫不犹豫地下令斩杀,是有其他理由呢?那……又会是什么理由呢?11真相如何暂且不论,我还是留了个心眼。我让宫里拨来几个小宫女,日日向我报告这三个男宠的行踪。他们看上去倒是规规矩矩。娄月是真过上了「保温杯里泡枸杞」的养老日子,整天去茶楼听评书,据说还路见不平,拔刀救下了一位差点被强抢的民女。我听了以后心呼诡异,你们仨不都差不多是被展羽霁强抢进侯府的吗?秦臻远一心向学,我倒是明白了他说的「倚仗我」是啥意思,感情是挂着我客卿的名头,好去参加一些文人清谈。至于 Tony 老师宣平之就更悠闲自在了,琢磨着新妆,往小宫女脸上试,一个两人个的,被他打扮得花枝招展。我一边纳闷自己是不是忒大惊小怪了,一边绕着皇城转悠,盘算着还有哪些表面投降,实存反心的臣子。这一次,我不太想让谢琛再这么辛苦。我一个无权无势的小世子当然谋划不了太多,但我可以替这些反臣们做一两件出格的事儿,足以让谢琛注意到他们。腊月末,大雪纷纷扬扬地下,我披着一件狐裘大氅站在兵部侍郎府前看戏。「让谢琛来见我,我真是瞎了眼,那小子在我手底下做事的时候,我怎么没看出来他是个狼子野心的东西,他这个千古罪人——」兵部侍郎双眼通红地嘶吼,却被扣押他的羽林卫拖远,后面的话听不清,埋进风雪里。这应该是最后一个假降的官员了。我滴溜溜地转着油纸伞黄木的伞柄,心情愉悦。原文里这兵部侍郎仗着和谢琛是旧识,差点下毒害死了他。我转身正准备离开,却猝不及防闯入一双探究的眼。谢琛不知在我身后站了多久。未带侍从,孤身一人,月白色长袍外也不晓得裹件斗篷披风,细碎的雪沫在他肩上铺了薄薄一层,更是落在他的长睫上,衬得眼眸更深邃清润。我心道:「药丸。」
评论
写评论

文章被以下专栏收录

    设计杂谈

    设计杂谈

    讲讲代码设计的那点事

推荐阅读

设计杂谈(0x01)——配置文件的起源与矛盾
HansBug 的文章 7 赞同
想来知乎工作?请发送邮件到 jobs@zhihu.com