编程的艺术门槛

编程是门艺术,这个说法由来已久。最近在朱赟的公众号(嘀嗒嘀嗒)读到一篇文章《设计是门逻辑学,然后才是美学》,文中作者漂洋过海追寻艺术,老师却说:“设计不是艺术!”。如果设计都不是艺术,那么编程还能是艺术么?

艺术

那么艺术到底是什么?我一下懵了,发现从来没有想过这个问题,只好求助于 Google。Wikipedia 上的定义是:「艺术是具有智能思考能力的动物(目前其实只有人类吧),借由各种形式及工具借以表达其情感与意识形态,所产生的形态泛称之为艺术。」

而上面那篇文章中老师的观点是:

设计是实现别人的需要,艺术是自我表达的需要。

和 Wikipedia 的说法相近,核心都在于表达。而目前公认的艺术分类,包括八大艺术种类:

  1. 文学
  2. 绘画
  3. 音乐
  4. 舞蹈
  5. 雕塑
  6. 建筑
  7. 戏剧
  8. 电影

它们的共性是这些都是人类自古以来的创造,其中最年轻的艺术门类当属「电影」了,其作品承载了作者的情感和意识形态。而所有被公认的艺术门类,显然它们最终作品呈现出的艺术表达形态更容易被普通人直接的感受到,直接作用于人们的视觉、听觉和触觉感官。

关于编程是一门艺术这个概念,到底什么时候钻入程序员的头脑中的呢?也许来自我们在学习编程的路上,很多讲述编程的书籍都冠以艺术之名,比如:《UNIX编程艺术》,这是一本讲述 Unix 专家们在创造 Unix 过程中形成的理念和文化,那么技术文化是艺术么?还有另一本程序员中的圣经《计算机程序设计艺术》,我们都知道,却几乎没读过。这是一套讲述算法,并基于数学来推导和论证算法的基础书籍,那么算法是艺术么?

编程的直接产物是代码,代码是面向程序员的,而非普罗大众。编程的间接产物是信息产品,在当下这个信息时代,信息产品的形态很多样化,可以是你手机上的 App,也可以是你每晚打开的电视。很可能一切和电子相关的东西,在当下或多或少都和编程有关,但我们发现即使是在这些间接产物中,也找不出一样可以让我们很严肃的把它归为艺术。即使是神化的乔布斯时代,我们给予的最大赞誉也只是苹果的每件产品都像艺术品一般。仅仅是像,像可以无限逼近,但毕竟还不是。

所以相对而言,编程也如设计是实现别人的需要,像我在这写作倒更多是自我表达的需要了。编程受限于程序语言的表达能力,是不可能达到像自然语言的表达能力的,因此编程的艺术性,它的受众也只可能是程序员们。虽然面向大众的艺术,很多大众也表示看不懂,但至少能感受,而编程艺术则是只有程序员本身才可能感受得到了。

技术

程序员的日常编程工作就是编写代码,完成功能,实现别人的需要。在这个过程中不小心就还会制造一些 bug,程序员也不知道这些 bug 是怎么变出来的,就像你天天在家做饭,不知道怎么厨房里就多了那么多小强。美食也不属于公认的艺术门类,但时不时我们会听到美食艺术的说法,这一点倒是和编程艺术很像。但若是你在创造美食的过程,时不时冒出些小强,哪里还有去感受艺术的心思。程序员大部分时候就是在不断的解决源源不绝,生生不息的 bug,这个过程与艺术无关,只与技术有关,技术越练越好,bug 也就越来越少。bug 少到我们能腾出精力和心思,才能去感受编程的艺术性。

编程的艺术源于技术,没有技术则艺术成了无源之水,无根之木。所以那些冠以「艺术」之名的程序书籍其实都是讲的技术或者技术原则与文化。而关于编程最基础的技术当然是写好代码,而如何写好代码这件事以前看过王垠写过的一篇长文《编程的智慧》,其中观点我都认同,包括下面一些方面:

  • 反复推敲代码
  • 写优雅的代码
  • 写模块化的代码
  • 写可读的代码
  • 写简单的代码
  • 写直观的代码
  • 写无懈可击的代码
  • 正确处理错误
  • 正确处理null指针
  • 防止过度工程

文章很长,但花点时间细细读来,必有收获,其中关于推敲代码这点于我感触最深。

看一个作家的水平,不是看他发表了多少文字,而要看他的废纸篓里扔掉了多少。

我觉得同样的理论适用于编程。好的程序员,他们删掉的代码,比留下来的还要多很多。

