2KB项目,专业的源码交易网站 帮助 收藏 每日签到

语义压缩

  • 时间:2019-01-23 18:31 编辑:2KB 来源:2KB.COM 阅读:380
  • 扫一扫,手机访问
  • 分享
摘要: 英文原文:Sem
英文原文:Semantic Compression

我们都知道如何使用C++编程,不是吗 ?  我的意思是,我们都已经读过由以及热闹的留着胡子的家伙们精选的好书,是他们率先定义了编程语言,因此我们已经都学过了编写C++代码来解决真实世界问题的最好方式.

首先来看看现实世界中的问题——比方说一个工资系统—— 你会发现他里面有一些复数名词: “员工(employees)”, “经理(managers)”, 等等.  因此你需要做的第一件事情就是为这些名词创建类.  至少应该有一个 employee 类和一个 manager 类.

但是实际上,它们两个都是人(people). 因此我们可能需要一个叫做 “人(person)”的基类, 这样在我们的程序中那些不在意你到底是一个员工还是一个经理的部分,就可以值把你当做一个人对待. 这是非常人性化的,而且使得其他的类感觉上不像是一个企业及其中的齿轮!

不过这儿还有点问题.  经理就不也是一个员工吗?   因此经理应该可能要从员工继承, 而后员工从人继承.  现在我们真的达成了某些目标!  我们还没有真正想过要如何去写一些代码, 确实是,但我们已经对相关的对象进行了建模, 而一旦我们拥有了这些尸体,代码就只是在自己编写自己了.

等等,啊 — 你知道了什么吗 ?  我刚刚意识到,如果我们还有承包商( contractors)该如何呢?  我们肯定需要一个 contractor 类, 因为他们不是员工. contractor 类可以从person类继承, 因为所有的承包商都是人 (是不是 ?).  这都会是不言而喻的 .

但是这样的话manager类该从哪继承呢?  如果它从employee类继承,那么我们就不能有从事承包商工作的经理. 如果它从contractor类继承,那么我们就不能有全职的经理. 这将会是一个真正困难的编程问题, 像是 Simplex 算法之类的问题!

OK, 我们可以让manager对两个类都进行继承, 然后只使用它们之中一个的特征. 但那样就没有足够的类型安全性了.  这并不是某些随意编写的JavaScript的程序 ! 但是你知道吗 ?  砰!  我就此得到了解决方案 : 对manager类进行模板化.  我们可以在基类上对manager类进行模板化, 然后所有随着manager类一起运作的东西都在其上被模板化了!

这将会是最好的工资系统了 !  当我梳理出了所有这些类和模板 , 就开始启动编辑器,去创建UML图形了.

程序员发编程贴

如果我刚刚写的都是荒谬的就好了,但可悲的是,实际上世上有许许多多的程序员都这样想啊. 我不只是在说 “实习生Bob” — 而是指所有类型的程序员,包括那些讲课和写书的知名程序员.  我也要痛心的指出在我的生涯中的一段时期也是这样子思考的.  在我18岁的时候被介绍了解了“面向对象编程”, 而直到大概24岁的时候才意识到这一切都是胡说八道 (而这种认识的形成少不了要感谢我在工作时使用的RAD游戏工具, 我很庆幸,它没有让我整个陷入OOP的噩梦中去).

但是尽管外头许多的开发者事实上都已经经历过像这样的糟糕阶段,并且最终得出了有关如何真正高效的写出好代码这样的总结,但是现有的海量教材仍然势不可挡的沦落到“中看不中用”之类。我猜想这跟一个事实有关,这个事实就是一旦你知道怎么做了,那么好的编程方式看起来就会是非常直接的, 不像那种徒然注重外表,让你想要去耗费时间才捣鼓出来的技巧,比方说一个花哨的数学技巧。因此,尽管没有任何数据佐证,我仍强烈的猜想着,有经验的程序员很少会花时间去告诉别人他们是如何去编写程序的,因为他们根本不认为这是什么特别的事情.

但他们应该这样做!这可能并不特别,但却是有必要的,而如果好的程序员没有开始去写点有关“如何好好的去编写程序”的东西给其他人看,那么我们将永远不会逃离泥潭,那时每个人就都要在认识到他们在浪费时间之前的六年时间,编写可怕的面向对象程序了。因此我要在接下来的一辑见证(Witness)文章上所做的,就是花一些重要的文笔讲述将代码放入计算机里去,这一纯机械的过程, 我也真诚地希望其他有经验的程序员能够花点时间也像我这样做一做。就个人而言,我喜欢读到更多有关那些实际上很优秀的程序员坐下来写代码时所使用的技术。

首先,我要开始细化一套简单的代码转换方案,我曾在《见证者》(The Witness)的编辑器代码中这么做过。在未来几周内,我将从一些比较大的案例中出来,在这些案例中我从头开始写了,但我用了全部的时间去痛苦地专注于代码和它的构建。我没什么要说的,在这其中根本就没有什么有趣的算法、数学或是其他的什么东西,一切都只是在“清理管道”。

