Thursday, April 21, 2016

How to Be a Better Programmer - Part 3


http://www.yacoset.com/Hoe/signs-that-you-re-a-good-programmer
http://blog.jobbole.com/87799/

1. The instinct to experiment first

The compiler and runtime can often answer a question faster than a human can. Rather than seek out a senior programmer and ask them "will it work if I do this?", a good programmer will just try it and see if it works before bringing their problem to someone else.
  1. 代码还没运行就能预知其中的 bug。

2. Emotional detachment from code and design

Code is like kleenex: you use it when it's useful and throw it away when it no longer serves. We all like to think that code-reuse is important, and while it is, it's not meant to be about raising a child. Code doesn't feel. Code doesn't care. Code will turn on you like a Frankenstein monster. Code is just bytes. Code is a liability.

Symptoms

  1. Almost no committed code that is commented out
  2. Willingly throws away weeks or months of work in order to adopt another programmer's superior code
  3. Puts finger to lips, furrows brow and says "hmm" when faults in their work are pointed out, while looking at the code and not the critic
  4. Indifferent to the way the IDE wants to auto-format code, uninterested in "tabs-vs-spaces" arguments
  5. Refers to it as "the code" rather than "my code", unless accepting blame
  6. Has abandoned a design of theirs that was previously used in a successful product
  7. Doesn't become defensive when the boss mentions that they're looking for an off-the-shelf alternative to what they've been writing for the past few years

it's you who controls the idea, not the idea that controls you.

Find the code that you're the most proud of and delete it, now re-write it from scratch in a different way. Use a "design pattern" that confuses you, or that you hate (e.g.: the Singleton) and figure out how to make it work. If necessary, delete that after you've got it working and try again with a new pattern or language. Not only will you learn that there's More Than One Way To Do It, but you'll learn that your code is transitory. Code, by its nature, is not just inextricably glued to its language, platform, and the APIs it consumes, but written in the form of ephemeral static charges, orientations of magnetic particles, subject to the whims of the market, Moore's Law, and your employer.

Other techniques to break the abusive relationship:
  1. Maintain somebody else's code
  2. Experience, either by accident or bloody intention, what it's like to lose a week's work to a failed backup or a botched commit and have to re-write it all over again
  3. Work for start-ups where you'll get laid-off when the second or third round of financing doesn't come through
  4. Be stupid enough to post your best code on Reddit

3. Eager to fix what isn't broken

Programs are infrastructure: they're built to serve a specific need, but needs always change. Good programmers realize that hard-coded values buried in code are bad, that a destoryBaghdad() function is immoral, and that it's a priority to eliminate "code smells". Not for pride. Not for backslapping attaboys from your peers or the authors of methodology books. But because you will itch until it is fixed.

  1. Doesn't take the spec by its word and tries to find out who wrote it and what they were thinking
  2. Hunts down and talks to the people who will use the program each day
  3. Owns a book written by a guy called Martin Fowler
  4. Tends to express extreme like or dislike for popular technologies such as XML, ORM and REST, and has also switched positions on one or more of these in the past
  5. Likes to use abstraction layers, but doesn't like to add more than one layer on top of what's already in the language or platform
  6. Talks about "low cohesion"
  7. At least 10% or more of their commits reduce the line-count of the project without adding new functionality
  8. Before adding a new feature, checks to see if an existing one can be re-designed to perform both tasks or replaced entirely with a better method
Code lets you learn in stages where you don't need to re-write everything from scratch. You re-write pieces after you understand what they need to do and what they'll never need to do, make them simpler, shorter and beautiful.

Aim for these, in increasing order of importance:
  1. Code that does the same thing, but is shorter or more efficient
  2. Code that does the same thing, but uses an appropriate "wheel" built-into the platform instead of reinventing its own
  3. Code that does the same thing, but is easier to modify for similar needs
  4. Code that does the same thing, but is easier to read and understand
  5. Code that doesn't exist

4. Fascinated by the incomprehensible


5. Compelled to teach

  1. Blogs about their work
  2. Has an active Wikipedia account
  3. Unhesitant to pick up a marker and approach a whiteboard
  4. Commits changes to the repository that consist only of comments
  5. Lets new hires borrow books that cost them $100 to buy

1. Incorruptible patience

  1. Unbothered by office politics
  2. Can predict a bug before the code is ever run

