这本书的副标题是From Journeyman to Master,中文翻译过来是”从小工到专家”,工作了近十年,回过头来再看这本书,发现这本书虽然从出版到现在已经近20年了,正如作者在09年的再版序言里说的:”Things Really Haven’t Changed That Much”,又一个十年过去了,书中的最佳实践放倒今天依然适用。虽然看副标题是推荐给新手的,但即便是从业多年的再读这本书也会颇有感触和共鸣。书已经有些年了,但亚马逊的书评2016年的都还有很多,里面不仅仅有新手,也有从业20+的架构师和经理。

书的中文名翻译为”程序员修炼之道”,和中文名相去甚远,Pragmatic的中文应该是”务实的”,”务实的程序员”具备如下的一些特征:

而上面这些特征,使得程序员不局限于特定的技术,拥有广博的知识背景和广泛的工程实践经验为基础,才能在特定的情况下选择最好的解决方案。

A Pragmatic Philosophy

这些可以理解为基本修养的要求,涉及到态度,风格和思考问题的方式。

态度

对自己事情负责,永远不要为自己找借口,要去说做什么才能挽回局面,提供其它的选择,并想办法避免再次发生,记住解决问题才是第一位的。

破窗户

不要容忍破窗户。发现一个修一个。

一扇破窗户,只要有那么一段时间不修理,就会渐渐给居民带来一种废弃感,一种职权部门都不关心这座建筑的感觉。于是又一扇窗户破了。人们开始乱扔垃圾。出现了乱涂乱画。严重的结构损坏开始了。在相对较短的一段时间里,建筑就被损毁得超出了业主愿意修理的程度,而废弃感也就变成了现实,有些居民也就搬走了。

同样的道理: 如果团队和项目的代码十分漂亮整洁,设计精良优雅,你也会格外注意不去把它弄脏,也不想成为第一个弄脏东西的人。

石头汤

整个系统就在你的眼前,你知道它是对的,但请求许可去处理整个事情,你会遇到拖延和漠然。大家要设立委员会,预算需要批准,事情会变得复杂,每个人都会守护他们自己的资源。

这就是拿出石头的时候了,在”忽悠”他人加入前,你需要有其他人看的见的东西,”石头汤”本不是什么美味,但它是一个催化剂,有了它,你可以”忽悠”他人说:”如果我们增加……会更好”,来团结其他人来协作,做到单靠他们自己做不到的事情。最后每个人都是赢家。

让人们参与正在发生的成功更容易,让他们瞥见未来,你就能让他们聚集在你周围。

煮青蛙

要持续不断的观察周围发生的事情,而不只是你自己在做的事情。

足够好的软件
不求完美,只求足够好。这里并非意味着不整洁和糟糕的代码而是因为外在的约束条件,使得你需要作出现实的权衡。外在的约束条件包括:

今天了不起的软件常常比明天的完美软件更可取,如果你给用户某样东西,让他们及早适用,他们的反馈常常会把你引向更好的最终解决方案。

知识资产

知识上的投资总能得到最好的回报。知识和经验是你最重要的职业财富,但你要能够区分哪些是有实效的,新技术的出现也许会让那些知识变的过时,而不断变化的市场驱动也许会使得那些经验变的陈旧和无关紧要。知识的价值降低,也直接体现在个人价值上。

知识资产和金融资产的管理有很多相似的地方:

交流

没有有效的交流,一个好的想法就只是一个无人关系的孤儿。你需要了解听众的需要,兴趣和能力。

了解听众的WISDOM法则

Pragmatic Software Development Tips

下面是这本书给出的一些Tips,涵盖了本书所涉及到的所有相关主题。

Care About Your Craft

Why spend your life developing software unless you care about doing it well?

Provide Options, Don’t Make Lame Excuses

Instead of excuses, provide options. Don’t say it can’t be done; explain what can be done.

Be a Catalyst for Change

You can’t force change on people. Instead, show them how the future might be and help them participate in creating it.

Make Quality a Requirements Issue

Involve your users in determining the project’s real quality requirements.

Critically Analyze What You Read and Hear

Don’t be swayed by vendors, media hype, or dogma. Analyze information in terms of you and your project.

DRY—Don’t Repeat Yourself

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

Eliminate Effects Between Unrelated Things

Design components that are self-contained, independent, and have a single, well-defined purpose.

Use Tracer Bullets to Find the Target

Tracer bullets let you home in on your target by trying things and seeing how close they land.

Program Close to the Problem Domain

Design and code in your user’s language.

Iterate the Schedule with the Code

Use experience you gain as you implement to refine the project time scales.

Use the Power of Command Shells

Use the shell when graphical user interfaces don’t cut it.

Always Use Source Code Control

Source code control is a time machine for your work—you can go back.

Don’t Panic When Debugging

Take a deep breath and THINK! about what could be causing the bug.

Don’t Assume It—Prove It

Prove your assumptions in the actual environment—with real data and boundary conditions.

Write Code That Writes Code

Code generators increase your productivity and help avoid duplication.

Design with Contracts

Use contracts to document and verify that code does no more and no less than it claims to do.

Use Assertions to Prevent the Impossible

Assertions validate your assumptions. Use them to protect your code from an uncertain world.

Finish What You Start

Where possible, the routine or object that allocates a resource should be responsible for deallocating it.

Configure, Don’t Integrate

Implement technology choices for an application as configuration options, not through integration or engineering.

Analyze Workflow to Improve Concurrency

Exploit concurrency in your user’s workflow.

Always Design for Concurrency