我曾经自己维护了一个项目,包括一些样板代码,称手的小工具等等。每一年我都会抽业余时间对这个工程做一次重构,一些代码随着技术发展而过时了,一些则被重新实现变得更简洁。每年的一次回顾,对过去自己的审视,对代码的推敲都带来新的成长,这个过程持续了大约七年。

在技术成长到了一定阶段,有些程序员就会开始不满足于仅仅实现别人的需要,也会在代码里尝试自我表达。最基础且最明显的表达是为代码签名,打上自己的标签,要是雷军二十年前没有为那段汇编代码签名,我们今天哪里知道这会是雷军写的,并在这里评头论足。但依然有很多程序员不会为自己的代码签名,连机器生成的代码都会签名说这是自动生成的,而一份没有签名的代码是缺乏艺术最基本的要素「自我」的,永远停留在艺术的门槛之外。

另一些程序员则不止于此,比如 Redis 的作者 @Antirez,你会在 Redis 启动控制后台看到下面的启动画面,这个程序字符精心打印出来的 Logo 无关乎任何功能和别人的需要,只是作者的自我表达而已。

而另外一段代码中,单元测试通过后的输出中每个 case 会有一个笑脸,在调试代码的寂寥中增加点点暖意。

进一步回归到源代码本身,代码同时是主观的和非主观的。编码非主观的方面就包括一些创建好代码必须遵循的「硬」规范:设计模式,项目结构,公共库的使用等等。 虽然这些概念奠定了高质量、可维护代码的基础,但正是程序员间不同的技术与工具的细微差别,微妙的风格选择——对齐方式、命名、空格使用、语境利用、语法高亮和IDE的选择——真正使代码清晰、可维护和容易理解,同时也使得代码更好的表达了其意图、功能和用法。

任何人都可以遵循设计模式或其他一些「硬」规范来编写代码,但有艺术追求的程序员会以自己的方式来填充代码的细节,使代码变得清晰、简洁、易懂。 这很重要,正如每个人都可以从一件艺术品中体会到独一无二的意义,不管代码的架构和设计怎样,每个开发者或代码阅读者可能也会从代码的命名和其他约定习俗中推断出不同的含义。

就像上面一段对得整整齐齐的代码声明块,没有语法或硬性的风格要求程序员要这样写。我只是觉得这样更符合视觉感受,更容易清晰分辨。而这一点 Poul-Henning Kamp 曾在 ACM Queue 发表文章提出了一个迷人的观点:

很多编程语言的风格源自于 ASCII 字符集和基于打字机的终端。编程语言没有利用现代设备的图形属性和选项。虽然代码是按照清晰的英语语法格式编写的,但它并不是英文句子。事实上,它更像数学和表格。

而有时还会有些看起来明显不符合「好」代码规范的代码编写方式。

上面的代码中,if 语句后面把多句代码写在了一行,但从整体上看这样一个短小的方法,其表现形式一下就能让阅读者捕捉到,方法内部有四个分支,每行代码一个分支情况,两种正常分支,两种异常分支。

上面这些随手拈来的例子,都是作者有意为之的选择,正是在这些微妙的个人风格选择中,体现了作者自我的表达。

技艺

单独说编程艺术是不完整的,编程是从技术走向艺术。编程艺术是开在枝头的鲜花,而技术是支撑花朵的枝与根。

而在技术和艺术之间实际存在一道很高的门槛,艺术是一种自我表达,但自我表达却未必是艺术。关于这一点我们说个大家耳熟能详的人——毕加索,他说:

我十多岁就能画的像拉斐尔那么好了。

毕加索到底有没有说过这句话,我没去考证,但他的作品至少说明了一些事实。拉斐尔是文艺复兴时期的写实派画家,他的素描和油画像是下面这样的(图片来自「顾爷」公众号,一个经常谈艺术很有趣的公号)。

而毕加索十多岁时候的素描和油画是下面这样的。

写实是毕加索的绘画基础技术,而其后期的抽象主义才是他的艺术自我表达,两者相辅相成。

虽然,我也不太看得懂毕加索后期的抽象作品,毕加索相对于大众的距离依然比编程相对于大众的距离更近。编程的艺术之花也许就像花中的「满天星」,永远只是配角,只有追寻艺术的程序员方能感受到满天星所营造的那份梦境吧。

编程是完成功能,编程是解决 bug,编程是打磨技能,编程是修炼心性,最后编程才成了艺术。



写点程序世间的文字,画点生活瞬间的画儿。

微信公众号「瞬息之间」,遇见了不妨就关注看看。

时间: 2024-11-04 13:32:09

编程的艺术门槛的相关文章

读《Java并发编程的艺术》(一)

