编程漫谈(四):基本功

 

                                                                 ——读《编程珠玑I》有感:

 

 

       Program.Program better. Program faster.

       要从事软件开发,首先要学会编程。如何编程呢?如何编写更高效更优雅的程序呢?《编程珠玑》通过简单而熟悉的示例,揭示了许多非常有益的编程原理和技巧,极具启发性。

 

            基本流程:

            问题定义—— 应用框架与界面设计 —— 选择合适的数据结构和高效的算法(对象和消息)—— 性能估计 —— 接口声明 —— 伪代码 —— 程序验证—— 编码 —— 测试与调试 —— [代码优化]—— 代码重审和回顾。

 

           问题定义:赢在起点。清晰明确的问题描述和定义几乎决定成功的一半。作为问题求解,如何正确地理解问题,从何种视角去思考问题,往往会产生天壤之别的结果;作为软件开发,“有所为而有所不为”,应当作为基本准则。谁都期望能够开发出性能强劲的、多能多才的软件,但并不是谁都能够承受这样的研发成本(时间、资金和人力)。在成本与所能获得的最终产品之间,必须作出合适的权衡和折衷。

          经过良好抽象的问题,更容易得到可复用的问题解决方案。比如,《编程珠玑I》第12章,取样问题,从随机选区列表抽样,抽象成“从n个整数中随机抽取m个有序整数”的问题;这样,问题的解决方案还可以用于其它领域的抽样问题。

 

        应用框架和界面设计:   在明确问题的求解目标之后, 就要思考如何求解问题了。  通常会有一个初步的思想,然后逐渐形成整个比较成熟的方案和应用框架。 与此同时, 定义良好的界面设计也是非常关键的。 在界面之上, 是依靠界面服务的应用程序的实现; 在界面之下, 是用来提供界面服务的数据结构与算法的实现。 

 

           数据结构与算法:掌握一门语言,就可以开始编写程序;而数据结构和算法,则可以帮助写出更为强大的程序。 粗浅地将《编程珠玑》阅读了一遍,发现:计算机程序的根本仍然是: 数据结构 +算法。数据结构和算法通常还是估算和提高系统期望性能的关键环节。

        对象和消息, 实际上是数据结构与算法的封装。 在面向对象程序中, 每一个类都是一些绑定在一起的“小数据结构”和“小算法”的携带者, 通过接口提供自己的服务;每一个对象都是状态携带者, 通过状态的变化来表征系统的变化,从而实现系统的特征和功能。

        数据结构有着非常重要的作用。有时候,复杂的逻辑,只要借助一定的数据视图,就能得到很大的简化,比如日期计算。《编程珠玑I》中谈到的重要数据工具有:超文本、值-对、字典、数据库、表格、模板等。

 

       性能估计:通常,通过算法的大O分析来粗略了解系统可能达到的性能;另外,一定的粗略估算能力也是非常必要的(见编程珠玑第七章):常识、关键参数、经验法则、量纲检验、安全系数。

 

         接口声明:涉及到系统的设计。系统由哪些数据结构(或对象)组成,它们如何进行交互(函数,消息)以完成系统的功能; 仔细定义每一个接口的声明(功能描述、参数列表、返回值、前置条件、后置条件),并使之良好地协作。

 

          伪代码:不要急于编程。使用伪代码来表达思路,勾勒程序的大致框架。这常常也会让思路更明晰:因为在这个过程中,通常可以发现系统有哪些子功能要实现,有利于模块化。

 

          程序验证:你能保证自己编写的程序在任何时候都正确吗?还是仅在你视线所及的范围内正确?你期望写出的程序仅仅是看上去正确吗?当然,我们都希望能够早早完工,可是,急不得,懒不得。学习一定的程序验证技术,也是有益无害的事情。虽然起初可能麻烦一点,但一段时间习惯之后,就不会觉得怎么样了。万事开头难,过了槛就好了。

         程序验证的常用方法:循环不变式和断言。这实际上是根据三种控制流来确立的技术。

 

          编码:终于可以编写程序了。恐怕经过上述折腾,编写程序的兴致早就减得不剩多少了。可是,一切,都是为了编码更加顺利,更加有创造性。总不期望发现,编码就是在Ctrl+C/V;当编码到一定程度时,突然卡了壳;突然发现思路有问题;突然发现性能无法满足所期望的;突然发现,之前的努力都白费了?

           很多人抱怨工作中的编码没有创造性可言,可是,有没有想过,你不去思考如何更有创造力的写程序,难道期望创造性自动跑到你面前吗?你不去努力使用算法、数据结构,难道它会自动跑到你跟前要求你去使用吗?你不去主动思考、勤于发现,难道你就指望奇迹自动降临于身?

          编码时,尽力遵循良好的代码规范,使之可读性良好,为后面的代码重审和回顾打下良好的铺垫。

 

          测试和调试:如何得到一段值得信赖的、可以放心复用的程序呢?苛刻的、彻底的测试。不要怕麻烦。凡事习惯就好了。编写自动化测试;掌握使用断言来进行调试。

        程序测试通常可以分为两种: 自动化测试和手工测试。对于小数据集,0-10,可以构建自动化测试;另外,还要构建手工测试,使得能够对特殊情形进行测试。

 

          代码优化: 代码优化通常意味着性能的小幅提升。通常是应用缓存原理,这需要对计算机组成和操作系统有深入的理解。代码优化通常意味着程序可靠性、可读性和可维护性的降低,程序复杂度的增加;因此要慎重进行。

 

          代码重审和回顾:没有总结就没有进步;“写了代码就丢弃”也不能期望有进步。通过代码重审和回顾,进一步改进代码的质量:可用性、可读性、可扩展性、可移植性、安全性、可靠性。

 

           其它:

 

           大数据集处理问题:初学者可能通常会考虑 1– 100 之内的小数据集处理;但进入到软件开发领域,大数据集处理,海量数据处理,就成了一个必须考虑的问题。对于排序问题来说,当n < 50 ,或许采用插入排序就可以了;但当n等于几百万,几千万时,就不能采用插入排序了。这说明:小数据集的处理方案和大数据集的处理方案往往会是迥然不同的。

 

            实用程序和工具箱:卓越的工匠都会备用自己喜爱的工具箱。程序员也不例外。初学者可能主要在于编程练习;但进入一定阶段之后,就必须考虑编写实用性强的工具和程序,而不是总停留在玩具程序的级别上。

            标准库;实用程序;熟悉的IDE;开源小工具;常用数据结构;算法技术;正则表达式;数据库使用;编程技术;编程技巧;设计思路;问题求解方案;错误录;等等。

 

            自动化重复工作:时常注意日常生活中是否有能够自动化的重复性工作,并通过编写实用程序和工具去简化它。如果当时因为时间来不及,那么,过后也应当尽力补上。

 

            习惯的变革:人天性通常都是“能躺着就不站着”的,因此,培养了很多不好的习惯。程序员呢,通常期望能够快速编写出满足功能的程序,然后运行察看是否如预期,接着便丢到一边不再理会了。什么问题分析、伪代码?什么程序验证、测试?什么代码重审和回顾?都扔到一边去。结果是,你逃掉了一分钟的测试时间,却用了将近一小时调试时间来补偿。划得来吗?

          其实,培养好的习惯,是一种一本万利的投资。只要最初一两个月坚持住,习惯成自然;之后,你便只是尽享好习惯带来的益处了。

 

           从编程到软件开发

            从某种意义上来说,在懂得《数据结构、算法技术、操作系统、组成原理》这些专业知识之后,再加上“勤于思考,善于追根究底”的探索精神,以及大量的编程实践,就可以逐渐掌握编程的基本原理和能力。

           在学会编程之后,就可以阅读关于软件架构的书籍了,理解软件是如何构建起来的。数据库,计算机网络等等,实际上也是通过“编程原理+软件架构”的产物,只是它们可以被用来作为更大系统的组件。

 

posted @ 2014-10-20 19:40  琴水玉  阅读(564)  评论(0编辑  收藏  举报