《The Pragmatic Programmer》读后感
这本书的副标题是From Journeyman to Master,中文翻译过来是”从小工到专家”,工作了近十年,回过头来再看这本书,发现这本书虽然从出版到现在已经近20年了,正如作者在09年的再版序言里说的:”Things Really Haven’t Changed That Much”,又一个十年过去了,书中的最佳实践放倒今天依然适用。虽然看副标题是推荐给新手的,但即便是从业多年的再读这本书也会颇有感触和共鸣。书已经有些年了,但亚马逊的书评2016年的都还有很多,里面不仅仅有新手,也有从业20+的架构师和经理。
书的中文名翻译为”程序员修炼之道”,和中文名相去甚远,Pragmatic的中文应该是”务实的”,”务实的程序员”具备如下的一些特征:
- 乐于尝试新事物,并能和自己已有的知识融合。
- 好奇心,乐于提问,全面的理解更能帮助做出正确的决策。
- 批判的思考,一定要知道为什么要这样做,是否合理。
- 设法理解问题的本质,这样对解决问题所需的投入才会有比较现实的估计。
- 多才多艺,工作要求也许仅仅需要某一方面的能力,但能够主动去熟悉更广泛的技术和环境,才能面对新的挑战。
而上面这些特征,使得程序员不局限于特定的技术,拥有广博的知识背景和广泛的工程实践经验为基础,才能在特定的情况下选择最好的解决方案。
A Pragmatic Philosophy
这些可以理解为基本修养的要求,涉及到态度,风格和思考问题的方式。
态度
对自己事情负责,永远不要为自己找借口,要去说做什么才能挽回局面,提供其它的选择,并想办法避免再次发生,记住解决问题才是第一位的。
破窗户
不要容忍破窗户。发现一个修一个。
一扇破窗户,只要有那么一段时间不修理,就会渐渐给居民带来一种废弃感,一种职权部门都不关心这座建筑的感觉。于是又一扇窗户破了。人们开始乱扔垃圾。出现了乱涂乱画。严重的结构损坏开始了。在相对较短的一段时间里,建筑就被损毁得超出了业主愿意修理的程度,而废弃感也就变成了现实,有些居民也就搬走了。
同样的道理: 如果团队和项目的代码十分漂亮整洁,设计精良优雅,你也会格外注意不去把它弄脏,也不想成为第一个弄脏东西的人。
石头汤
整个系统就在你的眼前,你知道它是对的,但请求许可去处理整个事情,你会遇到拖延和漠然。大家要设立委员会,预算需要批准,事情会变得复杂,每个人都会守护他们自己的资源。
这就是拿出石头的时候了,在”忽悠”他人加入前,你需要有其他人看的见的东西,”石头汤”本不是什么美味,但它是一个催化剂,有了它,你可以”忽悠”他人说:”如果我们增加……会更好”,来团结其他人来协作,做到单靠他们自己做不到的事情。最后每个人都是赢家。
让人们参与正在发生的成功更容易,让他们瞥见未来,你就能让他们聚集在你周围。
煮青蛙
要持续不断的观察周围发生的事情,而不只是你自己在做的事情。
足够好的软件
不求完美,只求足够好。这里并非意味着不整洁和糟糕的代码而是因为外在的约束条件,使得你需要作出现实的权衡。外在的约束条件包括:
- 性能的硬性要求
- 交付时间
- 现金流
今天了不起的软件常常比明天的完美软件更可取,如果你给用户某样东西,让他们及早适用,他们的反馈常常会把你引向更好的最终解决方案。
知识资产
知识上的投资总能得到最好的回报。知识和经验是你最重要的职业财富,但你要能够区分哪些是有实效的,新技术的出现也许会让那些知识变的过时,而不断变化的市场驱动也许会使得那些经验变的陈旧和无关紧要。知识的价值降低,也直接体现在个人价值上。
知识资产和金融资产的管理有很多相似的地方:
- 习惯性的定期投资。
- 多元化,能更好的进行调整,赶上变化。
- 管理风险,学什么,花多少精力去学。
- 低买高卖,在新技术流行前学习就好比买被低估的股票。
- 周期性的评估和平衡资产,批判的思考。
交流
没有有效的交流,一个好的想法就只是一个无人关系的孤儿。你需要了解听众的需要,兴趣和能力。
- 你想说什么
- 了解听众
- 选择时机
- 选择风格
- 让文件美观
- 让听众参与
- 做倾听者
- 回复他人
了解听众的WISDOM法则
- What do they want to learn
- What is their Intrest
- How Sophisticated are they
- How much Detail do they want
- Whom do you want to Own the information
- How can you Motivate them to listen to you
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.