2. A destructive pursuit of perfection

3. Encyclopedic grasp of the platform

Encyclopedic knowledge takes decades to acquire, but every Guru in the world got there by doing roughly the same three things each day:
  1. Struggling to solve problems they find to be difficult
  2. Writing about how they solved difficult problems
  3. Reflecting on how they solved difficult problems

4. Thinks In Code

5. When In Rome, Does As Romans Do

  1. No automatic interest in cross-platform frameworks
  2. Contemptuous of "language wars"
  3. Doesn't see a strategic disadvantage in maintaining the same program in multiple languages
  4. Assumes their own code is the source of a bug before blaming the compiler, library or operating system
  5. Displays a plush Tux penguin or Android in their cubicle soon after being assigned to a project targeting that platform
  6. Switches brand of cell phone or tablet in the same circumstance
  7. Hits a stack of technical manuals before assuming a data-type like double or decimal will do what they think on a new device

6. Creates their own tools

  1. Has set up an automated build server
  2. Has written their own benchmark or specialized profiler
  3. Maintains an open-source project on GitHub
  4. Has re-invented LISP at least once
  5. Knows what a Domain Specific Language is, and has designed and written an interpreter for one
  6. Extends their IDE/Editor with custom macros

Signs that you're destined for more

1. Indifferent to Hierarchy

Richard Feynman once pointed out that "it doesn't matter who your dad knows", if something is wrong then it's wrong no matter who says its right. Don't fear the consequences to your career, you''ll find another job. Society never wastes real talent.
  1. Getting into arguments with the CEO
  2. Quitting on principle
  3. Organizing teams without permission
  4. Creating new products after-hours while hiding from the Rent-a-Cops
  5. Re-organizing the workspace "Peopleware" style, against company policy
  6. Helps themselves to the boss's private stash of bottled water

2. Excited by failure

3. Indifferent to circumstances

  1. Stock options and bonuses are ineffective retainment techniques
  2. Cashes-in their 401k to fund their next venture

4. Unswayed by obligations

5. Substitutes impulse for commitment

6. Driven by experiences

The idea of recursion is easy enough to understand, but programmers often have problems imagining the result of a recursive operation in their minds, or how a complex result can be computed with a simple function. This makes it harder to design a recursive function because you have trouble picturing "where you are" when you come to writing the test for the base condition or the parameters for the recursive call.

Symptoms

  1. Hideously complex iterative algorithms for problems that can be solved recursively (eg: traversing a filesystem tree), especially where memory and performance is not a premium
  2. Recursive functions that check the same base condition both before and after the recursive call
  3. Recursive functions that don't test for a base condition
  4. Recursive subroutines that concatenate/sum to a global variable or a carry-along output variable
  5. Apparent confusion about what to pass as the parameter in the recursive call, or recursive calls that pass the parameter unmodified
  6. Thinking that the number of iterations is going to be passed as a parameter

Remedies

Get your feet wet and be prepared for some stack overflows. Begin by writing code with only one base-condition check and one recursive call that uses the same, unmodified parameter that was passed. Stop coding even if you have the feeling that it's not enough, and run it anyway. It throws a stack-overflow exception, so now go back and pass a modified copy of the parameter in the recursive call. More stack overflows? Excessive output? Then do more code-and-run iterations, switching from tweaking your base-condition test to tweaking your recursive call until you start to intuit how the function is transforming its input. Resist the urge to use more than one base-condition test or recursive call unless you really Know What You're Doing.
Your goal is to have the confidence to jump in, even if you don't have a complete sense of "where you are" in the imaginary recursive path. Then when you need to write a function for a real project you'd begin by writing a unit test first, and proceeding with the same technique above.

5.难以看透递归

递归的思想很容易理解,但程序猿们经常在自己脑子里想象一次递归操作的结果时遇到困难,或想不通一个简单函数是怎么计算出复杂结果的。这些不解使得要设计一个递归函数变得难上加难,因为当你要对初始条件或递归调用的参数进行测试时,你想象不出“当前走到哪一步了”。
特征
  1. 对问题设计极其复杂的迭代算法,但其实可以通过递归解决(比如:遍历一个文件系统树),尤其是在不用保证内存和性能的情况下。
  2. 递归函数在递归调用前后都会检查相同的初始条件。
  3. 递归函数没有测试初始条件。
  4. 递归子程序连接到一个全局变量或支持输出的变量上,或者累计这些变量的和。
  5. 对于递归调用中要传递什么参数表现出明显的困惑,或是不理解传递未修改参数的递归调用。
  6. 认为迭代的次数会被作为参数传递。
