Mark24
关于编程的思考
一、背景:
看了《SICP》 前面三章。然后休息了一阵子。首先对抽象的重要意义前三章讲得很好,也有了更深刻的体会。
回顾了Sinatra、Rails、Roda 三个框架的颗粒度,和我在他们之间的思考和徘徊
二、关于编程的思考
1.一切的问题在于编程的一半是人
程序,一方面交给计算机执行,一方面交给人来阅读。
人们编写程序主要目的其实是为了给人阅读,其次的目的是给机器执行。
编程的一半的意义是跟人相关。
人通过书写程序来表达一种思想。编程行为本身是一种表达。创造。所以很多大家都再说,与其说编程像是工程科学,他其实更像艺术。
同样,人也是程序生命周期的一部分。一个程序没有人维护就等同于死掉了。只有人会不断的更新程序,程序也就有了新的生命一样可以持续被改进。
2.抽象的高度自由和人
只要你愿意,你可以在程序的任何维度上面进行抽象。显然不同人有不同的选择。就像一千个人心中有一千个哈姆雷特。不同人的理解和表达,也不见得不容易被别人理解。
你依然可以书写作品被别人理解,交流你的观点。
程序抽象的好坏,其实就是表达的好坏。衡量人的部分就在这里得以体现。
3.抽象和DRY是一切的基础是圣剑的双刃
编程的过程中,可能用到数学、算法理论、机器原理……这些都是认知层面上的东西。
但是只要开始写程序就是表达层面上的东西。
凌驾于任何思想之上的,或者说是一切编程理论的根基,只有两个:
1)抽象 2) DRY
抽象是用来在程序中建立起结构的。
DRY是用来在工程中建立起结构的。
3.1 抽象
抽象就是起名字,通过函数、类封封装,底层就是一个指针的名字。《SICP》中有精彩的描述。抽象建立起抽象层。
有了抽象层,我们就可以像垒砖一样,一层一层构建起复杂的程序。就像一个一个基石可以堆砌成宏伟的金字塔。
“lambda演算”已经揭示了计算是一切的起源。同样和基于状态的图灵机互为等价模型。
抽象是为了屏蔽细节。我不用关心了。
抽象是为了产生新东西。如果没有新东西,不叫抽象。
3.2 DRY
DRY是工程层面上的,或者实现层面上的。为了增加可读性,DRY往往是依托在抽象上而生的。
一切的设计模式、编程原则、如何写出更好的程序的所有实践经验,归根结底逃不出DRY原则。
就是为了更少的重复。更少的改动。最大可能性的不变代码但是可以应对变化本身。
4.如何使用圣剑
圣剑可以斩断一切问题,圣剑有双刃——抽象和DRY
为了不被圣剑反噬。我们必须知道如何控制自己的武器。
1) 抽象
不做没有产生实际价值的抽象。
我为什么喜欢微框架,而且很认可这条路。是因为客观上在你做这件事情开始,抽象并未真正的产生。
大多数你可以使用的框架,他们能解决你的问题,仅仅是一个巧合。
当我们解决的是一个特殊的问题的时候,尤其如此。就像LISP它最终会进化为独一无二解决这个问题的语言。
我们自己的程序也是在走这条路。
所以我们的抽象,应该逐渐的逼近我们的问题而产生。
微框架提供了比较少的负担。
2)DRY
要去除产生的重复。才叫DRY。
如果在我们的发展过程中,从未重复,那何谈DRY呢?
DRY是伴随着问题的产生,持续发生变化的。
微框架的理念把DRY的权利留给你来做。
3)Rails VS Sinatra
正是由于上面两种思考,我反而是反对 Rails。
我非常认可Rails的存在,它积累和凝结了社区的智慧,沉淀了大量实践。挺好,只是我不会去用。
我鼓励Sinatra,因为你要做的东西,和Rails的方向可能是南辕北辙。尤其是新东西。
为什么你要接受你的代码里(框架也是代码的一部分)存在大量的冗余,那些你不理解,你无法控制的各种抽象,各种轮子。
站在我的角度,我们应该细颗粒度控制我们的项目。抽象我们自己的抽象。我们的抽象、DRY做到了自己服务,才会获得真正的自由。
三、反省一个脚手架
sinatra-app-template 是我自己想写的一个框架的雏形。
随着我对编程理解不断的变化,它也在不断地变化。
1) v1.0.0
这时候我想把框架做成一个无所不包的脚手架。包含像Rails一样的特性。最后我设想这里就像一个平台,可以融合很多的rack应用。
反思:
这就是一个错误的、冗余的设计。因为你过度自信了事情的发展方向。 而这种冗余的模板,会带来一大堆没必要的东西。
所以这是一个非常失败的设计。这也是某种很自然的第一直觉。
2)v2.0.0
产生了DRY思想的萌芽。产生了聚合,分职能的规划。对应用的理解出现了bases可继承类。
反省: 一切都恰如其分。但是实际上发展的太复杂了。目录超过了10个。 这是在制造问题,尤其是他们的引用关系。
他们真的有那么多,一切都非常必要么?
很多工作是无用功罢了
3)v3.0.1
我不再觉得我们需要很多app、rack包含在这里。
程序他应该是简单的、纯粹的、组织明确的。
于是程序变成 core+应用本身
一切只为一个应用而生,所有问题根据路由解决。
如果路由无法解决,那你应该新建一个应用产生服务。
这里逐渐提取了config、main_app、core的概念。
反思:
但是依然复杂。复杂在一切设定。复杂在太多的重复、无用的抽象。
比如 class BaseApp
是一个无用的抽象。他没有产生价值。
一个抽象,必须要屏蔽细节。而BaseApp没有真的屏蔽细节,他只是在假装看起来很简单。但是当你要修改的时候,还要跨越2个源码文件查看修改。这个抽象——没有带来新东西。所以这是失败的抽象。
没有带来新东西的抽象——是失败的抽象。
比如 config/boot.rb
处处在声明它。这是个靠声明拖动起来的框架,如果你丢了一个声明。一切无法运行。
这是一个存在大量无用重复代码的模板。
DRY应该切实的消除大量的重复 —— 实实在在的消灭重复
4)v4.0.0
伴随这次思考,应该会更加简单。
只保留有需要的。
开放可以修改的。
减少无用的。
我们应该跳出各种技能、最佳时间、编程最佳思想……枷锁的束缚。
那些只是前人工作经验的总结罢了。
我们要做的是思考和审视我们自己在做的事情。不断地评估他的合理性、抽象、和是否做到了DRY。仅此而已罢了,事情非常简单。
只不过为了这个目标,我们要使用各种办法表达,直到达到我们的目的。
一切就为了做好这件事本身 —— 纯粹的思考。