Изменить стиль страницы

GOOD DESIGN IS OFTEN DARING. At every period of history, people have believed things that were just ridiculous, and believed them so strongly that you risked ostracism or even violence by saying otherwise.

If our own time were any different, that would be remarkable. As far as I can tell it isn't.

This problem afflicts not just every era, but in some degree every field. Much Renaissance art was in its time considered shockingly secular: according to Vasari, Botticelli repented and gave up painting, and Fra Bartolommeo and Lorenzo di Credi actually burned some of their work. Einstein's theory of relativity offended many contemporary physicists, and was not fully accepted for decades—in France, not until the 1950s.

Today's experimental error is tomorrow's new theory. If you want to discover great new things, then instead of turning a blind eye to the places where conventional wisdom and truth don't quite meet, you should pay particular attention to them.

In practice I think it's easier to see ugliness than to imagine beauty. Most of the people who've made beautiful things seem to have done it by fixing something they thought ugly. Great work usually seems to happen because someone sees something and thinks, I could do better than that . Giotto saw traditional Byzantine madonnas painted according to a formula that had satisfied everyone for centuries, and to him they looked wooden and unnatural. Copernicus was so troubled by a hack that all his contemporaries could tolerate that he felt there must be a better solution.

Intolerance for ugliness is not in itself enough. You have to understand a field well before you develop a good nose for what needs fixing. You have to do your homework. But as you become expert in a field, you'll start to hear little voices saying, What a hack! There must be a better way. Don't ignore those voices. Cultivate them. The recipe for great work is: very exacting taste, plus the ability to gratify it.

Chapter 10. Programming Languages Explained

Any machine has a list of things you can tell it to do. Sometimes the list is short. There are only two things I can do to my electronic kettle: turn it on and turn it off. My CD player is more complicated. As well as turning it on and off, I can turn the volume up and down, tell it to play or pause, move back or forward one song, and ask it to play songs in random order.

Like any other kind of machine, a computer has a list of things it can do. For example, every computer can be told to add two numbers. The complete list of things a computer can do is its machine language.

10.1. Machine Language

When computers were first invented, all programs had to be written as sequences of machine language instructions. Soon after, they started to be written in a slightly more convenient form called assembly language . In assembly language the list of commands is the same, but you get to use more programmer-friendly names. Instead of referring to the add instruction as 11001101, which is what the machine might call it, you get to say add.

The problem with machine/assembly language is that most computers can only do very simple things. For example, suppose you want to tell a computer to beep 10 times. There's not likely to be a machine instruction to do something n times. So if you wanted to tell a computer to do something 10 times using actual machine instructions, you'd have to say something equivalent to:

put the number 10 in memory location 0

a if location 0 is negative, go to line b

beep

subtract 1 from the number in location 0

go to line a

b ...rest of program...

If you have to do this much work to make the machine beep 10 times, imagine the labor of writing something like a word processor or a spreadsheet.

And by the way, take another look at the program. Will it actually beep ten times? Nope, eleven. In the first line I should have said 9 instead of 10. I deliberately put a bug in our example to illustrate an important point about languages. The more you have to say to get something done, the harder it is to see bugs.

10.2. High-Level Languages

Imagine you had to produce assembly language programs, but you had an assistant to do all the dirty work for you. So you could just write something like

dotimes 10 beep

and your assistant would write the assembly language for you (but without bugs).

In fact, this is how most programmers do work. Except the assistant isn't a person, but a compiler . A compiler is a program that translates programs written in a convenient form, like the one liner above, into the simple-minded language that the hardware understands.

The more convenient language that you feed to the compiler is called a highlevel language . It lets you build your programs out of powerful commands, like "do something n times" instead of wimpy ones like "add two numbers."

When you get to build your programs out of bigger concepts, you don't need to use as many of them. Written in our imaginary high-level language, our program is only a fifth as long. And if there were a mistake in it, it would be easy to see.

Another advantage of high-level languages is that they make your programs more portable . Different computers all have slightly different machine languages. You cannot, as a rule, take a machine language program written for one computer and run it on another. If you wrote your programs in machine language, you'd have to rewrite them all to run them on a new computer. If you use a high-level language, all you have to rewrite is the compiler.

Compilers aren't the only way to implement high-level languages. You could also use an interpreter , which examines your program one piece at a time and executes the corresponding machine language commands, instead of translating the whole thing into machine language and running that.

10.3. Open Source

The high-level language that you feed to the compiler is also known as source code , and the machine language translation it generates is called object code. When you buy commercial software, you usually only get the object code. (Object code is so hard to read that it is effectively encrypted, thus protecting the company's trade secrets.) But lately there is an alternative approach: open source software, where you get the source code as well, and are free to modify it if you want.

There is a real difference between the two models. Open source gives you a lot more control. When you're using open source software and you want to understand what it's doing, you can read the source code and find out. If you want, you can even change the software and recompile it.

One reason you might want to do that is to fix a bug. You can't fix bugs in Microsoft Windows, for example, because you don't have the source code. (In theory you could hack the object code, but in practice this is very hard. It's also probably forbidden by the license agreement.) This can be a real problem. When a new security hole is discovered in Windows, you have to wait for Microsoft to release a fix. And security holes at least get fixed fast. If the bug merely paralyzes your computer occasionally, you may have to wait till the next full release for it to be fixed.

But the advantage of open source isn't just that you can fix it when you need to. It's that everyone can. Open source software is like a paper that has been subject to peer review. Lots of smart people have examined the source code of open source operating systems like Linux and FreeBSD and have already found most of the bugs. Whereas Windows is only as reliable as big-company QA can make it.

Open source advocates are sometimes seen as wackos who are against the idea of property in general. A few are. But I'm certainly not against the idea of property, and yet I would be very reluctant to install software I didn't have the source code for. The average end user may not need the source code of their word processor, but when you really need reliability, there are solid engineering reasons for insisting on open source.