Unix Is Actually Simple
Author: Chen Hao. Reposted from http://blog.csdn.net/haoel. Copyright belongs to the original author (when reposting, credit the author and source; no commercial use without permission).
A lot of programmer friends ask me online: how do I learn Unix? Why is Unix so hard? How do I get good at it? And they ask me for tips. Most of the time I find that people asking these questions share two traits:
-
They’re intimidated by Unix and lack confidence in it.
-
They like comparing Unix with Windows.
These two traits act like “psychological suggestions,” hinting to themselves that Unix is hard to learn, that Unix is terrible, that it isn’t as good as Windows. And so they end up hypnotized by their own long-term suggestions. Because they start out intimidated, they decide Unix is bad and find it painfully hard, and eventually that turns into dislike and aversion.
So, to correct that self-suggestion, I want to write this piece and tell everyone: Unix really is simple.
Before I get to “simple Unix,” a few notes (to avoid pointless arguments):
-
This is written from a developer’s perspective. If you disagree, please challenge and discuss it from a developer’s perspective too — you’re very welcome to.
-
I’ll inevitably compare Unix with Windows. That doesn’t mean I dislike Windows or that I’m asking you to abandon it. We all know this comparison has gotten tired, but since so many people have Windows as their first impression, I have to take Windows apart in order to reverse that suggestion. That’s all.
OK, back to the point. Start with Unix’s most important trait — “high cohesion, low coupling.” In other words, applications under Unix don’t interfere with each other. That’s the thinking that runs through all of Unix: a high degree of independence between modules and programs. This design makes your system relatively stable, and makes it especially easy to manage and maintain. Unix applications are like a regular army drawn up in neat ranks: as long as the commander (the kernel) is alive, the system won’t fail to boot because one unit was lost. Windows applications are like a forest: from above, the trees look neatly arranged, but their roots tangle together underground, impossible to cut apart or straighten out, extraordinarily complex.
The result of “high cohesion, low coupling” is that a Unix system is mostly made up of small programs with a single function. Those small programs are like building blocks: when we need to build a custom structure, most of the time all we do is play a simple game of stacking blocks. Windows is built magnificently, but you can almost never take someone else’s “blocks” and put them into your own building — you always have to imitate or rewrite.
(Aside: have you noticed that when downloading Windows software there’s something called “green software”? That’s the greatest irony of Windows. Install a piece of software on Windows and N DLLs land in the Windows system directory, N keys get written into the registry, plus plenty of other actions you don’t know about. Install software on Unix and you don’t worry about mysterious junk files appearing in your system directories — it’s as simple as a copy. Even with rpm installing automatically, you can query what changes the installation made to your system afterward. So distributing your software under Unix feels much, much simpler than under Windows.)
Next, Unix’s other most important trait: “every device can be operated like a file.” Simple, right? Every device — files, printers, displays, terminals, the network, floppies, tapes, USB, CD-ROMs, and so on — does I/O through a file descriptor. The two most important Unix system calls, read/write, handle I/O for all devices. Unix has already created these files for you under /dev. Using them is simple.
Many people feel Unix’s command line is too complicated: one command with a bunch of parameters, terribly complex. But the fact that Unix applications are still mainly character-based today is exactly what demonstrates Unix’s simplicity. It’s another Unix trait — “commands support each other.” Commands can be linked through a pipe or redirection, and with shell scripting on top, even implementing something fairly complex (a small text database, say) is trivially easy.
If none of the above convinces you that Unix is simple, let’s look at a concrete example of how simple Unix is. Try this thought experiment: “what if we had learned Unix first and then moved to Windows?”
-
We create processes under Unix with the
forkcall. On Windows we look it up in MSDN and find a system call calledCreateProcess, but it has ten parameters. Unix’sforkhas none. Wouldn’t that make your head spin? Under Unix you simply never see a system call API with ten parameters. -
Manipulating file permissions under Unix is simple: permissions come in three groups (owner, group, others), and each group has read, write, and execute. Two simple system calls,
chmod/chown, and you’re done. On Windows with NTFS, if you want to set file permissions programmatically — heh — you first need to understand what a SID is, what a DACL is, what an SACL is, what an ACE is, plus a dozen or so related system API functions waiting for you. (See my Manipulating NTFS File Permissions Programmatically.) You might think such a complex security policy is the foundation of a more secure system, but since the day Windows appeared it has never outperformed Unix on security. It’s a lot of effort for no thanks.
(Aside: switching users under Unix is quite easy and convenient. Switching users under Windows forces you to quit the current user’s foreground programs, which is why Windows users almost without exception choose to work and browse as a superuser — leaving their machine completely naked. That’s why a Windows virus, once running, can do whatever it likes. Under Unix, few users operate the machine as root, because switching users is so convenient.)
-
Under Unix, users have IDs, groups have IDs, and processes/threads have IDs. IDs are simple and easy to grasp, like our national ID cards. On Windows, the user identifier is called a Token and the process identifier is called a Handle (really just a DWORD). I see plenty of questions online asking what a Windows Handle is conceptually. I keep wondering why Microsoft didn’t pick a simple, understandable term, instead of choosing something so abstract and confusing. It makes Windows look impressive, but it also raises the learning difficulty. (Windows development is far more complex to learn than Unix, and it has far too many seemingly profound terms that leave people baffled.)
-
Let’s also look at user management and program ownership. Under Unix, what you need to do is configure an NIS server and an NFS server (with autofs mounting automatically) — concise and clear. On Windows the counterpart is something called a Domain (primary domain controller). First, to join a domain you need to reboot (under Unix you only edit
/etc/nsswitch.confto tell the machine where user logins come from, no reboot needed), and for developers Unix’s configuration is completely transparent to programs. Windows domain users and local users need a domain name to distinguish them. To switch users in a program, Unix only needssetuid/seteuid, while Windows has three fairly complex APIs for it:CreateProcessAsUser,ImpersonateLoggedOnUser,LogonUser. No need to compare the complexity. Also, under a Domain setup the files in your Documents and Settings directory all go onto the Domain server, and when you log in on another machine they get downloaded. In the end I’m not worried about your MSN chat logs following you everywhere — I’m worried whether the code you write in such a convoluted management environment can be trusted. :-( -
Under Unix, adding your program to the system’s startup services only means configuring
/etc/init.d. Write a script with start and stop functions and symlink it with the right naming into the different runlevel directories. On Windows, adding a startup service is probably hard unless you write a program. -
Under Unix, getting system information only means
cat-ing the pile of files under/proc. The state of every process and thread, command lines, memory and swap usage, open file descriptors — and the system’s CPU, memory, swap, memory-mapped file I/O, partitions, network, runtime state, devices, and so on — as detailed as you like, and all plain text you can read directly. On Windows, enumerating information about current processes isn’t easy, let alone getting the rest.
I admire Microsoft for making an operating system so complex: a registry, security policies, OLE, COM… Every time I open regedit.exe I don’t dare touch HKEY_CLASSES_ROOT, because looking at those thousands of CLSIDs makes me dizzy.
Since 1995, ten-odd years have passed. Microsoft has shipped all kinds of technologies. I still remember Visual Studio 6.0 shipping with two things called FoxPro and J++ — FoxPro came from Foxbase and lasted a few years; J++ seemingly didn’t even last that. ActiveX Control was a complete failure, and that language called VB, in hindsight, really did ruin a lot of promising programmers. When COM appeared, I wonder how many people today remember something called MTS? And today, how many still remember something called ODBC? In this convoluted, chaotic Windows world, are you exhausted from chasing it? How many of today’s .NET technologies will survive the settling of time? On Windows we’ve learned plenty of failed technologies, or transitional ones. Unix, meanwhile, hasn’t changed much since the 1970s, and C — born because of Unix — still shines today. I trust this Unix that has stood the test of more than thirty years and is still so simple.
Unix is just that simple. Friends who want to learn development on Unix: you made it through an operating system as complicated as Windows — are you still afraid of Unix, which is this simple?
