Tip 10Speak Your Language Fluently
White Belt[​​White Belt] You get paid to tell the computer what to do, so you’d best tell it as effectively as possible.

As programmers, we are translators in a way: we take a description of a program expressed in human languages and translate it to a real program expressed in a programming language. Translators must be fluent in both languages to be effective.

Fluency in programming languages is somewhat ill-defined, however. Many books purport to teach you, for example, Java in 21 days. I’ve even seen one that claims to teach Java in 24 hours. Perhaps you could learn the syntax of Java and some of its library calls, but would you call yourself fluent after 24 hours, or even 21 days? No way.

No Shortcuts

A language—or any skill for that matter—takes about 10,000 hours of dedicated practice to reach true competency. Malcolm Gladwell[19] and Peter Norvig[20] both make a compelling case for the 10,000-hour rule. This works out to about ten years for most people.

images/LearningCurve.png

Figure 2. Language/platform learning curve

Within those ten years, the mastery curve looks like Figure 2, Language/platform learning curve. There’s a couple notable points. First, you won’t get far past “Hello World” without hitting a wall of frustration. That’s normal; there’s a base of knowledge you need to assimilate—syntax, libraries, and such—in order to be productive at all. Past that, you hit a plateau of competency where you can putter along and pay the bills but you’re not great. This is the long grind where you’re cutting the grooves in your mind so that you can truly think in that language. If you stick with it, your competency starts taking off again as you reach toward true mastery.

There’s value in sticking with one language, or a set of related languages, through the 10,000-hour mark. With every additional language, you increase your skill as a programmer across the board, but you need to take at least one past 10,000 hours. Consider, by contrast, 1,000 hours of practice in 10 languages: how effective would you be at your job as a beginner in 10 languages?

By the same accord, you need to keep challenging yourself to make those 10,000 hours count. It’s easy to keep yourself challenged at first—everything is a challenge early on—but some people get stuck on that early plateau. Consider the website programmer who builds a site with a shopping cart, then another, then another…twenty web sites later, he’s paying the bills OK, but is he actually learning anything?

Andy Hunt writes in Pragmatic Thinking and Learning [Hun08] that practice requires a well-defined task that’s challenging but doable, feedback on how you’re doing, and the chance to repeat the task (or a similar one) and do better. Many places I’ve worked are good at all but the feedback part. As in Tip 8, Review Code Early and Often, seek out feedback from senior programmers early on to ensure you keep learning.

Idiomatic Programming

Once you get past the initial learning curve of a language’s syntax, you get into learning its style, or its idiom. There’s a maxim that “a good C programmer can write C in any language.” I’ve seen it happen—and in my younger years have been guilty of it myself. What the maxim is getting at is, if you only ever think in terms of C programming, you miss the different ways of thinking that other languages can offer.

For example, consider the following code snippets that all add the numbers in a list. First there’s C and the classic for loop:

SumArray.c
 
int​ a[] = {1, 2, 3, 4, 5};
 
int​ sum = 0;
 
 
for​ (​int​ i = 0; i < ​sizeof​(a) / ​sizeof​(​int​); i++) {
 
sum += a[i];
 
}

You could write largely the same thing in Ruby, but that’s not idiomatic Ruby. In Ruby, you use a block for this kind of thing:

SumArray.rb
 
sum = 0
 
 
[1, 2, 3, 4, 5].each ​do​ |i|
 
sum += i
 
end

But even that’s not truly idiomatic Ruby. The better way is to use Enumerable.inject, which abstracts the concept of combining all elements of a collection:

SumArray.rb
 
sum = [1, 2, 3, 4, 5].inject(:+)

In the same way, C programmers think of chewing through an array in terms of for loops, Ruby programmers think in terms of blocks, and Lisp and Scheme programmers think in terms of recursion. Here’s what the same code would look like in Scheme (without the reduce shortcut):

SumArray.scheme
 
(​define​ (sum-array a)
 
(​if​ (null? a)
 
0
 
(+ (car a) (sum-array (cdr a)))))
 
 
(sum-array (list 1 2 3 4 5))

The idiom of a language moves you toward thinking about your program in the way the language’s designers intended. In languages that are conceptually similar (say, C++ and Java) many idioms are shared where the language’s features overlap. With totally different languages (like C and Scheme shown earlier), you truly need to change your thinking.

There are a couple ways to learn idiomatic programming: first, if there’s a great book on the language, by all means start there; for C that could be The C Programming Language [KR98], and for Scheme I’d read Structure and Interpretation of Computer Programs [AS96]. Study the examples and study why the author writes the code the way they do.

Second, find open source projects written in the language and study them. This can be tricky, because the quality of code in the wild varies wildly. It can range from stupid and buggy to wizardly and incomprehensible. A good resource for small, straightforward code samples is the Rosetta Code[21] website.

Balance Your Productivity with the Machine’s

