标签 程序员 下的文章

给新手程序员的建议

本文翻译自Dr. Dobb’s杂志主编Andrew Binstock的"Advice to a new programmer"一文

总是有太多的建议摆在新手程序员面前,以致他们难于选择从何处开始。然而,所有这些建议都是建构在下面这五条实践的基础之上的。

每隔几个月,我就会收到一些勤奋有加的新手程序员的求助,他们希望知道如何才能成为一名真正优秀的程序员。在一些程序员论坛上,我也能看到为数不 少的类似问题,这是一个令人鼓舞的趋势。一些最周全的答案往往与我对这个问题的看法相似,这表明在基础的最佳实践上确实存在着某种一致。因此我下 面的建议并非原创,不过也许我的这些补充会提供给你更进一步的理解。

我印象中的新手程序员基本了解编程的原理,写过程序,但大多规模较小且复杂度不一,致力于某个领域的工作或自己或他人个人项目。

编程工作只有一种真正的基础活动,那就是写代码。要想擅于编程,你就必须编写大量的代码。 大量的工作可能成为一种促进你成长的工具,也可能是一些有限技能的重复练习。为了避免成为后者,你应该做到:

阅读大量代码。尤其是阅读大量由卓越程序员编写的代码。记住:不仅读那些坐在大厅里的优秀程序员的代码,更要读那些卓越程序员的。 在开源软件大行其道的今天,做到这些十分容易。当我学习Java时,我读了Tomcat的代码,读了Cruise Control CI服务器的代码。自从那时起,我已经读了大量优秀的代码。

阅读代码时很容易从main函数开始,但这样一来,你很可能会在初始化以及命令行解析代码上花费大量时间。我更喜欢根据源文件名寻找一些令我感兴 趣的功能实现,然后深入阅读这些源文件。理解整个项目或整体设计的来龙去脉并不是关键,做这些会让你感觉筋疲力尽的。阅读代码。查看注释,弄清楚 作者在做什么以及是如何着手做的。

彻底了解你的工具。我认为损耗编程时间最多的不是调试或重写代码,而是因开发人员对其所使用工具的不熟悉而导致的无数碎片时间的损 耗。我所指的工具包括:集成开发环境(IDE)、编程语言、构建系统以及版本控制系统。其中,集成开发环境和编程语言是到目前为止最为重要的。经 过几个星期的练习,你应该知道集成开发环境中的几乎每个按键组合,这样你只有在为了节省按键时间时才使用鼠标。如果你知道按键组合,你就知道了这 些命令。但如果你只使用鼠标,你只会知道菜单,菜单上面有你倾向于点击的相同的一个或两个条目。因此了解集成开发环境是一种不折不扣的纪律。

了解大型编程语言,诸如Java或C++,需要的不仅仅是纪律。它们自身规模庞大,它们的库亦规模庞大。阅读代码是我认为的了解编程语言最好的方式,阅读 那些使用了你所未知特性的代码并寻找机会使用它们。书籍(而不是博客)是另外一个极好的资料来源。了解你目前正在使用的特性的外围,很快你就会发现外围扩 大了。了解版本控制系统和构建系统将让你成为一个理想的团队成员 — 不会因为对重要操作的无知而浪费时间。

动手编码前先规划好你的代码。我认为这是建议列表中最难做的一项,但同时它也可能给你换来最多的益处。我所指的并不是正式的设计 – 在这个阶段正式设计一般不是必要的。不过你确实应该用一种其他方式精心策划一下代码,而不仅仅是将思路放在脑子里。最简单的方法就是编写一个小文档(我经 常使用的是思维导图):代码的需求是什么?你打算如何实现它?还有哪些目前未知的事情需要去了解?我需要或需要创建什么对象?将这些都写出来。只有在这样 之后开始编码,你才会发现代码变得更加容易编写了,更容易形成文档了,也更容易修改了。将你的笔记保存下来 – 它们将是很好的参考资料。

大量编写代码并进行代码评审。如果你那里不做代码评审,那你就自己来做。找出那些最好的程序员,并且你可以通过某种方式听 到和理解他们给你的有用的建议。别做令人讨厌的人,但也不能因为你害羞,忙碌或自负而回避这个过程。代码评审应该成为你编程人生的一部分。要有创造性。试 试在某个下午与比你更牛的程序员一起做结对编程。重要的是你需要反馈,而这些反馈是你自己无法给予自己的。

