- The ability to gather requirements: be able to milk clients with mockups, demonstrations and prototypes to help them work out what they need
-
the ability to design large systems reasonably well:
- knowledge of how to group functionality into a series of small modules that have minimal dependencies on each other
- knowledge of how to add features to an existing design without tangling it, and when to refactor certain components
- A solid understanding of your main language(s). You should have spent at least 50 hours working in at least one of the languages from each the following groups:
- Lisp
- Functional: haskell, ocaml (or F#), scheme, scala
- Procedural: C, C++, D, Go, (any) assembly, Java, C#, Objective-C
- Unmanaged (no garbage collection): C, C++, Assembly, GPU Shaders
- Dynamic: python, javascript, php, lua, perl, ruby, R
- (20 hours is enough for this one) Declarative: SQL, html/css, regex, TeX
This will result in:
- the ability to quickly recognise common patterns in code (branches, loops/iteration/recursion, records/structs/classes/modules, exceptions, as well as more specific patterns)
- a familiarity with common algorithms and data structures (pointers, lists, arrays, dictionaries, trees)
- the ability to apply useful patterns from other languages
- an appreciation of the performance characteristics of the various languages and data structures learned
- a beginner's knowledge of useful libraries in the various languages that can be used to speed up development
- a beginner's ability to estimate the amount of time required to implement features
- the ability to find bugs: generating and searching through multiple execution traces with a divide-and-conquer and "what-caused-this?" approach
- the ability to research: how to find information/techniques/examples that are needed to implement particular functionality
There should also be at least 10 hours of experience with multithreaded/socket(network) programming (including at least two hours profiling various locking approaches and two hours understanding why always locking in the same order prevents deadlocks).
-
Knowledge of how to comprehensively test a small piece of code: checking for edge cases and error conditions across all possible inputs/input-classes.
-
Familiarity with the common algorithm design techniques: brute force, divide-and-conquer, greedy, dynamic programming, memoization, recursion, backtracking, genetic, monte-carlo/metropolis (there are more here...)
- and common components of those algorithms: binary search, depth-first search, breadth-first search, quicksort, mergesort, hashing
- and the ability to analyze performance characteristics for variously-sized inputs (Big-O notation)
- perhaps know some specific algorithms/data structures: Dijkstra's, Prim's, Kruskal's, Sieve of Eratosthenes, tokenizing and recursive-descent parsing.. (others: Knight's Tour, 8-Queens, stable marriage, optimal selection, knapsack, topological sorting, b-trees, priority queues, boyer-moore string search, A* search, quadtrees/octrees/kd-trees, travelling salesman, convex hull by divide and conquer, permutation generation, GCD, FFT, more from TAOCP (summary by colin barker [5]))
- An understanding of the common pitfalls of various development methods and how to avoid them
- The ability to communicate/teach, and the ability to learn/be-taught ideas easily
- The ability to design easily-testable code (this comes from writing lots of tests)
- Familiarity with and appreciation of a version control system
- An appreciation of the difficulties of maintenance and reading other programmers' code:
- Data structures with many unrelated members are hard to understand
- Large functions doing multiple things are hard to understand
- Functions causing or relying on side effects are hard to understand
- Badly-named modules/functions/variables are hard to understand
- "Clever"/unusual code without comments is hard to understand
- Poorly-tested code is scary and hard to modify safely
- Code/data structures with many different approaches to using it/them is scary and hard to modify/"fix" safely
The good/"best"/most-useful programmers will _hate_ working with people who are lacking in the above areas, because they cause enormous amounts of avoidable work.
Glaring omissions
- Object-oriented programming: This comes naturally from the other requirements. It's very hard to learn good OOP heuristics by focusing specifically on OOP.
- Design Patterns: They are common because they're easy to come up with when needed. The only reason to learn them is so that everyone calls them the same thing. Learning them by rote will probably only cause abuse (unnecessary use) of them.
Recommended Reading
- The Pragmatic Programmer by Andrew Hunt and David Thomas
- The Art of Computer Programming by Donald Knuth
- Refactoring by Fowler, Beck, Brant, Opdyke and Roberts
Additional Reading
- Effective C++ (C++) by Meyers
- Programming Pearls (C++) by Jon Bentley
- The Algorithm Design Manual
- Introduction to Algorithms by Cormen
- Wikipedia: List of data structures, List of algorithms, Analysis of algorithms
- Applied Cryptography (second edition) by Schneier
References
- stackoverflow: language agnostic skills
- stackoverflow: is-knowing-some-basic-low-level-stuff-essential-to-all-programmers
- stackoverflow: basic algorithms
- stackoverflow: what-algorithms-should-every-developer-know
- hall-of-fame CS problems by Colin Barker
- stackoverflow: essential-math-for-excelling-as-a-programmer
- steve yegge: math for programmers
- steve yegge: get that job at google
No comments:
Post a Comment