Programmers often measure their mettle by how fast they can make a program run or how small they can make it. An often repeated example is Andy Hertzfeld rewriting a puzzle game in 1983 from a 6,000-byte Pascal program to a 600-byte assembly language program.[22] This is good fun—for a sufficiently geeky definition of “fun”—and sometimes essential to the job.

Where trouble starts is when programmers think they need to write all programs fast and small. More often than not, the computer’s efficiency is less important than your efficiency. Computers are cheap. Programmers are expensive. It’s therefore a better bet to program using a high-level language and in a clear, straightforward manner.

This is part of why languages like Ruby and Python have become tremendously popular: they allow the programmer to write programs quickly. As long as the program runs fast enough, who cares if it takes longer to run than an assembly language program?

Even Andy Hertzfeld’s story follows this model: he first wrote his puzzle game in Pascal, the highest-level language available on the Macintosh at that time. He wrote the assembly version only when he needed it smaller.

There are some cases, however, where the computer should trump the programmer:

  • Any program that is too slow and can’t be fixed by adding more machines. Some problems can be fixed by running more machines in parallel. (Most web applications fall into this category.) But other problems are inherently sequential. In the latter case, when the sequential part is too slow, you have to rewrite it to go faster.

  • Data sets that can grow to unbounded sizes. When you’re developing a program, you usually test with small data sets so everything fits in memory (possibly even cache) and runs great. If the real-world use of the program could include huge data sets, your design must account for that.

  • Anything in the operating system. System calls get called constantly, and interrupts fire constantly, and it’s the operating system’s job to service them quickly and return control to applications.

Finally, consider the case where some of your program is bound by the computer’s efficiency but most of it is not. Who says all of your program must be written in the same language? The use of hybrid designs is becoming popular. Games, for example, have extreme demands on the machine for their graphics, physics, and audio—this stuff is usually written in C. Games also have a lot of “world logic” like how a switch responds to the player pressing it. There’s no reason to write the latter in C. Many games have started using languages like Lua for their world logic because it’s more efficient for the game designers to work with.[23]

Competitive Advantage

You’ve probably noticed a trend: despite the desire to achieve competency in one programming language, you’ll need to learn more than one in your career. In part, this is because the world keeps moving: the generally accepted languages will change, and you, to be effective, will need to follow. In part this is because you should diversify; a programmer who can work in several languages will find more work than a one-trick pony.

Mastery of at least one low-level language and one high-level language will give you tremendous professional flexibility. In some situations you’re machine-bound, and you’ll need the machine efficiency of a language like C to make the program efficient enough. In other situations you’re programmer-bound, and the increased efficiency of a language like Ruby will help you get the program written quickly.

This all boils down to using the right tool for the job. With several tools at your disposal, you have an advantage over others who stubbornly try to bludgeon every problem into submission using whatever language they learned first. This requires you to learn more—usually on your own time—but it pays off by making you a more effective programmer.

Actions

Well, the 10,000-hour part is going to take a while, isn’t it? For now, let’s focus on your options: take the programming language you know now and one or two that you’re curious about. For best effect, pick languages with very different idioms.

Beyond “Hello World”

First, let’s not write a program that prints “Hello World” to the console. (Well, OK, I bet you already did. “Hello” back.) Here’s your first program: read a file that has an integer on each line. Print the minimum, maximum, mean, and median of the data set. Why? This exercises several basic principles common to many computing tasks: working with IO, iterating over a collection, and doing a little math.

The key goal is to not just make some code work but to write the program in the idiom of the language. As a secondary goal, try this in a test-driven style. For example, you’ll need a function that returns the median of a collection. Write some sample tests for that before writing the actual function. Test-driven development is discussed further in Tip 2, Insist on Correctness.

Sudoku

Ben Laurie comments, Sudoku is “a denial-of-service attack on the human intellect.”[24] That may be so, but it’s also a fun programming puzzle. You need to reason about data, constraints, and search heuristics.

Your task is to write a program that can read a Sudoku grid from a file—with some cells filled in and others blank—and then solve the puzzle and print the result. You can find puzzles online; just search for easy sudoku and so forth. Start with an easy puzzle; the generally accepted standard of easy is that it can be solved without guessing. This should test your solver’s ability to apply the rules of the game.

When you have the rules established, move onto hard puzzles. You’ll need to search (guess) to solve the puzzle, and your choice of search heuristic will have a dramatic impact on the performance of the solver. This is a good opportunity to apply the scientific method: make a hypothesis about a heuristic, and then measure its performance vs. another.

The point of this exercise is partly to give your brain a workout but to also give you a program sufficiently large that idiomatic use of the language starts to pay off—if you’re on the right track, it should feel like you’re using the language right; if you’re not, it should feel like you’re fighting the language. In the latter case, try to find an expert (in-person or online) to help.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.212.212