乔恩(Jon)开始做事了

在《见证者》的内置编辑器中,有一块UI被称为“移动面板”(Movement Panel)。它是一个浮动的带有若干按钮的窗口,被用来展示一些如“旋转90度”的操作。最初这个窗口非常的小,只有几个按钮,但当我在编辑器上开展工作后,我加了一系列的特性,都需要用到移动面板。这将会在很大程度上扩大它的内容,并且也意味着我不得不学习如何向这个UI中添加元素,这是我之前从未做过的。我检查了现有的代码,这些代码看起来是这样的:

int num_categories = 4;
int category_height = ypad + 1.2 * body_font->character_height;
float x0 = x;
float y0 = y;
float title_height = draw_title(x0, y0, title);
float height = title_height + num_categories * category_height + ypad;
my_height = height;
y0 -= title_height;

{
    y0 -= category_height;
    char *string = "Auto Snap";
    bool pressed = draw_big_text_button(x0, y0, my_width, category_height, string);
    if (pressed) do_auto_snap(this);
}

{
    y0 -= category_height;
    char *string = "Reset Orientation";
    bool pressed = draw_big_text_button(x0, y0, my_width, category_height, string);
    if (pressed) {
    ...
    }
}
...
其它翻译版本 (1) 加载中

我首先注意到的事情就是原来的程序员Jon做得真的很不错,将我正要做成的事情打好的前阵. 许多许多次你一打开某些像这样如此简单的东西的代码时,你会发现它只是一大堆乱麻一样的不必要的架构和中间层.  而在这里我们发现的则是一系列非常直接的事情在发生着,读起来非常像你在那样子指导一个绘制出一个UI的面板: “首先,计算出标题条应该怎么摆放,然后,绘制这个标题条.  现在,在那个标题条下面,绘制自动捕捉(Auto Snap)按钮. 如果它被按下了,就做自动捕捉 . . .”   这正就是我们所设计的如何运行的.  我才任何的大多数的人都能从这段代码读到它在做的事情,而且可能不用除了这段摘录的代码之外的其它任何东西,就能凭直觉知道如何添加更多的按钮.

不过,这段代码虽然如此漂亮,但是它明显不是为了做大量UI操作而生的, 因为所有的布局工作仍然靠手工完成,一行一行的编写.  在上面的代码段中这有点轻微的不方便, 而且一旦你考虑到更加复杂的布局,事情就会变得更加的繁重, 就像这块UI的代码,在同一行出现了四个独立的按钮:

{
    y0 -= category_height;

    float w = my_width / 4.0f;
    float x1 = x0 + w;
    float x2 = x1 + w;
    float x3 = x2 + w;

    unsigned long button_color;
    unsigned long button_color_bright;
    unsigned long text_color;

    get_button_properties(this, motion_mask_x,
        &button_color, &button_color_bright, &text_color);
    bool x_pressed = draw_big_text_button(x0, y0, w, 
        category_height, "X", button_color,
        button_color_bright, text_color);

    get_button_properties(this, motion_mask_y,
        &button_color, &button_color_bright, &text_color);
    bool y_pressed = draw_big_text_button(x1, y0, w, 
        category_height, "Y", button_color, 
        button_color_bright, text_color);

    get_button_properties(this, motion_mask_z,
        &button_color, &button_color_bright, &text_color);
    bool z_pressed = draw_big_text_button(x2, y0, w, 
        category_height, "Z", button_color, 
        button_color_bright, text_color);

    get_button_properties(this, motion_local,
        &button_color, &button_color_bright, &text_color);
    bool local_pressed = draw_big_text_button(x3, y0, w, 
        category_height, "Local", button_color, 
        button_color_bright, text_color);

    if (x_pressed) motion_mask_x = !motion_mask_x;
    if (y_pressed) motion_mask_y = !motion_mask_y;
    if (z_pressed) motion_mask_z = !motion_mask_z;
    if (local_pressed) motion_local = !motion_local;
}

因此,在我们开始添加许多的新按钮之前,我已经觉得自己应该花一点点时间在底层的代码上,以使其能更容易的添加新的东西进去.  为什么我会这样子觉得呢,而我又如何知道在这种情况下“更简单”意味着什么呢?

语义压缩

我把编程从本质上分为两个部分:找出处理器在完成任务中真正需要做的事情,然后以我所使用的语言,用最有效的方式来表达.而事实上,程序员在后者上花费越来越多的时间:在将所有这些算法和数学形式连成一个整体,并且不会因其自身的重量而这件事情上进行缠斗. 