Allow for concurrency, and you’ll design cleaner interfaces with fewer assumptions.

Use Blackboards to Coordinate Workflow

Use blackboards to coordinate disparate facts and agents, while maintaining independence and isolation among participants.

Estimate the Order of Your Algorithms

Get a feel for how long things are likely to take before you write code.

Refactor Early, Refactor Often

Just as you might weed and rearrange a garden, rewrite, rework, and re-architect code when it needs it. Fix the root of the problem.

Test Your Software, or Your Users Will

Test ruthlessly. Don’t make your users find bugs for you.

Don’t Gather Requirements—Dig for Them

Requirements rarely lie on the surface. They’re buried deep beneath layers of assumptions, misconceptions, and politics.

Abstractions Live Longer than Details

Invest in the abstraction, not the implementation. Abstractions can survive the barrage of changes from different implementations and new technologies.

Don’t Think Outside the Box—Find the Box

When faced with an impossible problem, identify the real constraints. Ask yourself: “Does it have to be done this way? Does it have to be done at all?”

Some Things Are Better Done than Described

Don’t fall into the specification spiral—at some point you need to start coding.

Costly Tools Don’t Produce Better Designs

Beware of vendor hype, industry dogma, and the aura of the price tag. Judge tools on their merits.

Don’t Use Manual Procedures

A shell script or batch file will execute the same instructions, in the same order, time after time.

Coding Ain’t Done ‘Til All the Tests Run

‘Nuff said.

Test State Coverage, Not Code Coverage

Identify and test significant program states. Just testing lines of code isn’t enough.

English is Just a Programming Language

Write documents as you would write code: honor the DRY principle, use metadata, MVC, automatic generation, and so on.

Gently Exceed Your Users’ Expectations

Come to understand your users’ expectations, then deliver just that little bit more.

Think! About Your Work

Turn off the autopilot and take control. Constantly critique and appraise your work.

Don’t Live with Broken Windows

Fix bad designs, wrong decisions, and poor code when you see them.

Remember the Big Picture

Don’t get so engrossed in the details that you forget to check what’s happening around you.

Invest Regularly in Your Knowledge Portfolio

Make learning a habit.

It’s Both What You Say and the Way You Say It

There’s no point in having great ideas if you don’t communicate them effectively.

Make It Easy to Reuse

If it’s easy to reuse, people will. Create an environment that supports reuse.

There Are No Final Decisions

No decision is cast in stone. Instead, consider each as being written in the sand at the beach, and plan for change.

Prototype to Learn

Prototyping is a learning experience. Its value lies not in the code you produce, but in the lessons you learn.

Estimate to Avoid Surprises

Estimate before you start. You’ll spot potential problems up front.

Keep Knowledge in Plain Text

Plain text won’t become obsolete. It helps leverage your work and simplifies debugging and testing.

Use a Single Editor Well

The editor should be an extension of your hand; make sure your editor is configurable, extensible, and programmable.

Fix the Problem, Not the Blame

It doesn’t really matter whether the bug is your fault or someone else’s—it is still your problem, and it still needs to be fixed.

“select” Isn’t Broken

It is rare to find a bug in the OS or the compiler, or even a third-party product or library. The bug is most likely in the application.

Learn a Text Manipulation Language

You spend a large part of each day working with text. Why not have the computer do some of it for you?

You Can’t Write Perfect Software

Software can’t be perfect. Protect your code and users from the inevitable errors.

Crash Early

A dead program normally does a lot less damage than a crippled one.

Use Exceptions for Exceptional Problems

Exceptions can suffer from all the readability and maintainability problems of classic spaghetti code. Reserve exceptions for exceptional things.

Minimize Coupling Between Modules

Avoid coupling by writing “shy” code and applying the Law of Demeter.

Put Abstractions in Code, Details in Metadata

Program for the general case, and put the specifics outside the compiled code base.

Design Using Services

Design in terms of services—independent, concurrent objects behind well-defined, consistent interfaces.

Separate Views from Models

Gain flexibility at low cost by designing your application in terms of models and views.

Don’t Program by Coincidence

Rely only on reliable things. Beware of accidental complexity, and don’t confuse a happy coincidence with a purposeful plan.

Test Your Estimates

Mathematical analysis of algorithms doesn’t tell you everything. Try timing your code in its target environment.

Design to Test

Start thinking about testing before you write a line of code.

Don’t Use Wizard Code You Don’t Understand

Wizards can generate reams of code. Make sure you understand all of it before you incorporate it into your project.

Work with a User to Think Like a User

It’s the best way to gain insight into how the system will really be used.

Use a Project Glossary

Create and maintain a single source of all the specific terms and vocabulary for a project.

Start When You’re Ready

You’ve been building experience all your life. Don’t ignore niggling doubts.

Don’t Be a Slave to Formal Methods

Don’t blindly adopt any technique without putting it into the context of your development practices and capabilities.

Organize Teams Around Functionality

Don’t separate designers from coders, testers from data modelers. Build teams the way you build code.

Test Early. Test Often. Test Automatically.

Tests that run with every build are much more effective than test plans that sit on a shelf.

Use Saboteurs to Test Your Testing

Introduce bugs on purpose in a separate copy of the source to verify that testing will catch them.

Find Bugs Once

Once a human tester finds a bug, it should be the last time a human tester finds that bug. Automatic tests should check for it from then on.

Build Documentation In, Don’t Bolt It On

Documentation created separately from code is less likely to be correct and up to date.

Sign Your Work

Craftsmen of an earlier age were proud to sign their work. You should be, too.