补救措施
先体会一下,准备好迎接某种堆栈溢出吧。首先,在代码里只写一个初始条件检测并只调用一次递归,递归中使用同一个被传递的未修改参数。即使你觉得写得不够好也要停下来,无论如何,让代码运行一下。它抛出了一个堆栈溢出的异常,那么现在返回去继续写,在递归调用中传递参数的已修改拷贝。产生了更多的堆栈溢出错误?输出过度?那就接着反复修改代码再运行,从修改初始条件测试转向修改递归调用,直到你开始凭直觉就知道函数怎么转换它的输入参数。忍住冲动,使用的初始条件测试或递归调用不要超过一次,除非你真的知道自己在做什么
你的目标是勇于进行递归调用,即使在这条想象中的递归路径上,你没有完全搞清楚“自己在哪里”。那么,等你需要为一个真正的项目去写一个函数时,你会从写单元测试开始,并且运用上面提到的相同技术来一步步推进。

2. Lack of critical thinking

Unless you criticize your own ideas and look for flaws in your own thinking, you will miss problems that can be fixed before you even start coding. If you also fail to criticize your own code once written, you will only learn at the vastly slower pace of trial and error. This problem originates in both lazy thinking and egocentric thinking, so its symptoms seem to come from two different directions.
Start with a book like Critical Thinking by Paul and Elder, work on controlling your ego, and practice resisting the urge to defend yourself as you submit your ideas to friends and colleagues for criticism.