所以任何有经验的优秀程序员一定会考虑高效地编程意味着什么即便只靠直觉.说起 “高效 “,并不仅仅指代码优化.更准确地说,这意味着代码的开发过程也是优化的即代码得是结构化的,这种结构化能够最小化敲代码,跑起程序,修改代码,进行足够的debug使其能够交付使用所付出的人类劳动力.

我喜欢尽量从整体上考虑效率性. 如果你将一块代码作为整体考察开发的过程,你不会对任何隐藏的花费视而不见. 在代码被使用的地方给定其性能和质量的等级, 从有了它开始到最后一次被任何人因为任何原因而使用到结束,我们的目标就是讲它所要耗费的人力成本最小化. 这包括了将其输入的时间,包含了修改它的时间,包含了将其适配到其它用途的时间. 它包含为了让它能与其运行起来的,而假如是被用不同方式写出来的,则可能不会有那么必要的代码的任何工作量. 使用这份代码的整个生命周期的所有工作都被包含了进来.

当以这种方式进行考虑的时候,我的经验让我总结出,编程最有效率的方式就是让自己就像是一个字典压缩器一样的处理你的代码. 从字面意思上看,你假装自己是PKZip的很棒的版本,它不断的在你的代码上运行,不断地寻找让它(在语义上)更加小的方式.  而要明白,我的意思是语义上更加的小,如重复和相似的代码少,而不是物理上更加的小,如文本少,尽管这两者经常如影随形.

这是一个非常地自下而上的编程方法, 它是一个最近被冠上绰号“重构”的伪变体 , 尽管它同时也是因为许多原因而被视为不值得进行的荒谬过程.  我也认为正式的“重构”这个概念丢失了要点,而并不值得我们去实践.  要点会是,它们是某类相关的,而你有希望将在阅读这一系列文章的过程中理解到的异同.

那么面向压缩编程会是什么样子呢,而它为什么是有效的呢?

就像一个好的压缩机,我不会重用任何东西,除非我至少需要两个它这样的东西.  许多程序员不理解这有多重要,并且立马就尝试去写“可重用的”代码,但那可能就是你会犯下的最大的错误之一. 我提倡的是,“在让你代码可以重用之前,先让它是可以用的”.

在每一个特定的情况中,我总是只去写出我确切的想要发生的东西, 没有任何有关”正确性“或者”抽象性“的东西,或者任何其它的流行词, 而我也让其运行了起来. 然后,当我发现自己在其它的某中情况下正在第二次做相同的事情, 那就是时候我该把可重复使用的部分拉出来进行共享,从而有效地”压缩“代码.  我更喜欢拿”压缩“来做比喻, 因为它意味着某些有用的东西,而不像常用来做比喻的“抽象”,它并没有表达出任何有用的东西. 谁会关心代码是否抽象了?

等待着,直到一块代码(至少)有了两个用到它的实例,意思是要直到我知道自己真的需要考虑如何去重用它,同时它的意思也是在我尝试去使其可以重用之前,我总是会有至少两个真正的,代码所要做的实例.  这一点对于效率至关重要,因为如果你只有一个实例,或者更加糟糕,(在没有想好就开始写代码的情况下)没有实例, 那么很有可能会在编写它的时候犯错误,并且会产生不那么方便拿来重用的代码.  这会导致你在使用它时更多时间浪费, 因为它要么将会很麻烦,要么你将为了让它能按你需要的方式运行而不得不重新编写它. 因此我努力尝试从不去使得代码“过早的可重用”, 导致要用到高纳德(Kruth)的那些麻烦东西.

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。 2KB翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。


2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务

  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【计算机/互联网|】Nginx出现502错误(2020-01-20 21:02)
【计算机/互联网|】网站运营全智能软手V0.1版发布(2020-01-20 12:16)
【计算机/互联网|】淘宝这是怎么了?(2020-01-19 19:15)
【行业动态|】谷歌关闭小米智能摄像头,因为窃听器显示了陌生人家中的照片(2020-01-15 09:42)
【行业动态|】据报道谷歌新闻终止了数字杂志,退还主动订阅(2020-01-15 09:39)
【行业动态|】康佳将OLED电视带到美国与LG和索尼竞争(2020-01-15 09:38)
【行业动态|】2020年最佳AV接收机(2020-01-15 09:35)
【行业动态|】2020年最佳流媒体设备:Roku,Apple TV,Firebar,Chromecast等(2020-01-15 09:31)
【行业动态|】CES 2020预览:更多的流媒体服务和订阅即将到来(2020-01-08 21:41)
【行业动态|】从埃隆·马斯克到杰夫·贝佐斯,这30位人物定义了2010年代(2020-01-01 15:14)
联系我们

Q Q: 7090832

电话:400-0011-990

邮箱:7090832@qq.com

时间:9:00-23:00

联系客服
商家入住 服务咨询 投拆建议 联系客服
0577-67068160
手机版

扫一扫进手机版
返回顶部