离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督促自己要不断的学习,不断的进步. 最近在进一步学习Java并发编程,不言而喻,这部分内容是很重要的.现在就以<并发编程的艺术>一书为主导线,开始新一轮的学习. 进程和线程 进程是一个应用程序在处理机上的一次执行过程,线程是进程的最小基本单位(个人理解).一个进程可以包含多个线程. 上下文切换 我们

Java并发编程的艺术(六)——线程间的通信

多条线程之间有时需要数据交互,下面介绍五种线程间数据交互的方式,他们的使用场景各有不同. 1. volatile.synchronized关键字 PS:关于volatile的详细介绍请移步至:Java并发编程的艺术(三)--volatile 1.1 如何实现通信? 这两种方式都采用了同步机制实现多条线程间的数据通信.与其说是"通信",倒不如说是"共享变量"来的恰当.当一个共享变量被volatile修饰 或 被同步块包裹后,他们的读写操作都会直接操作共享内存,从而各个

《java并发编程的艺术》读书笔记-第三章Java内存模型(二)

一概述 本文属于<java并发编程的艺术>读书笔记系列,第三章java内存模型第二部分. 二final的内存语义 final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.可以参照之前整理的关键字final.这里作者主要介绍final域的内存语义. 对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序. 初次读一个包含final域的对象的引用,与随后初次读这

基于CAS线程安全的计算方法 java并发编程的艺术上的一个案例

package thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /**  * @author  changxiangxiang  * @date 2014年8月6日 下午3:25:12  * @description  * @since  sprint2  */ public class Counter {     privat

&lt;java并发编程的艺术&gt;读书笔记-第三章java内存模型(一)

一概述 本文属于<java并发编程的艺术>读书笔记系列,继续第三章java内存模型. 二重排序 2.1数据依赖性 如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性.数据依赖分下列三种类型: 名称 代码示例 说明 写后读 a = 1;b = a; 写一个变量之后,再读这个位置. 写后写 a = 1;a = 2; 写一个变量之后,再写这个变量. 读后写 a = b;b = 1; 读一个变量之后,再写这个变量. 上面三种情况,只要重排序两个操作的执行顺序,

Java并发编程的艺术——互动出版网

这篇是计算机类的优质预售推荐>>>><Java并发编程的艺术> 阿里系和1号店资深技术专家撰写,Java并发编程领域的扛鼎之作,内容在InfoQ等社群得到高度认可,从JDK源码.JVM.CPU等多角度全面剖析与讲解Java并发编程的框架.原理和核心技术 编辑推荐 阿里系和1号店资深技术专家撰写,Java并发编程领域的扛鼎之作 内容在InfoQ等社群得到高度认可,从JDK源码.JVM.CPU等多角度全面剖析与讲解Java并发编程的框架.原理和核心技术 前言 为什么要写这本

Java并发编程的艺术,解读并发编程的优缺点

并发编程的优缺点 使用并发的原因 多核的CPU的背景下,催生了并发编程的趋势,通过并发编程的形式可以将多核CPU的计算能力发挥到极致,性能得到提升. 在特殊的业务场景下先天的就适合于并发编程. 比如在图像处理领域,一张1024X768像素的图片,包含达到78万6千多个像素.即时将所有的像素遍历一边都需要很长的时间, 面对如此复杂的计算量就需要充分利用多核的计算的能力.又比如当我们在网上购物时,为了提升响应速度,需要拆分,减库存, 生成订单等等这些操作,就可以进行拆分利用多线程的技术完成. 面对复

《Java并发编程的艺术》之ConcurrentLinkedQueue

队列这个数据结构已经很熟悉了,就不多介绍,主要还是根据代码理解Doug Lea大师的一些其他技巧. 入队 如图所示,很多人可能会很疑惑,为什么第一次入队后,TAIL没有指向Node2?答案是为了效率!Σ(っ °Д °;)っ 那这还能叫队列吗?当然,它依然符合先进先出(FIFO)的规则.只是TAIL变量不一定指向尾结点,那么来看看大师是怎么做的. public boolean offer(E e) { checkNotNull(e); final Node<E> newNode = new No

Java并发编程的艺术下载 &#155949;

下载地址: http://www.gqylpy.com/di/11 <Java并发编程的艺术>PDF高清完整版-下载 内容简介 并发编程领域的扛鼎之作,作者是阿里和1号店的资深Java技术专家,对并发编程有非常深入的研究,<Java并发编程的艺术>是他们多年一线开发经验的结晶.本书的部分内容在出版早期发表在Java并发编程网和InfoQ等技术社区,得到了非常高的评价.它选取了Java并发编程中核心的技术进行讲解,从JDK源码.JVM.CPU等多角度全面剖析和讲解了Java并发编程的