Once you get used to other people examining your ideas, start examining your own ideas yourself and practice imagining the consequences of them. In addition, you also need to develop a sense of proportion (to have a feel for how much design is appropriate for the size of the problem), a habit of fact-checking assumptions (so you don't overestimate the size of the problem), and a healthy attitude towards failure.
Finally, you must have discipline. Being aware of flaws in your plan will not make you more productive unless you can muster the willpower to correct and rebuild what you're working on.

4. Unfamiliar with the principles of security

Symptoms

  1. Storing exploitable information (names, card numbers, passwords, etc.) in plaintext
  2. Storing exploitable information with ineffective encryption (symmetric ciphers with the password compiled into the program; trivial passwords; any "decoder-ring", homebrew, proprietary or unproven ciphers)
  3. Programs or installations that don't limit their privileges before accepting network connections or interpreting input from untrusted sources
  4. Not performing bounds checking or input validation, especially when using unmanaged languages
  5. Constructing SQL queries by string concatenation with unvalidated or unescaped input
  6. Invoking programs named by user input
  7. Code that tries to prevent an exploit from working by searching for the exploit's signature
  8. Credit card numbers or passwords that are stored in an unsalted hash

Remedies

The following only covers basic principles, but they'll avoid most of the egregious errors that can compromise an entire system. For any system that handles or stores information of value to you or its users, or that controls a valuable resource, always have a security professional review the design and implementation.
Begin by auditing your programs for code that stores input in an array or other kind of allocated memory and make sure it checks that the size of the input doesn't exceed the memory allocated for storing it. No other class of bug has caused more exploitable security holes than the buffer overflow, and to such an extent that you should seriously consider a memory-managed language when writing network programs, or anywhere security is a priority.
Next, audit for database queries that concatenate unmodified input into the body of a SQL query and switch to using parameterized queries if the platform supports it, or filter/escape all input if not. This is to prevent SQL-injection attacks.
After you've de-fanged the two most infamous classes of security bug you should continue thinking about all program input as completely untrustworthy and potentially malicious. It's important to define your program's acceptable input in the form of working validation code, and your program should reject input unless it passes validation so that you can fix exploitable holes by fixing the validation and making it more specific, rather than scanning for the signatures of known exploits.
Going further, you should always think about what operations your program needs to perform and the privileges it'll need from the host to do them before you even begin designing it, because this is the best opportunity to figure out how to write the program to use the fewest privileges possible. The principle behind this is to limit the damage that could be caused to the rest of the system if an exploitable bug was found in your code. In other words: after you've learned not to trust your input you should also learn not to trust your own programs.
The last you should learn are the basics of encryption, beginning with Kerckhoff's principle. It can be expressed as "the security should be in the key", and there are a couple of interesting points to derive from it.
The first is that you should never trust a cipher or other crypto primitive unless it is published openly and has been analyzed and tested extensively by the greater security community. There is no security in obscurity, proprietary, or newness, as far as cryptography goes. Even implementations of trusted crypto primitives can have flaws, so avoid implementations you aren't sure have been thoroughly reviewed (including your own). All new cryptosystems enter a pipeline of scrutiny that can be a decade long or more, and you want to limit yourself to the ones that come out of the end with all their known faults fixed.
The second is that if the key is weak, or stored improperly, then it's as bad as having no encryption at all. If your program needs to encrypt data, but not decrypt it, or decrypt only on rare occasions, then consider giving it only the public key of an asymmetric cipher key pair and making the decryption stage run separately with the private key secured with a good passphrase that the user must enter each time.
The more is at stake, then the more homework you need to do and the more thought you must put into the design phase of the program, all because security is the one feature that dozens, sometimes millions of uninvited people will try to break after your program has been deployed.
The vast majority of security failures traceable to code have been due to silly mistakes, most of which can be avoided by screening input, using resources conservatively, using common sense, and writing code no faster than you can think and reason about it.


1. 不断学习
程序员的学习从Google开始。一遇到问题就求助于同事的程序员不仅会让正在紧张工作的同事感到反感而且还易养成依赖的坏毛病。正确的解惑姿势应该是擅用身边最大的资源器——搜索引擎,它检索的出来的信息远比你周围的同事能提供给你的多得多。

不断接受新的技术。程序员是一个非常残忍的职业。你所学所用的语言、框架、模式,很可能在数年内就成昨日黄花了。所以除了技术的深度之外,想成为优秀程序员的你还需要重视技术的广度,C语言、Java、PHP、C++、Perl….总之,越大越好。

阅读大量别人的代码。提升编程技能的一个鲜为人知的方法就是阅读大量别人编写的代码,吐槽的同时边阅读边思考:如果换成我应该如何编写这部分代码?这段代码是否还有可优化的空间?如何优化?这项技术如何应用在我过去已经编写的代码中?

2. 突发事件处理
斑斑一向认为如何处理bug、崩溃、调优、入侵等突发事件是比编程本身更能考验程序员能力的,也是一般程序员和优秀程序员的根本差距所在。当面对一个未知的问题时,你如何抽丝剥茧地分析问题的潜在原因、如何一点一点的排除干扰项找到问题的本源、如何选择最合适的解决方案,都是衡量一个程序员是否优秀的重要标准。一个优秀的程序员会用尽一切方法让事情前进。
3. 重视代码注释
如果你看自己三个月前写的代码,也许你能够凭借自己写代码的习惯和记忆中这段代码的运行结果而想明白当初自己为什么要这么写,但如果你看的是自己三年前写的代码,恐怕就没有这么好的运气了,这个时候你就需要注释来帮忙了。优秀的程序员不止代码是优秀的,注释也同样。简洁的代码配上详尽的注释,完美的简直不要不要的。
4. 学会与人沟通
沟通无处不在,而且不可避免,一个优秀程序员的沟通绝不是简单的和策划、产品经理讨价还价,而是善于运用沟通的技巧更精确的表达出自己的立场。斑斑一直认为沟通也是编写代码的一部分,沟通出问题势必会影响代码的编写质量,使最终的呈现结果出现瑕疵。立志成为优秀程序员的你绝不会被区区沟通所打败,不是吗


5. 习惯优化代码

“代码能跑”可不是优秀程序员编程的终极目标,编程人员工作的第一步就是编写出符合要求的代码,但这也仅仅只是第一步而已。作为一名优秀的的程序员,你需要经常性地进行代码优化,把自己编写的代码当成是一件艺术品,精益求精。如果真的有让你忍无可忍的代码,麻烦请重构。

6. 热爱分享

7. 社区意识


No comments:

Post a Comment

Labels

Review (554) System Design (293) System Design - Review (189) Java (178) Coding (75) Interview-System Design (65) Interview (60) Book Notes (59) Coding - Review (59) to-do (45) Knowledge (39) Linux (39) Interview-Java (35) Knowledge - Review (32) Database (30) Design Patterns (29) Product Architecture (28) Big Data (27) Soft Skills (27) Miscs (25) MultiThread (25) Concurrency (24) Cracking Code Interview (24) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Distributed (20) Interview Q&A (20) OOD Design (20) System Design - Practice (19) Security (17) Algorithm (15) How to Ace Interview (15) Brain Teaser (14) Google (13) Linux - Shell (13) Spark (13) Spring (13) Code Quality (12) How to (12) Interview-Database (12) Interview-Operating System (12) Redis (12) Tools (12) Architecture Principles (11) Company - LinkedIn (11) Testing (11) Resource (10) Solr (10) Amazon (9) Cache (9) Search (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Company - Uber (8) Interview - MultiThread (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Scalability (8) Cassandra (7) Git (7) Interview Corner (7) JVM (7) Java Basics (7) Machine Learning (7) NoSQL (7) C++ (6) Design (6) File System (6) Highscalability (6) How to Better (6) Kafka (6) Network (6) Restful (6) Trouble Shooting (6) CareerCup (5) Code Review (5) Company - Facebook (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Be Architect (4) Big Fata (4) C (4) Company Product Architecture (4) Data structures (4) Design Principles (4) Facebook (4) GeeksforGeeks (4) Generics (4) Google Interview (4) Hardware (4) JDK8 (4) Optimization (4) Product + Framework (4) Shopping System (4) Source Code (4) Web Service (4) node.js (4) Back-of-Envelope (3) Company - Pinterest (3) Company - Twiiter (3) Company - Twitter (3) Consistent Hash (3) GOF (3) Game Design (3) GeoHash (3) Growth (3) Guava (3) Interview-Big Data (3) Interview-Linux (3) Interview-Network (3) Java EE Patterns (3) Javarevisited (3) Map Reduce (3) Math - Probabilities (3) Performance (3) Puzzles (3) Python (3) Resource-System Desgin (3) Scala (3) UML (3) geeksquiz (3) AI (2) API Design (2) AngularJS (2) Behavior Question (2) Bugs (2) Coding Interview (2) Company - Netflix (2) Crawler (2) Cross Data Center (2) Data Structure Design (2) Database-Shard (2) Debugging (2) Docker (2) Elasticsearch (2) Garbage Collection (2) Go (2) Hadoop (2) Html (2) Interview - Soft Skills (2) Interview-Miscs (2) Interview-Web (2) JDK (2) Logging (2) POI (2) Papers (2) Programming (2) Project Practice (2) Random (2) Software Desgin (2) System Design - Feed (2) Thread Synchronization (2) Video (2) ZooKeeper (2) reddit (2) Ads (1) Advanced data structures (1) Algorithm - Review (1) Android (1) Approximate Algorithms (1) Base X (1) Bash (1) Books (1) C# (1) CSS (1) Chrome (1) Client-Side (1) Cloud (1) CodingHorror (1) Company - Yelp (1) Counter (1) DSL (1) Dead Lock (1) Difficult Puzzles (1) Distributed ALgorithm (1) Eclipse (1) Facebook Interview (1) Function Design (1) Functional (1) GoLang (1) How to Solve Problems (1) ID Generation (1) IO (1) Important (1) Internals (1) Interview - Dropbox (1) Interview - Project Experience (1) Interview Tips (1) Interview-Brain Teaser (1) Interview-How (1) Interview-Mics (1) Interview-Process (1) Jeff Dean (1) Joda (1) LeetCode - Review (1) Library (1) LinkedIn (1) LintCode (1) Mac (1) Micro-Services (1) Mini System (1) MySQL (1) Nigix (1) NonBlock (1) Process (1) Productivity (1) Program Output (1) Programcreek (1) Quora (1) RPC (1) Raft (1) RateLimiter (1) Reactive (1) Reading (1) Reading Code (1) Refactoring (1) Resource-Java (1) Resource-System Design (1) Resume (1) SQL (1) Sampling (1) Shuffle (1) Slide Window (1) Spotify (1) Stability (1) Storm (1) Summary (1) System Design - TODO (1) Tic Tac Toe (1) Time Management (1) Web Tools (1) algolist (1) corejavainterviewquestions (1) martin fowler (1) mitbbs (1)

Popular Posts