编码与写测试并驾齐驱。这也许是这里唯一有争议的一条。它并非是对TDD的认可(译注:测试驱动开发)。但这里要认可的是你的代码 在大多数要面对的场合里都是可以工作的。开始单元测试,并用边缘值测试新代码。例如,当传入一个负数或者是整型数最大值时,你的函数是否还能正常工作?如 果不能,你的函数是否抛出了一个信息详实的异常或只是崩溃退出?如果不是异常,你是否使用了断言(assert)来缩小输入的范围?如果这么做了,那就测 试这个断言。利用之前做的规划编写一些模拟(mock)测试,接下来用这些模拟对象去开始测试你的新代码。这将有助于阐明你当前代码中的设计问题以及即将 实现的对象。保存你的测试代码,在每次签入代码前都运行它们,这些测试将成为后续那些破坏你当前代码的新代码的早期预警系统。

还有许多建议和至理名言可以添加到这个列表中。但这本身就是问题的一部分:过多的建议将导致新手难于知道到底从何处开始。因此,我故意将我的建议缩减到仅 剩五点。如果你能勤奋地运用这五点建议实践,你会很快发现两件事情:你将可以逐步应付更大更重要的任务了,并且当你回首翻看你几个月之前编写的代码时,你 会觉得尴尬。

毫无疑问这两种感受都是你进步的标志。祝你好运!

Python脚本命令行变量的实现

我们知道Make工具是支持命令行变量的,这种手段为我们提供了很好的灵活性,我们可以通过敲入不同的命令行参数来决定Makefile脚本的行为。

make [variable1=value1 variable2=value2 ... ... ]。

#
# Makefile
#

CMODE = 64-bit

ifeq ($(CMODE), 64-bit)
    CFLAGS += -m64
endif
  
all:
    gcc $(CFLAGS) -o foo foo.c

$> make
gcc -m64 -o foo foo.c

$> make CMODE=32-bit
gcc -o foo foo.c

近期我们的一个Python脚本工具也有类似的需求了,但Python脚本原生并不支持这种命令行变量,我们来看看是否可以利用Python提供的机制实现一种可以满足我们需求的命令行变量。

我们的期望结果如下:

$> foo.py fruit=apple

# foo.py

flag = '' #这个定义可以有,也可以没有,如果有,可以理解为默认值

….

if flag == 'apple':
    ….
elif flag == 'orange':
    ….
elif flag == 'banana':
    ….
else:
    ….

Python是动态语言,提供了注入eval、exec等在运行时执行代码的能力。我们要实现命令行变量的机制,离不开这些能力的支持。eval用于求值表达式,而x=y是语句,我们只能用exec。

【#1】

import sys

if __name__ == '__main__':
    c = len(sys.argv)
    if c <= 1:
        print "found zero command variable"
        exit(0)

    exec(sys.argv[1])

    if fruit == 'apple':
        print 'this is apple'
    elif fruit == 'oracle':
        print 'this is orange'
    elif fruit == 'banana':
        print 'this is banana'
    else:
        print 'other fruit'

$> foo.py fruit=apple

Traceback (most recent call last):
  File "./foo.py", line 18, in <module>
    exec(sys.argv[1])
  File "<string>", line 1, in <module>
NameError: name 'apple' is not defined

上面的例子执行后,提示'apple'没有定义。执行foo.py fruit="apple"得到的也是同样的错误。从内部输出来看,无论是fruit=apple还是fruit="apple",exec的参数始终都 是fruit=apple,导致exec抱怨apple这个符号没有定义。

我们打开一个Python命令行交互窗口,做如下测试:

$> python
Python 2.7.3 (default, Aug  1 2012, 05:14:39)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exec("fruit=apple")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'apple' is not defined
>>> exec("fruit='apple'")
>>> fruit
'apple'
>>> exec("num=1")
>>> num
1

通过这个小实验可以看出,我们不能将命令行参数直接原封不动的传给exec,我们要对其进行一下加工,加工的效果如下:

fruit=apple => fruit='apple'
num=1 => num=1

【2】

import sys

def __convert(source):
    (var, sep, val) = source.partition("=")
    if val.isdigit():
        return source
    return  var + "=" + "\'" + val + "\'"

if __name__ == '__main__':
    c = len(sys.argv)
    if c <= 1:
        print "found zero command variable"
        exit(0)

    exec( __convert(sys.argv[1]))

    if fruit == 'apple':
        print 'this is apple'
    elif fruit == 'orange':
        print 'this is orange'
    elif fruit == 'banana':
        print 'this is banana'
    else:
        print 'other fruit'

__convert函数对命令行的参数做了转换,对于数值类的var直接原封不动的返回,否则对于值为字符串的var,将其val用''包裹起来后返回。我们来测试一下新程序:

$> foo.py fruit=apple
this is apple
$> foo.py fruit=orange
this is orange
$> foo.py fruit=watermelon
other fruit

从输出结果来看,我们的预期是达到了^_^。上面的程序只是示例性质的,Python的exec具有运行时执行动态代码的能力,我们在获得这种强大能力的 同时,也面临着巨大的风险。一旦恶意代码从外部传入被exec执行,将带来严重的后果。因此对于exec要执行的代码务必要预先进行必要的形式校验。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats