basic algorithms

The book is my primary source of interest while being a freshman, which presents a wide range of algorithms in a very coherent and systematic way. I remember “rescuing” this hard-copy from a Fahasa‘s junk pile for about 4 USD, which from that time on became a student’s most precious thing! You can read the soft-copy here.

This is among the subjects I was very fascinated the early years at university: algorithms, graph theory, geometry, image processing… I was not quite good at “symbolic” math (like algebra), but “visual” math offered me much inspiration. The thing I would remember most is Robert Sedgewick‘s Algorithms, a book that I’ve read through over and over again many many times. It is indeed the most important Computer Science textbook that beginners MUST read until today.

The Java applet below is “refurbished” from the code I wrote the first year at college, which visualizes the nature of different sorting algorithms (original code was written in Borland C++ 3.1 with BGI – Borland Graphics Interface). This is among my various attempts to visualize the knowledge collected from the book, which had taught me that even a simple thing like “bubble sort” is not that “very simple”! Let select an algorithm in the dropdown list and click ‘Start’ and see the differences!

My visualizations above are very early (1997), much prior to those demonstrations on wiki. Later on, I’d learned that the author R.Sedgewick put a great emphasis on algorithms’ visualizing himself, his work used PostScript. Many new ways of visualization are really impressive and easy to understand, such as this (using JavaScript).

I started with with C/C++ at school, then continue with C/C++, Java, Design Patterns… on various projects. Later I abandoned Design Patterns (and Java), then I abandoned C++. To me there’s no Design Patterns, there’s only data structures and algorithms! Would write another post on the bloating and non-sense usages of Design Patterns later on!

It seems that most software engineers today lack fundamental knowledges and skills. It’s quite apparent that you could not rely on a guy talking about architecture, GoF’s design patterns… all the time but can not state the algorithmic differences between a DFS (depth first search) and a BFS (breadth first search).

3d graphical user interface

The code is written in C++ base on Clutter 1.2.4 library. It shows basic widgets: tabbed container, scrolling container, list box, combo box, check box, edit box, button, label, radio button…

This is my personal project in which I tried to evaluate some new ideas and concepts in using 3D techniques for GUI (Graphical User Interface). It’s quite tiny indeed (about 6000 LOC – line of code), all written by myself in about a month (mostly in my free times at weekends). So please don’t blame me on some un-completed or un-polished features, they are just for testing the ideas only. I would try to examine the trend of applying 3D graphics to GUI, but first, let have a look at the video below.

1.   The first thing to consider is not 3D engines or hardwares, it is about usability. Many traditional (2D) GUI out there are already complex and obstructive. GUI is about information presentation and presentation should be really simple and clear so that even my grand mother can understand and use. I’ve been seeking, trying to explore many new ways invented to represent information in 3D (or 2.5D) space, and I could say only a very very small percent of them could make a usable value. Users have long been familiar with 2D, and yet 3D hasn’t been very much persuasive.

2.   3D hardwares can be categorized into 3 groups (as listed on the left), and the 3D engine can be configured to off-load calculations to hardware. With the 1st type of device, only bitmap operations could be off-loaded. With the 2nd type of device, many drawing operations (the path_xxx functions) can be off-loaded. The 3rd type of hardware is most valuable since we can have its finish for ourselves a lot of work.

It’s important to understand the target device our software stack would be running on. If it is an out-date machine with just some blitters, we should use paint-like (aka: bitmaps) operations, while on most modern PC, draw-like (aka: 2D vector) operations are more encouraging. While bitmaps may offer nicer and more customizable GUI, the cons is it lacks the scalable ability that vector has.

3.   The last is about software implementation. Many of the graphics concepts are first introduced in software, which then embedded to hardware, which then standardized by software (like OpenGL or DirectX) again. Thus, many elements of a graphics pipeline is the production of a long history of interactive evolution. A graphics pipleline is not a general framework, it depends on very detailed, in-depth techniques to be operational in real-world application.

Game & graphics are the domains where most formal software methods would easily failed. 3D graphics developers should have good knowledge on graphics in general (bitmap and vector drawing), geometry, linear algebra & discrete maths, deep understanding on data-structures and algorithms… are strong pluses, advanced tips & tricks in coding and optimization is a must (game & graphics programming has always been a hell of tricks from the age of dawn) and finally good understanding on 3D techniques (model, scenegraph, projecting, shading, clipping, lighting, effects…)

3d

We are building something like this, a 3D user interface. Day by day, we’re witnessing more and more diversities in computer user interface: concepts, designs, look and feel, animations, effects… While some would stick to an bare – bone, obscured text console, the others prefer some fancy, eye – candy GUI with all its bells & whistles. Things are much easier now with many 3D libraries and tools. Remind me about how I did all the 3D things: polygon, mesh, texture, sprite, shading, lighting, scene – graph, etc… with C & assembly on DOS!

vim for programmer

VIM “IDE” with symbol – browsing and auto – completion

Various utilities inside VIM: media player, calendar, file explorer…

I have been using VIM for most of my daily programming, and everyday, I’ve been discovering new things about VIM. We can tune VIM into a full-fledged and powerful IDE (Integrated Development Environment) that far surpasses every others! With ctags and taglist.vim, we can build tags database, which would then enable searching, browsing all symbols, variables, functions in a code – base. cscope enhances ctags even more with advanced search & browsing features. And I would need no external diff tool since we’d already have vimdiff to compare and merge code.

Working with different types of version – control system, we’d already had vcscommand.vim, which can help interfacing with svn, cvs or git! To interact with file system, I would use NERDTree or vimExplorer, a lot of tasks with fs is done even without leaving VIM! I’m not fool enough trying to do everything with VIM, but there are many other plug-ins that you would find useful: a.vim and c.vim would help you a lot in C/C++ programming, calendar.vim helps you viewing date, and keeping small notes (diary) for each day, musicbox.vim serves you with media playing inside VIM, and vimail helps send, receiving emails with just a few convenient keystrokes!

fooled by randomness

Usually on my birthday, I would receive messages like: Congratulation to the Party! Congratulation to the government! Congratulation to President Ho Chi Minh! (the day happens to be also the Man’s birthday). But last month, I received this book, a nice gift from a friend, a soft – paperback hard – copy of the famous writing: Fooled by Randomness! I’m now half – way through the book, a bit difficult for non – English – native readers, but really interesting in every details!

My major hobby is teasing people who take themselves & the quality of their knowledge too seriously & those who don’t have the courage to sometimes say: I don’t know. You may not be able to change the world but… (www . fooled by randomness . com)

As with every outstanding thinkers and thinkings, the book’s caused controversies since it was first published (2001), written by Nassim Nicholas Taleb, a skeptical scholar and at the same time, a successful trader. I’ve been for long, looking forward to these types of cognitive thoughts! It’s too soon to have some comments on the book, but for now, the debate between Einstein and Heisenberg, between determinism and un – determinism would just go on!

elektronika

Russian Elektronika clone

Nintendo Game & Watch original.

A very sweet souvenir, a sudden reminiscence that happen to recall, my first computer game. Some day in the mid-80s, I’d got a gift, a Soviet built, hand-held device. I still remember the sound, the addictive feelings came with it! The game featured a wolf, a rabbit, likely to be seen in the Nu, pogodi! cartoon series (pronounced by us – little child as nupacachi). The game’s goal is trying to catch falling eggs, if an egg missed, it breaks and a chick is born. If 4 chicks are born, you lose! I played hundreds of games on this pad, then batteries ran out but can’t find anywhere replacement back then.

Several years later, in the late-80s, these types of games became obsolete, then seen the Nintendo’s Famicom console widespread. Now I know it was a clone of Egg (a variant of Mickey Mouse), played on console manufactured by Nintendo. Although capable of building super computers, the Soviet Union was, at the time, in shortage of consumer goods, they choose to reverse engineer various Western products.

It’s very interesting to learn about separate branches of electronics and computer science in the USSR. They had distinctive type of computers, architectures, operating systems, programming languages… Some are even found nowadays quite bizarre like the trinary computers (as apposed to binary systems we’re extensively using). It should be noticed that the Russian had very successful specific-purpose models that offer superior power in narrow fields (such as ballistic computing). Areas in their separated genealogical branches of science and technology remain mysterious until today, some are covered in the book Computing in Russia, a highly-recommended reading!

Update, May, 13rd, 2009

It was kind of a very first and famous game, yet only ones at the time know about it, in the early and mid 80s. After searching a while, I found various simulators for playing the Game & Watch series, on Linux, on Windows and even on Mac. On the left is Flash version of the game, the Soviet variant named Nu, pogodi!, you can guess from Cyrillic letters above the screen. Enjoy!

ô ăn quan

Có 50 quân dân, và 2 quân quan, mỗi quan tương đương 10 dân. Người chơi có quyền chọn di chuyển theo hướng bất kỳ, những game Mancala khác chỉ được di chuyển theo một chiều nhất định.

Ăn quân ở ô kế tiếp trong lượt đi chứ không phải ở ô đối diện của đối phương. Khi đến lượt mình mà không còn quân để đi thì phải bỏ 5 quân đã ăn được vào 5 ô của mình để tiếp tục chơi. Trường hợp không có đủ 5 quân thì phải vay của đối phương và trả lại khi trò chơi kết thúc.

Trò chơi dân gian Việt Nam Ô ăn quan thuộc họ Mancala, có nguồn gốc châu Phi và có hàng chục biến thể khác nhau trên thế giới. Khi nhỏ, tôi có chơi trò này vài lần, gọi theo tên địa phương là Ô làng chứ không phải Ô ăn quan. Hôm nay thử nhìn cái game này dưới góc độ tin học xem sao! Ô ăn quan có một số luật khác với những game Mancala khác.

Những luật bên, nhất là luật thêm & mượn quân làm Ô ăn quan phức tạp hơn nhiều so với những biến thể Mancala khác. Viết một chương trình cho máy tính chơi Ô ăn quan không phải là quá dễ dàng, dùng những heuristic đơn giản (hill-climbing, min-max, hay brute-force đến một độ sâu nhất định…) không đủ bảo đảm máy tính sẽ thắng trong nhiều trường hợp.

Trên internet, tôi không tìm được game Ô ăn quan nào theo đúng luật Việt Nam. Một số là những biến thể gần giống Ô ăn quan, một số tác giả claim là đã viết Ô ăn quan nhưng không cung cấp được link download. Có vẻ như game này không dể như khi vừa mới nghĩ đến! Bạn nào có ý kiến về chiến thuật chơi game này xin được trao đổi để cùng phát triển một trò chơi hoàn chỉnh.

Bên đây là screenshot của một Java applet tôi vừa viết trong vài tiếng đồng hồ, cho phép 2 người chơi với nhau (máy tính chỉ kiểm luật, chưa phải là một chương trình cho máy tính chơi thực sự). Những hiệu ứng đồ họa: di chuyển quân, ăn quân nhìn rất giống thật, graphics được vẽ bằng Photoshop: những viên sỏi và bàn chơi được vẽ bằng phấn trên mặt sân xi-măng… gợi lại những kỷ niệm thủa nhỏ.

minesweeper

Two more hours of work and I’ve added this hexagonal tiles to my MineSweeper! Anyone interested in the game can found the tiny binary and source code (450 LOC) here. Mine sweeping with hexagons is quite a different experience! More about MineSweeper, a simple game?

On the left: Minesweeper with hexagonal tiles

virtualization

MineSweeper running in DOSBox

Click the demo page below (jpcapplet.jar – 1.8 MB in size), it would take some times to load, embedded in it is a DOS image (floppy.img) of a floppy’s size (1.4 MB). In Linux, using dd to create a blank image file, launch JPC app, mount the empty image, fdisk to give it a partition structure, format to give it a bootable FAT12 file system, copy the files over, edit autoexec.bat to have the game run at startup, and voila – there you are, the classic DOS game of MineSweeper on the web!

Beside is screen-shot of my very first programming, the classic MineSweeper, an exercise I did first year at university. After getting started with Borland C++ 3.1, I began to write numerous toys like this; small games, graphics, animation, 3D… are among the things I was very fond of. We still had not had Internet in Vietnam then, lacking of information, we’d reinvented many wheels, including a package for displaying 3D objects (in form of polygon mess), a complete GUI for DOS with window, menu, toolbar, all kinds of controls: combo, list, button… But as they say: don’t reinvent the wheel, unless you plan on learning more about wheels, the reason we did all that fun stuff.

Back to my MineSweeper, it’s tiny, about 350 LOC (Line Of Code), using BGI (Borland Graphics Interface), C/C++ and some ASM. Yesterday, just want to check the old source, but didn’t have a Windows machine at hand, I needed to run the Borland C++ 3.1 compiler on my Linux box. Wine is good for many Windows applications, but it simply won’t work with pure DOS programs. Then I found DOSBox, you start it up in form of a console, mount a directory in local file system, have BC 3.1 installed and compiles flawlessly, and MineSweeper runs well on this virtual DOS on top of Linux!

That’s some layers of virtualization, say I want more, I want to show MineSweeper on the web, but don’t want to make change to the code, or even to the compiled binary. Could it be possible? The answer is: YES! You would need JPC, a pure Java IBM-PC emulator, it runs where there is Java: x86, RISC, mobile phone… On top of it, you can run a bundle of different OS: DOS, Linux, Windows… Then comes the delicate distinction between virtualization and emulation, hardwares, softwares, all can be virtualized to some great extent. Imagine you would run some games & utilities on a virtual DOS (or Linux) running inside JPC, hosted in Firefox browser, which in turn runs on Windows (or Linux)!

JPC can only bring about 20% power of the native machine, and even a tiny game like this is overkill to it, and mouse functioning is really crappy too. But that’s suffice to demonstrate the idea, JPC could be improved I believe. More games would be added to this Web DOS console later on! Anyone still remember Tetris, Croix-Zero, Snake, Mario…? So, what’s the points for JPC? Demonstrating the fractal principles in hardware, software evolution? Too much “nostalgia” for the “good old days” – DOS games? Anything else or just reinventing the wheel? The answer may be so, but I love this idea of cultivating the past, and pop out new things for the future!

otp (one-time-pad)

OTP takes a security problem and changes it into a
distribution problem. Modern cryptography takes a
distribution problem and changes it into a security problem.

Chuỗi khoá được in trên một cuốn sổ bé xíu, để dễ cất dấu hay tiêu huỷ khi cần thiết. Mỗi lần mã hoá dùng một (hay nhiều) tờ trong cuốn sổ, những tờ đó sẽ bị huỷ sau khi dùng, do vậy mà có cái tên one-time-pad

Hình bên: một cuốn sổ OTP của KGB, được in trên giấy phim để dể cháy khi đốt

đĩa Vigenere

Tôi đến với Computer Science khá trể, nhớ lại hồi năm nhất đại học, khi lần đầu tiên học về toán tử XOR (bit-wise operator XOR), tôi đã nghĩ ngay đến phương pháp mã hoá đơn giản và hiệu quả: thông điệp cần gửi được XOR với một chuỗi ký tự ngẫu nhiên (chuỗi khoá), ở đầu nhận, người ta XOR chuỗi đã được mã hoá với chuỗi khoá lần nữa để giải mã thông điệp. Đây chính là biểu diễn máy tính của phương pháp mã hoá cổ xưa OTP (one-time-pad) được dùng từ thời đệ nhất thế chiến.

Lincolnshire Poacher (MI6 ?) 
Magnetic Fields (Deuxième Bureau?) 

OTP được các điệp viên CIA, KGB, MI6… dùng phổ biến trong hai cuộc thế chiến. Lý do thứ nhất là vì nó đơn giản: mã & giải mã chỉ cần dùng đến tính nhẩm (có thể dùng thêm bút chì và giấy), lý do thứ hai là nó rất an toàn. Tuy đã được dùng rất lâu từ trước nhưng mãi đến khoảng năm 1940, phương pháp này mới được chứng mình bằng lý thuyết về tính an toàn tuyệt đối của nó. Chứng minh được đưa ra đồng thời và độc lập bởi Claude Shannon (nhà toán học Mỹ, cha đẻ lý thuyết thông tin) và Vladimir Kotelnikov (viện sĩ khoa học Liên bang Nga, kỹ sư chế tạo rađa).

Mã & giải mã với OTP rất đơn giản, tương đương phép XOR, ta định nghĩa phép biến đổi như sau. Mã hoá = (text T(19) + khoá X(23)) mod 26 = Q(16). Giải mã = (Q(16) – khoá X(23)) mod 26 = text T(19), với 26 là kích thước bản chữ cái (phép XOR thực chất là phép cộng và modulo cho 2, với 2 là kích thước bảng chữ cái nhị phân: 0 & 1). Những người không giỏi tính nhẩm có thể dùng “thiết bị” sau (gọi là đĩa Vigenere), đĩa gồm 2 vòng giấy đặt đồng trục. Mã hoá text T với khoá X: gióng (xoay) vị trí [X] của vòng trong với vị trí [A] của vòng ngoài, tìm [T] tại vòng ngoài, ví trí tương đương [Q] tại vòng trong chính là kết quả. Giải mã là quá trình ngược lại: gióng [Q] của vòng trong với [A] của vòng ngoài, tìm [X] tại vòng trong, vị trí tương đương [T] tại vòng ngoài là văn bản gốc.

Có một cách sử dụng OTP đặc biệt gọi là chia xẻ bí mật (secret splitting), sau khi mã hoá, văn bản gốc bị huỷ thay vì khoá, sau đó khoá và văn bản mã hoá được đưa cho hai người khác nhau cất giữ. Chỉ khi hai người này cũng đồng ý nối hai “khoá” lại với nhau thì mới giải mã ra được văn bản gốc. Tương tự, có thể chia xẻ bí mật cho 3, 4,… người bằng cách sử dụng 2, 3,… khoá. Đây là cách bảo vệ các tài nguyên đặc biệt quan trọng, trách nhiệm bảo vệ đó được chia xẻ cho nhiều người, tuy nhiên lưu ý rằng nếu chỉ một phần của bí mật bị mất đi, thì bí mật đó cũng sẽ mất đi vĩnh viễn.

OTP là phương pháp mã hoá tuyệt đối an toàn nếu được sử dụng đúng cách, và là phương pháp tuyệt đối an toàn duy nhất cho đến thời điểm hiện tại. Văn bản được mã hoá với OTP không cho biết bất kỳ thông tin gì về văn bản gốc, ngoại trừ độ dài. Với một văn bản đã mã hoá cho trước, chúng ta có thể nghĩ ra các chuỗi khoá để “giải mã” nó về bất kỳ văn bản nào chúng ta muốn! Các phương pháp mã hoá mới sau này như DES (Data Encryption Standard), AES (Advanced Encryption Standard), PGP (Pretty Good Privacy), PKI (Public Key Infastructure)… tuy tiện dụng và có nhiều ưu điểm khác, nhưng về mặt lý thuyết không phải là không phá được. Nhưng trong sử dụng thực tế, có những lý do sau khiến OTP trở nên không an toàn:

  • Chuỗi khóa OTP không thực sự ngẫu nhiên (các nhân viên thư ký của KGB tạo ra OTP bằng cách gõ ngẫu nhiên lên máy đánh chữ, nhưng xu hướng gõ phím của tay người vẫn có những pattern nhất định).

  • Việc cất giữ và tiêu huỷ OTP có quá nhiều yếu tố rủi ro (đã có tình huống CIA giải được mã nhờ một cuốn sổ OTP đã bị đốt nhưng chưa cháy hết).

  • Mỗi trang OTP chỉ được dùng một lần (đã có lúc trong tình hình khẩn cấp, nhân viên KGB bất cẩn dùng một trang OTP cho nhiều lần mã hoá, dẫn đến việc CIA giải được khoảng 1% trong số những thông điệp gửi bởi KGB trong những năm 1945 ~ 1950).

Điểm yếu nhất của OTP nằm trong quá trình trao đổi khoá (key exchange), đó là một trong những lý do hình thành phương pháp public key rất tiện dụng sau này. Đến bây giờ, khi những phương tiện mã hoá và truyền thông đã quá hiện đại, người ta vẫn còn tiếp tục dùng OTP cho những kênh thông tin thuộc loại top secret (như đường dây hotline Washington DC – Moscow, liên lạc với tàu ngầm…) vì tính tuyệt đối an toàn đã được chứng minh lý thuyết của nó. Có thể kiểm chứng dấu vết của việc sử dụng OTP trong thực tế:

Các Number Station nổi tiếng bí ẩn, là những đài phát thanh không rõ nguồn gốc, phát trên băng tần sóng ngắn (shortwave) những bản tin toàn chữ số, được xem như những hoạt động tình báo của nhiều nước. Trên internet, những Numbers Relay Pages như nrp.write2me.com là hình thức mới của Number Station, cho phép mọi người gửi đi những thông điệp bí mật. Tất cả đều dưới hình thức những bộ 5 chữ số của mã hoá OTP (e.g: 41888 42037 89537 55295 14846 82981 63440…).

biệt kích, bộ binh & cảnh sát

Từ lâu tôi có một suy nghĩ, ẩn dụ vui vui về software engineering. Nay tìm được một bài viết tương tự ở đây, người ta cũng nghĩ như mình, và diễn đạt tốt hơn. Không có cách nào khác hơn là dịch lại nguyên văn bên dưới.

Có ba “lực lượng” hoàn toàn khác biệt có liên quan đến những giai đoạn hình thành và phát triển của một công ty, đó là: “biệt kích”, “bộ binh” và “cảnh sát”.

Biệt kích

Khi xâm chiếm một vùng lãnh thổ (hay thị trường), lực lượng tham chiến đầu tiên thường là các nhóm biệt kích. Như Stephen WozniakSteve Jobs của Apple, Don Estridge của IBM PC, Mitch KaporJonathan Sachs của Lotus 1-2-3… là những nhóm biệt kích. Nhảy dù vào sau lưng địch, đổ bộ bí mật lên bờ, gây ra thật nhiều thiệt hại cho đối phương, đặt đầu cầu cho những cuộc tấn công tiếp theo là công việc của biệt kích. Họ làm điều đó bằng cách tạo ra những mẫu hình sản phẩm mà ý tưởng sáng tạo của chúng xuất sắc đến nỗi những sản phẩm tương tự không có cách nào khác hơn là thua cuộc và bị đào thải.

Với hầu hết các loại sản phẩm, “biệt kích” là nhóm duy nhất có quyền sáng tạo: đẩy công nghệ tới những giới hạn mới, tìm ra những khách hàng tiềm năng, và xem quá trình phát triển như một cuộc phiêu lưu. Tuy vậy, cái họ làm ra được còn lâu mới có thể gọi là sản phẩm, chúng thường có những điểm yếu chết người mà cá tính “biệt kích” khó lòng nhận ra được.

“Biệt kích” thường chóng chán. Tôi (ND: tác giả) nhớ lại cuộc phỏng vấn đội trưởng một đội biệt kích Hoa Kỳ sau khi đổ bộ vào Panama: Chẳng có gì thần kỳ! Chúng ta vẫn còn đang ở đây! Một đôi khi nhóm biệt kích đâm chán nản ngay cả khi mẫu sản phẩm đầu tiên vẫn chưa xuất hiện, lúc đó đành phải chờ đến khi họ có hứng thú trở lại (hay là thuê một nhóm biệt kích khác). Một ví dụ: Ron Crane, trưởng nhóm “biệt kích” tại 3COM Corp, công ty sản xuất card Ethernet trước tiên, khi đang thiết kế card này, Crane phát chán và bỏ đi nghiên cứu hiệu ứng phản xạ âm thanh trên trần nhà công ty. Mọi người đành phải chờ cho đến khi Crane kết thúc việc nghiên cứu, thiết lập nên chuẩn nội thất mới cho công ty, tiếp tục với card mạng và đưa 3COM lên mức lợi nhuận 900 triệu.

BỘ BINH

Biệt kích là người tạo bước đột phá đầu tiên, tuy vậy hầu hết mọi cuộc chiến (hay thương vụ) đều là chiến tranh quy ước. Tiếp theo sau biệt kích, lực lượng bộ binh tấn công với số lượng lớn để phát triển hơn nữa những lợi thế có được ban đầu. Thử nghiệm, cải tiến, sản xuất, tiếp thị sản phẩm dựa trên nguyên mẫu ban đầu và bắt đầu thu về lợi nhuận. Nếu biệt kích sáng tạo những cách mới đề làm bị thương đối thủ, bộ binh mới thực sự là người kết liễu hoặc đẩy lùi đối phương, chiếm lĩnh trận địa và cắm cờ chiến thắng. Đôi khi, bộ binh cũng phải sửa chữa những sai lầm mà nhóm biệt kích mắc phải. Vì là một tập thể số đông, nhiều người, nhiều loại, bộ binh cần có một cơ chế quản lý, luật lệ phức tạp mà những tay biệt kích giỏi đều cảm thấy không thích hợp.

Cảnh sát

Khi các lực lượng biệt kích và bộ binh đã tiến được về Berlin (hay Baghdad), những vùng đất bị bỏ lại phía sau cũng cần được bình định, quản lý. Lúc đó cần có một đội ngũ cảnh sát: thiết lập cuộc sống dân sự, xây dựng phát triển kinh tế. Cảnh sát thường xem công việc là công việc hơn là một cuộc phiêu lưu, họ ngại thay đổi, chấp nhận phần thưởng ít hơn với những vị trí ít rủi ro hơn. IBM, AT&T… những công ty lâu đời, đa phần thuộc lực lượng thứ 3 này, nhiều khi họ còn không nhớ những thành viên “biệt kích” hay “bộ binh” đầu tiên là những ai.

Thành lập và phát triển một công ty, hay điều hành một dự án phần mềm lớn đều cần dùng đến cả 3 lực lượng này. Dùng sai người (như “biệt kích”) vào sai vị trí (như bảo trì) là một thảm họa. Làm một “biệt kích” nghe thật hấp dẫn, tuy nhiên cũng còn tùy vào tình huống, “biệt kích” cũng có thể gây hại nghiêm trọng cho chính dự án anh ta đang phục vụ.

math expression on www

I rarely need to write mathematics expressions on the web, but the last time I did, it took me some times to figure out just how to do. It’d turned out to be pretty easy, there’s a free LaTeX rendering server at yourequations.com. Excellent site! Just feed it with a LaTeX expression, it would render an image for you to put on your web page. This may be the best solution for now, while waiting for an workable HTML version that supports math.

There’s also a guide to embed this feature onto Blogger blogs (and also WordPress, and some PHP forums…) Just insert your LaTeX code between the pre (or code) tags as below and the jsTeXrender JavaScript would do the rest for you. This works fine for any browser with JavaScript support (mouse over the expressions and you would see the underlying LaTeX code). You may also need this LaTeX Reference Card for a list of LaTeX’s symbols.

Update, Otc 1st, 2010

Due to heavy traffic, yourequations.com has ceased the service. Please see this new post on how to run a LaTeX rendering server of your own!

signals and slots

C makes U hang yourself;
C++ even gives U a rope object to hang;
C# scourges U using a rope wrapper!

I rarely talk about programming unless it comes to some new idea or something fun. However, in this article, I’m going to summarize a part of experiences in my career, about important concepts that I’ve learned and used: signals and slots. First appear and remain as fundamental concepts in the Qt library (“Qt” pronounced “cute” – which is so cute as a cross-platform application framework), the concepts has been adapted and developed into some other libraries (such as boost) and are being proposed as next standards for C++ language.

Please note that we’re talking C/C++ here, although signals & slots has been brought to many other languages (Java, Python, Ruby, JavaScript, etc.) Every coin has two sides and C/C++ is no exception, it has its own advantages and disadvantages (depend on types of applications). But the thing I like about C/C++ is that its half – civilized nature made it a strong language: the balance between abstraction and comprehensiveness has always been considered as core factor.

Noone want to build general applications using Assembly, and noone want to write lengthy code just for some simple features. To adhere the doctrine, strong – abstraction concepts must be introduced to capture grammar of the language, and simple, clear syntax that would make the code concise and comprehensive.

I came to signals & slots as solution to problems I’ve met when leading the CMS project, a DVRs managing software (client & server) with complicated GUI: a few screens, each screen can have a dozen tabs, each tabs can have hundreds of controls. Events on one control can affect other controls on other tab or screen, events can be user inputs as well as various signals come from dozens of (managed) network client machines.

The overwhelmingly – complicated communications surpass every MPM (message passing method), then signals & slots appeared as a saviour solution. To be simple, signals & slots is a very efficient mean of interaction between objects within a process space. I personally think it would be the next metaphor extension added to C/C++ language. Structure of this post would be as follow:

1. Introduction to signals & slots, from raw to abstract concepts.

2. ISO C++ compliant and cross – compiler, cross – flatform problems (would discuss about delegate and how function pointer has evolved from C to C++).

3. Different implementations of signals & slots: Qt, boost, sigslot, libsigc++

1.   INTRODUCTION

Flow of code is no more than a series of function call, and to perform asynchronous function call, traditional C programming use callback. A callback is a pointer to a function, so if you want a processing function to notify you about some event, you pass a pointer to another function (the callback) to the processing function. Callbacks have two fundamental flaws: firstly, they are not type-safe, we can never be certain that the processing function will call the callback with the correct arguments. Secondly, the callback is strongly coupled to the processing function since the processing function must know which callback to call. In C, to define function pointer, you would write something like this:

float (*my_func_ptr)(int, char *);
typedef float (*MyFuncPtrType)(int, char *);
MyFuncPtrType my_func_ptr;

When move to C++, things are a bit more complicated (note the weird syntax ->* to call a member function through pointer).

float (SomeClass::*my_memfunc_ptr)(int, char *);
my_memfunc_ptr = &SomeClass::some_member_func;
SomeClass *x = new SomeClass;
(x->*my_memfunc_ptr)(6, "Another Arbitrary Parameter");

Though a very strong concept in C, function pointer add little to the language C++. The only two uses of member function pointer in C++ are:

  • Demonstrate the tricky syntax of the language.

  • Help in implementation of delegate.

Now, imagine slots as invisible communication channels, every object can register to listen to some channels by providing delegates (pointer to a member function). The delegate would be invoked when slot is “filled” with a signal. The signals and slots mechanism is type safe: signature of a signal must match signature of the receiving slot. Signals and slots are loosely coupled: a class which emits a signal neither knows nor cares which slots receive the signal. To summarize the benifits:

  • Syntactically neater: signals & slots make for very readable code: you define the signals, you define the slots, then you wire them up.

  • Inherently robust: when either end of a signal/slot connection is destroyed, the connection is automatically removed. It is therefore impossible to emit a signal and have it arrive at a class that has already been deleted. Best of all, you don’t need to write any cleanup code.

  • Easier code reuse: since the thing that has to type-agree is the signal and the slot, not the whole class interface, it is much easier to plug together disparate classes that had never initially been intended to work in that way.

2.   DELEGATE

To summarize section 1: pointer is the root of all evils. Function pointer is the physical of callback method traditionally used in C programming. When evolved to C++, the C++ standard committee failed to address how to define function pointer to a single C++ object. With common-sense knowledge, we know that it take two elements to represent the thing: first is the address of the object itself (the implicit pointer this), second is pointer to the object’s member functions. The undefined land leads to different implementations across various compilers.

Contrary to common belief, the actual physical storage of pointer differs between various compilers, and even differs between types of pointer, e.g: pointer to a single – inheritance object, an multiple – inheritance one or virtual inheritance. The table below shows how many bytes it take to store pointers on different compilers (just make use of the operator sizeof). Then to calculate the actual member function’s address, each compiler uses one kind or another of offset:

struct BorlandMFP
{
        CODEPTR m_func_address;
        int delta, vindex;
};
if (vindex==0) adjustedthis = this + delta;
else adjustedthis = *(this + vindex –1) + delta;
C++
compiler
void*
pointer
function
pointer
single
inheritance
multiple
inheritance
virtual
inheritance
MS VC++ 4 4 4 8 12
GNU G++ 4 4 8 8 8
Borland C++ 4 4 12 12 12

So, delegate is just the new name for pointer to (an object’s) member function. The hard part really is that: since each compiler stores different type of pointers differently, there’s need for a way to store delegate in a universal manner: cross compilers and cross flatforms. Various techniques have been proposed by excellent programmers. Please refer to the articles below for specific techniques. I personally would prefer the method of Quynh Nguyen, an engineer at Global Cybersoft (Vietnam) Ltd.

3.   IMPLEMENTATIONS

To make those obscured concepts above clearer, I would go into some detailed implementations of signals & slots with the emphasize on the sigslot library, for this is really a compact lib: everything is contained in just one header file. Suppose you have a server that would receive some signal from network (tcp socket), then parse the received data and trigger some processing (display on GUI, store to disk…). We would define the “network signal” as follow (please note any number of parameters can be defined, we use an int and a char* here just for the example):

// the temmplate ‘signal2’ denote for
// a signal with 2 parameters

signal2<int, char*>m_netSig;

Then, at the place you want to process that event, e.g some class CDisplayForm, you would need to provide a function to process the signal:

DisplayForm::OnNetSig (int cmd, char* data)
{
  // the delegate would be invoked
  // when the signal is recieved

}

Please note that multiple objects can register to a same signal slot (and vice versa), e.g some class CRecordThread would also need to log that event to database. Then the listening objects would just register with the signal slot using a connect function:

// we pass the function pointer
// here to be called later

m_netSig.connect (this, &CDisplayForm::OnNetSig);

When the network signal arrive, e.g in some class CAsyncSocket, we would fire the signal and get it populated to all connected objects:

// emit the signal with it’s data
m_netSig.emit (NETSIG_DATA_RECEIVE, xmlStr);

Then the CDisplayForm and CRecordThread object would both receive the signal. Please note that when either end of the communication channel go out of scope, the connection is automatically removed, you don’t have to write any cleanup code. Just define the signal, the slot and wire them up! Any unrelated classes can be wired up in this type-safe manner without any pre-defined relation within them.

Speaking as an ex-hardware designer, I’d like software components to have pins around their edges, like ICs, so they can be ‘wired up’, but otherwise should be well behaved… I don’t want to know how that pin is wired internally – I just want to know that it will work when I send a signal into it.
(Sarah Thompson – sigslot library)

ipix fish-eye camera


the dome camera and it’s Nikon fish-eye lens

Image above: Ipix’s raw format (spherical image). Click to try the Ipix static image viewer in a separate window, which helps to view a single Ipix’s frame, wrapping from raw format to normal rectangular format (not the video).

This is among the most interesting things I’ve ever worked on: Ipix’s CommandView™: fish-eye cameras which provide a 360° x 180° field of vision. This camera and it’s technology were very special and advanced at the time, about 3, 4 years ago, it were so new that the manufacturer could not survive the small market share and went bankruptcy. However, the technology has now revired at http://www.ipix.com. The camera came with some totally new concepts, patents and technologies. Some information on Ipix:

Ceiling or wall-mounted, with thick hard steel cover, the camera is designed to operate indoor or outdoor, and can withstand a temperature range from -40°C to 60°C. It costs about $2100 at the current time, and about $5000 when it first appeared. CommandView™ Dome is an IP camera, having a small Linux computer inside, once plugged onto LAN or WAN, the camera turns into a video server and can stream video in many protocols: http, ftp, rtp, or multicast. There’re 3 ways to control the camera: ssh to the Linux machine, access to it’s web-server or programatically use the XML-RPC interface. The product has a very matured and solid development flatform.

CommandView™ Dome is a mega-pixel camera (2 MB, 3 MB). The unique feature of this product is that it provides a 360° x 180° field of view with no moving parts. See the image beside (on the left – click to view a mega-pixel version), every details in the room is captured on a parabolic sphere (called wrapped image). To have a normal view, a region on the sphere is dewrapped (by software) into usual rectangular plane.

Since a whole 360° space is captured, PTZ (pan / tilt / zoom) is just a matter of dewrapping, there’s no need to motorize the camera for different sighting fields. This special camera has broadened the definition of ‘panorama’ and has many applications in security surveillance as well as photography. I myself found it very interesting to apply the concepts and softwares to demonstration and show-case purposes (search for ‘ipix’, the name has gone far beyond just a type of camera).

file system encryption


The pc-link reader, could be in many forms: usb, serial, pcmcia, pinpad…

An Axalto (previously Schlumberger’s, now Gemalto) smart card, this could be an access – control card, a bank debit / credit card, health – care card, social – identification card… Some smart card types are actually tiny computers – they have an Operating System, and Java virtual machine inside. Note: many of the smart card vendors are OEM – ed from SCM Microsystems, a Germany – based company. We’d better choose hardware and firmware directly from SCM when work on open – source projects.

You have important data on your laptop, and one day the laptop is stolen. The best you can expect is that you loose all those valuable information. The worse… who know what it can be!? Since having a computer (hardware) in touch means having access to every data stored on it. How can you protect yourself from that situation?

The solution is encrypting your storage and keep your key safe from others’ access. You can encrypt your home directory or a whole data partition. (Some even encrypts /boot, /swap and /(root) – full disk encryption – so that their activities leave no traces). With Linux, every tools is at your hand, so let start making your life easier. Below is some guide lines on how to do it on Debian.

1.   Install eCryptfs: a Linux native and POSIX – compliant enterprise – class stacked cryptographic file system.

$ aptget install ecryptfsutils
$ modprobe ecryptfs
# you may have to patch your kernel in order for
# ecryptfsd (the key management daemon of eCryptfs)
# to work. in that case, you’d better grab and
# build eCryptfs from the latest source.

2.   Setup eCryptfs:

# simple setup, passphrase entered from stdin,
# eCryptfs allows overlay mounting: mount point
# and the actual storage can be the same.

$ mountt ecryptfs /encrypted/storage /mount/point
# you can now see your new fs using the command df,
# test it, go to your mount point and input some
# data, watch the output at the encrypted storage.
$ cd /mount/point
$ echo “Hello World” > hi.txt
$ cd /encrypted/storage
$ less hi.txt
# umount /mount/point and the file system
# is not accessible anymore

HOW TO PROTECT YOUR KEY?

Every security solution comes to a very dead-end that there’s must be a MASTER KEY as the main entrance for the whole system. And we have several ways to protect the master key:

+   the tricky way: store the key somewhere on the disk, e.g: at the first sector of the volume image (offset some bytes to a position only you know) so that the key is hard to find and can not be accidentally deleted. More information about the trick is here.

+   the explicit way: store on an external storage such as usb, the system could only be functional once the usb is plugged in.

+   the “smart” way: smart card is the best way to store key. Since you can write public / private key to a smart card but can only read public key back, no – one can read the private key, including you. Smart card is designed to do encryption / decryption jobs: just request the card to encrypt / decrypt some data using a specified key, and the card sends back the required output.

In an organization, the private key is stored on smart card and given to the “person in charge” without the fear of loosing the key. For personal use, I think the second solution (using usb) is quite enough.

1.   Setup smart card:

# install pcscd, the daemon to talk with
# card reader install OpenSC, the open
# source smart card project

$ aptget install pcscd
$ aptget install opensc
# in my case, I have an Axalto reader which is not
# supported by pcscd. knowing that Axalto’s
# hardwares are OEM-ed from SCM, I just download
# the firmware from SCM, flash the reader and it’s
# then recognized as a SCM SCR 331 device. You can
# play around the smart card using opensc-tool,
# you can erase, init the card’s file system,
# create some PIN, generate some keys using
# pkcs#15-init, encrypt/decrypt can be
# done using pkcs#15-crypt

2.   Working with keys:

Public and private keys are fundamental concepts of Digital Signature. In short, multiply two big prime numbers – two private keys – you have a semi-prime number – the public key. Certificate is wrapper of the public key to work with a CA (Certificate Authority), for the public to check if a public key really belongs to an organization.

# generate public and private keys in RSA 1024
# bit pem format extract the public key from this
# keys pair, encrypt/decrypt with the keys

$ openssl genrsaout private.pem 1024
$ openssl rsain private.pemout public.pemoutform PEMpubout
$ openssl rsautlencryptinkey public.pempubinin file.txtout file.ssl
$ openssl rsautldecryptinkey private.pemin file.sslout decrypted.txt
# create the smart card’s file system,
# then create a PIN

$ pkcs15initcreatepkcs15
$ pkcs15initstorepinauthid 01label “mycom”
# copy private key to smart card, to decrypt,
# we need to specify key’s usage

$ pkcs15initstoreprivatekey private.pemauthid 01id 45format pemkeyusage sign,decipher

3.   Setup the whole thing:

With your smart card properly setup (a public/private key pair has been stored), we can use the following script to: 1. create a temporary volatile file system 2. use smart card to decrypt the password and store to that file system (these files would simply disappear when the machine power down) 3. using the decrypted password to mount with eCryptfs.

# 1. create a volatile fs to temporarily store the
# decrypted passfile

$ mountt tmpfso size=10M,nr_inodes=10k,mode=0700 /tmp_fs
# 2. decrypt the password file from
# /root/passwd to /tmp_fs/passwd

$ pkcs15cryptpkcs1decipherk 45i /root/passwdo /tmp_fs/passwd
# 3. now mount our encrypted
# directories with eCryptfs

$ mountt ecryptfs /encrypted/storage /mount/pointo key=passphrase:passfile= /tmp_fs/passwd, cipher=aes, ecryptfs_key_bytes=16, passthrough=1, verbosity=0

Done! Choose a strong encryption algorithm (e.g AES 256 – bit), and in most cases, you and your data would be safe until they have quantum computer running. Be sure to keep your key secret or your efforts would be of no help. For maximum security, choose a good smart card model, increase your keys’ size, revise all procedures of your software system…

(You’re pretty safe right now, so why there’s an “in most cases” in my last paragraph? The truth of being secured is actually more complex than that, as a quite-simple technique like this could be applied to steal password of a disk-encryption system. This bases on the fact that data in DRAM is not faded right away after loosing power, it still can last for some seconds (or even minutes), and by cooling the DRAM using an air duster (to slow down the fading speed), the DRAM module could than be copied and scanned for password (assuming that password has been entered and kept in memory). Nothing is really safe, however, hardware problem like this should have a hardware solution (like this AES 256-bit encryption Fujitsu hard drives).

CMS 2.0 released

Some typical UI features:

Data & input validation using XPath

Custom-drawn combobox (with check-box item)

Custom-drawn grid with tens of thousand cells

Simple vector object editing

Custom-draw tree with loading effect

The CMS project, in which I’m the team leader, has come to it’s second phase, with major features completed. Although I felt tired with the on-going work, it’s my most beloved product. CMS (short for Central Management System) serves as a gateway through which clients manage the DVR Servers (Digital Video Recorder). The product demonstrates many technologies & programming techniques, just to name a few:

  • IOCP (IO completion port): the multi-threaded IOCP server has proved to be very efficient, hundreds of concurrent connections won’t rise CPU usage to higher than 5%. However, the connections are stateless, it’s best that we would add a state-machine to better control the traffic.

  • TCP + XML communication: we devise a draft protocol like XML-RPC or SOAP, which bases on TCP rather than HTTP.

  • XML data storage: all network command & data is presented in XML. With version-numbered XML, we hope to solve the backward compatibility problem ever existed with so many releases of our main DVR products.

  • XML processing is made easy thank to the wonderful TinyXML and TinyXPath libraries. I must emphasize that XPath makes XML processing much more feasible, it greatly reduces the number of LOC (line of code) and procedural complexity.

  • A sophisticated client MFC GUI demonstrates various GUI programming techniques, almost every tricks with MFC GUI has been gathered in this product: heavy custom-draw controls, flicker-freed rendering, advanced input validation…

  • Some borrowed concepts from other flatforms: the elegant “signal & slot” are added to handle complicated interaction between GUI’s elements (in addition to MFC’s message queue mechanism).

I have some lessons learned after the project:

  • It’s a MUST that you have a team with members of the same professional level. This would make sure the members would easily understand each others and share a common culture.

  • C/C++ is still a MUST for real time programming tasks (it’s “half-civilized nature” makes it a strong language). And the use of some matured flat-form: boost, wxWidget… would greatly help the developing process.

  • It’s only by the desire for creation & creativity that programmer would offer an excellent product. The culture of a developing team is somewhat like honey-bees, who collect pollen little by little to make honey and wax.

I’ve been involved in many projects, some is more interesting, some is more difficult than this one. But this is the first one that I’d made, everything from A to Z. It’s now time to leave I3 but I must say this is the project that I loved and two years at I3 was a special time in my career! Looking at the screenshots below, you would see that CMS is very rich in it’s designs about information presentation.

how to be a good programmer?

After a while, too tired and indisposed with parts of our commnunity, I try to figure out what I’m expecting myself and others to behave, what are the characteristics that this career requires. Then I found out this how-to document. We’ve seen too many how-to on the web: how to setup Apache with SSL, how to date a girl, how to build your own business … But this is a real how-to, in a programmer’s usual style, concised, practical, and shows a right attitude towards our job. I’ve made a Vietnamese translation of this document. Let taste our career as serious and gentle as it could be.

GIỚI THIỆU

Lập trình viên là một nghề khó khăn và cao quý. Phần khó nhất có lẽ là làm việc với các đồng nghiệp và khách hàng. Viết chương trình khéo là một kỹ năng lớn, nhưng chỉ là trò trẻ so với những thứ khác mà một lập trình viên phải làm để một hệ thống phần mềm thành công. Trong tài liệu này, tôi tóm tắt ngắn gọn những điều tôi ước có ai đó chỉ cho tôi lúc tôi 21 tuổi. Những điều viết ra đây chỉ mang tính chất cá nhân, và phần nào bảo thủ. Một số vấn đề khá chung nên có thể nghe nhàm chán. Nhưng tôi hy vọng chúng sẽ có ích.

Chào mừng đến với cộng đồng !

I.       CHO NGƯỜI MỚI VÀO NGHỀ

I.1.    CÁC KỸ NĂNG CÁ NHÂN

I.1.1  HỌC CÁCH DEBUG

Debug là nền móng của công việc lập trình. Nghĩa đầu tiên của động từ debug là sửa lỗi, nhưng nghĩa thực sự cần hiểu là: xem xét quá trình thực thi của một chương trình. Một lập trình viên không biết debug thì xem như bị mù trong nghề của mình vậy.

Những người có cái nhìn lý tưởng về nghề lập trình thường xem lập trình bao gồm thiết kế, phân tích, các lý thuyết về độ phức tạp, vân vân… Nhưng thực sự những điều đó không phảI là những nền móng của nghề này. Chúng ta không sống trong thế giới lý tưởng và ngay cả khi bạn cảm thấy mình là lý tưởng và hoàn hảo thì những điều xung quanh bạn cũng không phải vậy. Phần lớn các mã nguồn đều không hoàn hảo, và tài liệu của chúng càng như vậy. Thiếu cái nhìn vào bên trong quá trình thực thi của một đoạn mã đến lúc sẽ gây rắc rối cho bạn.

Nhiều gói phần mềm được mua từ các hãng thứ ba, và bạn không có cơ hội xem mã nguồn của chúng. Nhiều đoạn mã nguồn thực thi không đúng như tài liệu kỹ thuật của chúng. Nhiều khi bạn viết một đoạn code có lỗi mà vẫn không hiểu vì sao nó gây lỗi (điều này thường là vì bạn đã ngầm định một số điều kiện nào đó, nhưng thực tế những điều đó không xảy ra). Đôi khi đọc kỹ càng từng dòng code một sẽ tìm được lỗi, nhưng nhiều khi không thể phát hiện được chúng bằng cách này. Khi đó thì phải debug thôi.

Những cách debug thông thường:

  • Dùng một công cụ debug
  • In ra từng dòng một
  • Log

Các công cụ debug rất tuyệt nếu chúng ổn định. Công cụ debug của một ngôn ngữ thường phát triển chậm hơn ngôn ngữ đó, nhiều khi bạn không thể tìm được một công cụ debug tốt. Hơn nữa, trong quá trình debug, các công cụ này có thể đã thay đổi quá trình thực thi của chương trình. Nên các công cụ sau là quan trọng hơn.

Nhiều người mới vào nghề thường sợ sửa code khi debug. Nhưng debug cũng như phẫu thuật vậy, bạn phải loay hoay trong đống code với nhiều thử nghiệm khác nhau. Nếu bạn sợ việc này thì tốt nhất hãy tìm sự giúp đỡ ở một người có nhiều kinh nghiệm hơn bạn.

I.1.2  DEBUG BẰNG CÁCH CHIA NHỎ KHÔNG GIAN BÀI TOÁN

Đầu tiên debug là một công việc thú vị. Nó giống như bạn đi thám hiểm, một không gian bạn nghĩ nó phải như thế này nhưng thực sự nó không giống như vậy. Debug đòi hỏi tính sáng tạo. Và nếu có chìa khóa nào cần biết để debug thì đó là dùng kỹ thuật chia để trị (devide to conquer).

Ví dụ như một đoạn code làm 10 công việc. Bạn viết xong, thế rồi nó crash, mà bạn không viết nó để nó crash. Thế là bạn phải debug, nhìn trên màn hình output, bạn thấy 7 việc đầu tiên vẫn bình thường, như vậy nghi ngờ của bạn là nó có thể crash ở việc #7, #8 hay #9. Như vậy không gian tìm kiếm đã thu hẹp lại. Và luôn có trong đầu một vùng để nghi ngờ như vậy sẽ giúp bạn tìm ra chỗ sai. Rất nhiều khi, một nhóm lập trình viên tập trung cho một lỗi được phát hiện, dưới sức ép của deadline đang đến gần, nhưng dưới sức ép đấy, không ai giữ được sự tập trung trong không gian tìm kiếm của mình, hoặc không biết cách chia xẻ không gian đấy với nhau.

Nó cũng giống như việc thiết kế thuật toán: nếu bạn biết cách chia nhỏ không gian tìm kiếm thì thực sự bạn sẽ không phải chia nhỏ nó quá nhiều lần. Và luôn giữ sự tập trung vào một miền không gian nào đó. Nhưng đâu là miền không gian bạn cần phải tập trung? Đây là vấn đề của kinh nghiệm và sự sáng tạo.

Với người mới vào nghề thì dường như lỗi có thể ở mọi nơi: bạn không có được cái nhìn về các phương diện (dimension) khác nhau của chương trình: các dòng mã, cấu trúc dữ liệu, quản lý bộ nhớ, tương tác với các thư viện bên ngoài… Với người có kinh nghiệm, chính những chiều khác nhau này tạo nên cái mô hình không hoàn hảo nhưng lại có ích để biết được chỗ sai có thể nằm ở đâu. Và nắm bắt được mô hình này sẽ giúp cho việc định hướng trong không gian tìm kiếm.

Không phải khi nào bạn cũng có thể thu hẹp được không gian tìm kiếm đến một dòng mã code nào đó, và nếu như thế thì bạn may mắn. Thường thì lỗi không nằm tại một dòng mã, hay một đoạn mã, mà có thể có tình huống như: “trong đồ thị đó (cấu trúc dữ liệu) có con trỏ nào trỏ sai không?”, và bạn cần viết một chương trình khác để kiểm tra điều này.

I.1.3  SỬA LỖI NHƯ THẾ NÀO

Khi bạn đã tìm ra lỗi, tiếp theo là việc sửa nó. Hãy làm theo cách nào đòi hỏi ít thay đổi nhất. Cũng có khi bạn phát hiện ra nhiều thứ khác cần cải tiến, nhưng hãy chỉ làm một việc tại một thời điểm thôi. Nhiều khi có nhiều lỗi trông giống như nhau, hãy định nghĩa từng lỗi riêng biệt và sửa từng cái một. Đôi khi bạn không rõ đoạn mã đó làm gì hay ý tác giả ban đầu như thế nào. Khi đó cần phải thử nghiệm và phán đoán để quyết định ý nghĩa của đoạn mã đó. Đây là một kỹ năng không phải của người mới vào nghề, và thường là khó hơn cả việc viết chúng lúc ban đầu. Nhưng thế giới thực là như vậy, bạn phải sửa nó vì bạn không thể tạo ra nó.

I.1.4  DÙNG LOG NHƯ THẾ NÀO

Log khác với việc in ra từng kết quả một tạm thời. Người mới vào nghề cần log vì kinh nghiệm của họ hạn chế. Kiến trúc sư hệ thống cần log vì hệ thống thực phức tạp. Tốt nhất là bạn có thể cấu hình mức độ ít nhiều thông tin trong log-file ngay khi chương trình đang chạy. Log có những lợi điểm sau:

  • Log lưu thông tin về các lỗi khó lập lại (reproduce), nhất là những lỗi chỉ xuất hiện trong hệ thống thực mà không xuất hiện ở các hệ thống test.
  • Log có thể cho các con số thống kê về hiện suất của hệ thống (thời gian thực thi các tác vụ…)
  • Khi có thể cấu hình được, log cho phép bạn sửa những lỗi mới mà không phải sửa hay xem xét lại nhiều các đoạn code chỉ để đối phó với một dạng lỗi ấy.

Quá nhiều thông tin trong log-file sẽ gây rối việc tìm kiếm, quá ít sẽ không có điều bạn cần tìm. Vậy nên cần phải tạo log-file sao cho có thể cấu hình tính nhiều/ít thông tin này được. Mỗi record trong log-file thường có: vị trí trong mã nguồn, thread nào đang thực thi, thời gian thực thi, giá trị của các biến, lượng bộ nhớ còn trống… Những đoạn mã ghi ra log-file có thể ở khắp nơi, cần nhất là ở những chức năng quan trọng và các đoạn mã nguy hiểm (có khả năng gây nhiều lỗi). Mỗi đoạn mã ghi log-file cần được gán một mức độ quan trọng, và bạn điều chỉnh cái gì cần ghi ra bằng cách thay đổi mức độ quan trọng này. Log được thiết kế cho các vấn đề mà bạn lường trước, và luôn lường trước vấn đề hiệu suất của hệ thống.

I.1.5   HIỂU VẤN ĐỀ HIỆU SUẤT CỦA HỆ THỐNG NHƯ THẾ NÀO

Vấn đề hiệu suất của hệ thống cũng có cùng lý do như việc debug. Ngay cả khi bạn hiểu một đoạn code đủ rõ, thì không có nghĩa là nó sẽ chạy tốt, đôi khi nó gọi hàm từ một thư viện bên ngoài nào đó, mà bạn thì không kiểm soát được thư viện này. Thực tế thì vấn đề hiệu suất cũng không khác và không dễ hơn việc debug. Nếu hệ thống quá chậm, bạn cần xác định do đâu mà nó chậm, và do đó cần xây dựng một mô hình về vấn đề này. Có câu châm ngôn nổi tiếng là: 90% thời gian được chi trên 10% lượng mã nguồn. Theo kinh nghiệm của tôi, phần lớn thời gian chậm là chi vào các thao tác nhập xuất (I/O) theo cách này hay cách khác.

Có nhiều lý do khác ảnh hưởng đến hiệu suất hệ thống. Nhưng đầu tiên là hãy đo thời gian thực thi của các đoạn mã. Log lại điều này rất quan trọng vì đôi khi chúng cho ta biết tình huống mà các kỹ thuật profiling khác không phát hiện được. Đôi khi một hàm thực thi chậm hơn vài giây so với khi bạn đã sửa chúng, nhưng thực sự thì vẫn tốt hơn vì có thể các chi phí khác (bộ nhớ, băng thông, cơ sở dữ liệu…) sẽ đắt hơn khi đưa hệ thống vào chạy thực.

Các tài nguyên chia xẻ không được đồng bộ hóa đúng có thể dẫn đến deadlock, hay starvation. Nếu có thể hãy lường trước các vấn đề này từ lúc bắt đầu dự án.

I.1.6  SỬA VẤN ĐỀ HIỆU SUẤT HỆ THỐNG NHƯ THẾ NÀO

Chọn các giải pháp đơn giản và nhanh chóng dưới sức ép của thời gian là một việc làm khôn ngoan. Nhưng hiệu suất là một phần của sản phẩm, và do đó phải cân nhắc vấn đề này kỹ lưỡng. Chìa khóa là: biết các cổ chai (bottleneck) của hệ thống nằm ở đâu, hay chỗ nào tiêu thụ nhiều tài nguyên nhất. Việc tối ưu một hàm chạy nhanh hơn 1% thực sự chẳng có mấy ý nghĩa, và bạn chỉ nên làm điều này khi bạn nghĩ bạn có thể làm cho hệ thống chạy nhanh gấp đôi so với trước. Cân nhắc các chi phí testing và QA đối với những thay đổi này. Ngay cả khi bạn đã làm cho hệ thống chạy nhanh gấp đôi, hãy phân tích lại để tìm ra những bottleneck còn lại, để có thể làm cho hệ thống chạy nhanh thêm gấp đôi nữa.

Thường thì việc tìm các bottleneck sẽ giống như việc đếm bò bằng cách đếm số chân rồi chia cho 4 thay vì đơn giản hơn bạn có thể đếm số đầu. Ví dụ như: không làm chỉ mục cho một trường sử dụng rất nhiều lần trong cơ sở dữ liệu có thể làm cơ sở dữ liệu đó chạy chậm hơn 20 lần. Những cải tiến dạng này thường được gọi là low-hanging fruit, có thể dễ dàng hái chúng để có được lợi ích. Khi những quả ở thấp đã hết, bạn sẽ phải leo lên cao hơn. Bạn có thể cần cù làm những cải tiến nhỏ trên cao này, hoặc bạn có thể thiết kế lại toàn bộ hệ thống. Đây là cơ hội để chứng tỏ bạn là một lập trình viên thực thụ, nhưng chỉ làm thế khi đề nghị của bạn có thể làm cho tình huống 5 hay 10 lần tốt hơn.

I.1.7  TỐI ƯU CÁC VÒNG LẶP NHƯ THẾ NÀO

Đôi khi bạn gặp một vòng lặp tạo nên bottleneck của hệ thống. Trước khi tìm cách cải tiến vòng lặp cho nó nhanh hơn một chút, hãy cân nhắc xem có cần đến vòng lặp này không đã: có thuật toán nào khác không cần đến lặp, hay thực sự thông tin đã được tính toán đâu đó rồi? Nếu không làm được vậy thì việc tối ưu hóa vòng lặp cần đến hiểu biết về các chi phí của từng lệnh cụ thể, một số gợi ý:

  • Tránh các phép tính dấu chấm động (floating point operation).
  • Không cấp phát bộ nhớ một cách không cần thiết.
  • Ghép các hằng số lại với nhau.
  • Đem các thao tác I/O vào một bộ đệm (buffer)
  • Tránh các phép chia
  • Tránh ép kiểu
  • Dùng con trỏ thay vì tính toán lại chỉ mục

Chi phí của những việc cụ thể này còn phụ thuộc hệ thống. Một số trình biên dịch và phần cứng làm những việc tối ưu này cho bạn. Nhưng dù sao mã hiệu quả vẫn tốt hơn.

I.1.8  XỬ LÝ CÁC THAO TÁC NHẬP XUẤT (I/O) NHƯ THẾ NÀO

Thường thì CPU nhanh hơn các thiết bị ngoại vi như đĩa, mạng, database… Nên việc tối ưu hệ thống thường không phải là việc tối ưu một vài vòng lặp, mà tối ưu các thao tác nhập xuất. Có hai kỹ thuật cơ bản:

  • Caching: tránh các thao tác I/O không cần thiết bằng cách lưu các giá trị thường truy cập ở một nơi nào đó. Có điều nguy hiểm với việc caching là các bản lưu này đôi khi không được cập nhật với bản gốc.
  • Representation: tìm cách biểu diễn data hiệu quả hơn. Nhưng cũng cần xem xét đến các yêu cầu khác: rõ ràng với người đọc, có thể dễ dàng chuyển đổi qua các dạng khác… Kinh nghiệm cho thấy việc biểu diễn có thể được tối ưu 2 hay 3 lần so với phiên bản biểu diễn đầu tiên. Kỹ thuật: biểu diễn nhị phân đi kèm với một từ điển các ký hiệu (để không phải mã hóa các ký hiệu quá dài), các thuật toán nén như mã hóa Huffman…

Một kỹ thuật thứ ba có thể được dùng: vị trí giải quyết vấn đề, nếu bạn cần một tính toán đơn giản trên một số data từ database (như một phép cộng), tốt hơn hãy nhờ đến database làm điều đó.

I.1.9  QUẢN LÝ BỘ NHỚ NHƯ THẾ NÀO

Bộ nhớ là tài nguyên quý giá không thể để cạn kiệt. Bạn có thể lơ vấn đề này một lúc, nhưng cuối cùng cũng phải nghĩ đến việc quản lý nó. Tùy vào hệ thống, có hệ thống bạn cần hủy bộ nhớ đã cấp phát một cách tường minh. Có hệ thống có thiết kế một “bộ phận thu nhặt rác” (garbage collector – GC), bộ phận này sẽ tự động giải phóng các phần bộ nhớ không cần đến mà không cần đến thao tác nào từ lập trình viên. Các GC rất có ích, dùng chúng bất cứ lúc nào có thể.

Tuy vậy, bạn có thễ vẫn để rác trong bộ nhớ. Một lỗi cổ điển như: dùng bảng băm và quên giải phóng các tham chiếu trong bảng băm đó, vùng nhớ vẫn còn tham chiếu đến mặc dù đã hết sử dụng. Vấn đề này gọi là rò rỉ bộ nhớ (memory leak). Bạn phải để ý vấn đề này từ sớm, một số hệ thống không cho thấy vấn đề bộ nhớ nào lúc test, nhưng sẽ nãy sinh vấn đề trong môi trường sử dụng thật.
Nếu bạn có thể định nghĩa một chặn trên (upper bound) cho các đối tượng (cùng kích thước) cần cấp phát, bạn nên cấp phát cả một vùng đệm (buffer) một lúc để lưu chúng. Nếu có thể, hãy cấp phát và giải phóng các đối tượng bên trong vùng đệm này theo kiểu xoay vòng (ring-buffer). Điều này thường nhanh hơn là cấp phát trong heap.

Đôi khi bạn cần phải giải phóng tường minh một đối tượng (để cấp phát lại chẳng hạn) và không thể nhờ đến GC. Hãy cẩn thận, hãy chắc chắn rằng tương ứng với một lệnh cấp phát là một lệnh giải phóng. Điều này thường rất khó, thường thì lập trình viên sử dụng một dạng GC đơn giản nào đó (như đếm tham chiếu – reference counting) để làm việc này.

I.1.10  ĐỐI PHÓ VỚI CÁC LỖI BẤT CHỢT NHƯ THẾ NÀO

Có những lỗi thực sự là ác mộng, chúng lúc nắng lúc mưa, ít xảy ra đến độ dường như không nắm bắt được, và không thể debug vì không biết chúng ở đâu. Dường như chúng chỉ xảy ra sau 8 giờ làm việc, khi bạn bắt đầu nghi ngờ chúng có tồn tại hay không. Điều làm cho chúng khó nhận ra là bạn không biết chúng xảy ra trong điều kiện nào: tìm cách ghi nhận tình huống xảy ra, hoặc cũng có thể lỗi chỉ xảy ra với một dạng đặc biệt nào đó của dữ liệu, ví dụ như “nó chỉ xảy ra khi có từ wyoming trong dữ liệu nhập vào”. Sau hết, nếu không phải là các nguyên nhân này, hãy nghĩ đến lỗi đồng bộ hóa tiến trình.

Nếu không thể lặp lại lỗi (reproduce), hãy tìm cách bẫy nó. Bố trí lại hệ thống log theo các hướng bạn phán đoán. Đôi khi điều này cũng không đem lại kết quả gì ngoài việc bạn biết cách cải tiến hệ thống log tốt hơn, và điều đó có thể giúp bạn bẫy được những lỗi này về sau.

Lỗi ngu ngốc nhất tôi từng gặp phải là trong một chương trình có nhiều tiến trình, tôi đã kiểm tra kỹ lưỡng việc đồng bộ hóa các tiến trình nhưng quên đồng bộ hóa GC. Hệ thống kết thúc tốt đẹp mọi tác vụ trước khi lỗi xảy ra, và điều ngu ngốc hơn nữa là tôi lúc đó đã bắt đầu nghi ngờ phần cứng có vấn đề trước khi biết được lỗi là do phần tôi.

I.1.11  HỌC CÁC KỸ NĂNG THIẾT KẾ NHƯ THẾ NÀO

Để học cách thiết kế, hãy quan sát các hành động của người làm điều đó. Sau đó xem xét các gói phần mềm viết tốt, và có thể đọc một vài cuốn sách mới nhất về vấn đề này. Sau đó thì hãy tự bạn làm, khởi đầu với các dự án nhỏ. Sau khi thành công hay thất bại, tìm cách hiểu xem bạn đã ly khai khỏi các ý tưởng sơ khởi như thế nào. Sau đó làm các dự án lớn hơn, với nhiều người thiết kế hơn. Thiết kế là kỹ năng đánh giá chỉ có được sau nhiều năm. Một lập trình viên có thể học các điều cơ sở chỉ sau vài tháng và cứ thế tiến bộ. Nhưng thiết kế thì khác, nó là vấn đề nghệ thuật hơn là khoa học, và những người viết sách về vấn đề này thường cố trình bày như chúng rất là khoa học, nhưng cũng đừng tin một cách giáo điều, võ đoán theo những sách đấy.

I.1.12  TIẾN HÀNH THỬ NGHIỆM NHƯ THẾ NÀO

Edsger Dijkstra đã hùng hồn giải thích rằng khoa học máy tính (CS) không phải là một khoa học thực nghiệm và không phụ thuộc vào các máy tính điện tử, ông ta nói những điều này vào những năm 1960:

Tội ác đã hoàn tất! Khoa học này đã được gọi bằng cái tên: Khoa học Máy tính, theo cùng một cách như bạn gọi Giải phẫu học là Khoa học Con dao, và điều đó khiến cho mọi người nghĩ rằng khoa học máy tính là về các máy móc cũng như các thiết bị ngoại vi của chúng. Do đó lập trình cũng không thuộc về khoa học thực nghiệm.

Nhưng phần lớn lập trình viên không có được cái xa xỉ mà Dijkstra nói đến. Chúng ta làm việc trong một lĩnh vực cũng giống như một số nhà vật lý học (thực hành) làm vậy. Nếu như trong vòng 30 năm nữa mà lập trình không còn cần đến thử nghiệm nào thì đó là một thành tựu lớn lao của Khoa học Máy tính. Những dạng thử nghiệm cần tiến hành bao gồm:

  • Test các hệ thống với các ví dụ nhỏ để kiểm chứng nó có chạy đúng như tài liệu nói không, hay để hiểu các tác vụ của chúng khi không có tài liệu.
  • Test các thay đổi để xem chúng có thực sự sửa được lỗi không.
  • Đo hiệu suất của hệ thống dưới các điều kiện khác nhau vì không biết các đặc điểm về hiệu suất này.
  • Kiểm tra tính toàn vẹn của dữ liệu.
  • Thu thập số liệu thống kê để tìm giải pháp cho các vấn đề khó.

Tôi có hai lời khuyên cho việc này:

  • Hãy làm cho các giả thiết của bạn rõ ràng, nếu có thể, viết chúng ra giấy.
  • Bạn thường tiến hành các thí nghiệm dựa trên kết quả của thí nghiệm trước. Do đó hãy thiết kế các thí nghiệm (các bài test – ND) làm sao để nó có thể cung cấp nhiều thông tin nhất. Và cân bằng với yêu cầu đơn giản của thí nghiệm là một kinh nghiệm bạn chỉ có được với thời gian.

 

I.2.    CÁC KỸ NĂNG NHÓM

I.2.1  TẠI SAO ƯỚC LƯỢNG QUAN TRỌNG

Một dự án phần mềm không chỉ bao gồm việc coding mà còn thiết kế, làm tài liệu, testing, và các công việc kinh doanh… Nếu không đoán trước được tiến độ phát triển, sẽ không thể có kế hoạch hiệu quả được.

Ước lượng tốt giúp dự đoán tốt. Những nhà quản lý thích điều đó, và họ cũng nên làm điều đó. Thực tế là, trên cả phương diện lý thuyết lẫn thực hành, không thể dự đoán chính xác thời gian cũng như chí phí để làm tất cả những công việc đó. Chúng ta được đòi hỏi làm những điều có thể làm được, do đó thật không hay khi thú nhận không thể làm được chúng. Có rất nhiều chuyện hiểu lầm trong việc ước lượng, ví như thường thì người ta, thật ngạc nhiên, có xu hướng hiểu câu sau một cách khôn ngoan:

Tôi ước lượng rằng, nếu tôi thật sự hiểu vấn đề, thì khoảng 50% chắc chắn là chúng ta sẽ xong việc đó trong vòng 5 tuần (nếu không ai quấy rầy chúng ta suốt thời gian đó).

Như sau:

Tôi hứa sẽ làm xong tất cả trong vòng 5 tuần kể từ bây giờ.

Những kiểu diễn dịch này đòi hỏi bạn phải thảo luận rõ ràng tất cả những ước lượng đó nghĩa là gì, với ông chủ cũng như với khách hàng, cứ như họ là những người ngu ngốc. Và lặp đi lặp lại điều đó cho dù họ có tỏ ra như thế nào.

I.2.2  ƯỚC LƯỢNG NHƯ THẾ NÀO

Ước lượng cần phải được thực tập, và nó cũng tốn nhiều công sức. Và nó tố nhiều công sức đến nỗi chúng ta cần ước lượng thời gian chúng ta cần để ước lượng thời gian làm công việc thực sự, nhất là khi bạn được yêu cầu làm một khối lượng công việc lớn. Nếu phải ước lượng một điều gì lớn, điều lương thiện nhất bạn cần làm là trì hoãn. Sẽ có nhiều lập trình viên khác thông cảm cho điều này. Dĩ nhiên sẽ có người không hài lòng vì điều đó, nhưng một ước lượng tức thì có thể sẽ không chính xác. Trong lúc trì hoãn, bạn có thể tìm cách làm hoặc phác thảo việc cần làm. Và nếu bầu không khí tại nơi làm việc cho phép, đây là cách tốt nhất để ước lượng, hơn nữa, nó cũng đóng góp vào tiến độ thực sự.

Nếu không thể trì hoãn, bạn cần trước nhất phát biểu ước đoán của mình thật rõ ràng. Viết lại phần ước đoán của mình ở cuối phần văn bản viết, và trong phần kế hoạch viết, chia nhỏ các công việc sao cho các công việc con chỉ cần tối đa 1 ngày để hoàn thành. Điều quan trọng nhất là không để sót điều gì, ví dụ như: phần viết tài liệu, phần testing, thời gian lên kế hoạch, thời gian tương tác với các nhóm khác, và cả thời gian nghĩ. Nếu mỗi ngày, bạn cảm thấy cần nhiều thời gian hơn vì phải làm việc với những kẻ ngu đần thì gộp cả thời gian đó vào trong kế hoạch. Những điều này cho phép ông chủ biết bạn ít nhất đang làm gì, vì thực sự bạn sẽ cần nhiều thời gian hơn. Tôi biết có những kỹ sư lập trình tốt, những người ngầm tính thêm một khoảng thời gian vào thời gian đã ước lượng. Nhưng tôi khuyên bạn không nên làm vậy, vì sự tin tưởng ở nơi bạn có thể bị giảm sút. Ví dụ một lập trình viên ước lượng 3 ngày cho một công việc anh ta có thể làm trong 1 ngày, và 2 ngày dư ra, anh ta có thể chỉ ngồi viết tài liệu hay làm việc khác. Nếu việc ấy bị phát hiện, sẽ có ý kiến cho rằng bạn lười nhác hay ước lượng quá. Tốt hơn là bạn cho phép Người ta nhìn rõ vào tiến trình bạn làm việc.

Thay vì như vậy, bạn có thể tính thêm một khoảng thời gian một cách công khai. Ví dụ như công việc mất một ngày, nhưng cũng có thể 10 ngày nếu cách tiếp cận không đúng, thì hãy ghi điều đó vào ước lượng của bạn, hay ít nhất tính trung bình trên các ước lượng khác của bạn. Bất kỳ yếu tố rủi ro nào cũng cần được xác định và đưa vào lịch làm việc. Nếu công ty có những khóa học bắt buộc thì cũng phải thêm thời gian đó vào. Dĩ nhiên vẫn sẽ còn lại những thứ không thể xác định, hay nghĩa là không thể được xác định bởi một cá nhân. Tạo thêm một mục cho điều này và làm cách nào đó để sếp của bạn biết, và làm sao cho sếp bạn phải biết, vì rất dễ sau đó ước lượng sẽ trở thành kế hoạch. Trong một nhóm, bạn cũng sẽ cần những người làm các công việc cụ thể có ước lượng của mình, và bạn cũng sẽ cần sự nhất trí của các nhóm khác. Mọi người rất khác nhau về kỹ năng, kinh nghiệm, mức độ sẵn sàng, tính tự tin… Tai họa đến khi một lập trình viên giỏi ước lượng theo khả năng của anh ta sau đó giao công việc cho một lập trình viên kém. Việc có được sự đồng ý của mỗi thành viên trong nhóm trên mỗi dòng của bản ước lượng sẽ giúp cả nhóm hiểu, đó cũng là cơ hội để có thể có được sự phân chia tốt nhất.

Nếu có những rủi ro chưa thể lượng giá, thì bạn phải gào lên làm sao cho giám đốc của bạn không ủy thác điều gì trong nhiệm vụ đó và sẽ không ngạc nhiên, bối rối khi nó xảy ra. May thay, thường trong những trường hợp đó, tất cả những gì có thể làm sẽ được làm để giảm thiểu rủi ro. Nếu bạn có thể thuyết phục công ty bạn dùng Extreme Programming, thì bạn sẽ chỉ cần ước lượng các việc tương đối bình thường, và sẽ có được hiệu suất tốt hơn.

I.2.3  TÌM THÔNG TIN NHƯ THẾ NÀO

Bản chất của vấn đề bạn cần biết xác định cách bạn sẽ tìm chúng. Nếu bạn cần thông tin về các đối tượng cụ thể, dễ xác định (như bản vá sau cùng của một sản phẩm), thì chỉ cần hỏi ai đó, tìm trên internet, hay gởi bài trong các diễn đàn thảo luận. Nếu bạn có được kiến thức chung về những thứ đã có chủ đề, thì hãy tìm nó ở thư viện. Nếu bạn cần biết cách làm một điều gì đó khó, thì thường cần đọc 2, 3 cuốn sách về chủ đề đó, những thứ dễ đã có trên internet. Nhưng bạn rất dễ tốn nhiều thời gian chỉ để tìm kiếm, và sắp xếp những thứ kiếm được, và tìm hiểu về nguồn gốc của chúng, hơn là thực sự nắm bắt những điểm quan trọng trong đó.

Nếu bạn cần thông tin về những thứ mà bạn không nghĩ sẽ có ai khác biết, đầu tiên vẫn cần tìm trên internet, ở thư viện, và nếu đều không có kết quả thì phải thăm dò vấn đề đó bằng những thí nghiệm. Nếu bạn cần những đánh giá chuyên môn, tốt nhất là bạn có được những chuyên gia.

Nếu bạn cần quyết định những chuyện cá nhân chỉ có bạn quyết định được, ví như có nên làm công ty riêng hay không, thì hãy viết một danh sách những điều nên, và không nên. Nếu điều này cũng không giúp gì, thì hãy xem xét việc tin vào chiêm tinh bói toán. Và nếu bạn đã hỏi ý kiến tất cả các thiên thần, đã suy xét tất cả hệ quả, những điều thuận lợi và khó khăn mà vẫn chưa quyết định được, thì hãy bảo đầu bạn câm mồm lại và nghe theo con tim bạn. Tất cả các dạng chiêm tinh bói toán đều có tác dụng xác định các ước mơ nửa thức nửa ngủ của bạn, vì mỗi ước ao đại diện cho một mẫu tình cờ và mơ hồ mà tiềm thức của bạn sẽ tự gán cho nó những ý nghĩa.

I.2.4  DÙNG NGƯỜI KHÁC NHƯ NGUỒN THÔNG TIN NHƯ THẾ NÀO

Hãy tôn trọng thời gian của người khác và tìm cách cân bằng nó với của bạn. Hỏi người khác một câu thì sẽ được nhiều hơn là một câu trả lời. Bạn sẽ biết về người khác theo một cách nào đó, và thường thì điều đó quan trọng hơn câu hỏi. Nhưng thường thì những giá trí này càng ít đi nếu bạn càng làm nhiều nó. Thời gian bạn cần nói chuyện với các đồng nghiệp tùy thuộc vào vai trò của họ (hơn là vị trí của họ). Bạn nên nói chuyện với những người cao hơn bạn, ít nhất là một lần một tháng. Quy luật rất đơn giản: mọi người có lợi khi nói chuyện với nhau, nhưng nói càng nhiều thì lợi càng ít, do đó cần phải cân đối với chi phí (là thời gian bạn trò chuyện). Nếu nói chuyện với ai đó có thể tiết kiệm thời gian của bạn thì bạn nên trò chuyện với người đó, trừ khi bạn nghĩ là thời gian của người đó quý giá hơn của bạn.

I.2.5  LÀM TÀI LIỆU NHƯ THẾ NÀO CHO KHÔN NGOAN

Cuộc đời quá ngắn để viết những thứ tào lao không ai đọc. Nên chỉ cần một it tài liệu tốt vẫn tốt hơn. Những người làm quản lý thường không hiểu điều này, vì những tài liệu tệ đã làm họ quá chán với những thứ lập trình viên viết ra. Nếu ai đó khăng khăng đòi bạn viết những thứ tài liệu tào lao, giả tạo, thì cứ nói và sau đó yên lặng tìm một công việc khác tốt hơn. Thực tế thì thật là lạnh lẽo: làm tài liệu, cũng như testing, hay coding thường cần nhiều thời gian hơn dự tính.

Để viết tài liệu tốt, dĩ nhiên đầu tiên là viết tốt. Nhưng nếu bạn viết kém thì có một quy luật vàng: làm cho người khác đúng như cách người ấy sẽ làm với bạn. Dành thời gian suy nghĩ về ai sẽ là người đọc, họ cần biết điều gì từ tài liệu, và bạn có thể diễn đạt điều đó như thế nào. Nếu bạn làm được như vậy, thì chắc chắn bạn đã hơn một người viết tài liệu trung bình, và dĩ nhiên là một lập trình viên tốt.

Những lập trình viên tốt nhất tôi được biết có một đức tính chung: viết giải thích ngay trong code và chỉ viết tài liệu những nơi mà cần thiết. Như vậy có hai cái lợi: một là ai cần hiểu hệ thống sẽ có cơ hội đọc code, hai là như vậy thì code và tài liệu sẽ không có chỗ mâu thuẫn nhau. Cùng lắm thì code rối hoặc sai cũng chẳng sao, nhưng tài liệu mà sai thì nhiều lần tệ hơn. Nhưng giải thích trong code là sao:

  • Viết những mã mà biết chắc rằng có ai đó sẽ đọc nó.
  • Dùng luật vàng đã nói trên.
  • Chọn giải pháp dễ hiểu nhất, ngay cả khi bạn có một giải pháp nhanh hơn.
  • Bỏ những cải tiến nhỏ làm rối code.
  • Hãy nghĩ một chút về người đọc, và bỏ thêm thời gian làm những gì bạn viết dễ đọc hơn, và
  • Đừng bao giờ dùng những tên hàm như: foo, bar hay doIt.

I.2.6  LÀM VIỆC VỚI CODE TỆ NHƯ THẾ NÀO

Bạn sẽ rất thường gặp code ai đó viết rất tệ. Đừng nghĩ nhiều về điều đó, vì đôi khi bạn cũng sẽ như vậy, họ có thể đã làm việc rất nhanh để kịp tiến độ. Dù sao để làm việc với những code không rõ ràng, bạn cũng phải hiểu chúng, và điều đó tốn thời gian. Bạn sẽ phải đọc code, và đây là lúc để làm tài liệu. Có thể chỉ là để làm cho chính bạn thôi, nhưng điều này sẽ giúp bạn hiểu các khía cạnh khác của vấn đề, và tài liệu viết được sẽ đến lúc có ích. Bạn cũng có thể nghĩ đến việc viết lại toàn bộ hay một phần code, nhưng cần cân nhắc khi nào điều này.

Điều quan trọng cần nhớ là abstraction và encapsulation, là hai công cụ tốt nhất của lập trình viên, và cũng là cách trị code tệ hại. Vì bạn không thể thiết kế lại một khối code lớn, nhưng bạn có thể gói chúng vào một lớp trừu tượng nào đó và như vậy bạn cũng có thể có được một thiết kế chút ít tốt hơn mà không phải làm việc lại với toàn bộ code, hơn nữa, có thể cô lập một số code thực sự tệ để thiết kế lại riêng sau.

I.2.7  DÙNG SOURCE CODE CONTROL – SCC NHƯ THẾ NÀO

Các hệ thống kiểm soát phiên bản code là không thể thiếu được, ngay cả khi bạn làm việc đơn độc: nó theo dõi tất cả các thay đổi, không có sửa chữa nào mất đi, những code debug và code “vất đi” vẫn có thể được viết thoải mái và không ảnh hưởng đến nhánh code chính thức. Có thể hình dung một hệ thống như thế này một quần thể có tiến hóa, có nhiều thay đổi nhỏ và liên tục. Một lỗi lầm liên quan đến kiểm soát code làm ảnh hưởng đến toàn nhóm là một điều cấm kỵ.

I.2.8 UNIT-TEST NHƯ THẾ NÀO

Unit test là một phần của việc coding. Cũng như một phần của việc thiết kế code là thiết kế công việc test. Bạn nên viết xuống một kế hoạch test, ngay cả khi chỉ có một dòng. Đôi khi unit-test rất đơn giản: “cái nút nhìn có đẹp không?”, đôi khi lại là phức tạp: “thuật toán so sánh mẫu có trả về những phép so sánh đúng không?”

Dùng assertion và test driver bất kỳ lúc nào có thể. Điều này không chỉ bắt các lỗi sớm, mà còn ngăn chặn các “lỗi bí ẩn” về sau. Các lập trình viên của Extreme Programming có những bài viết rất hay về unit-test.

I.2.9 HÃY NGHỈ KHI RỐI TRÍ

Khi bạn rối trí, tốt nhất hãy nghỉ một lát. Tôi thường trầm tư khoảng 15 phút khi rối trí và thường thì vấn đề được giải quyết sau đó. Nhưng toàn diện hơn cả là một giấc ngủ đủ. Hay bạn cũng có thể chuyển qua một công việc hay hoạt động khác.

I.2.10 HÃY BIẾT KHI NÀO NÊN VỀ NHÀ

Lập trình là một hoạt động, và là một văn hóa. Nhưng không may, văn hóa đó không tôn trọng sức khỏe tinh thần và thể xác lắm. Lập trình viên thường bị làm việc quá mức, 60 giờ một tuần là phổ biến. Đây là vấn đề nghiêm trọng của lập trình viên, người có trách nhiệm không chỉ với anh ta mà với cả nhóm. Bạn cần biết khi nào phải về nhà, và đôi khi cũng nên đề nghị người khác về nhà. 60 giờ một tuần là quá mức với tôi, và tôi chỉ có thể chịu được như vậy trong khoảng 1 tuần. Thực tế đáng buồn là lập trình viên thường bị đòi hỏi làm việc nhiều chỉ để trình diễn cho ai khác xem, như là giám đốc muốn chứng tỏ cho ủy viên hội đồng quản trị xem. Mà lập trình viên thì thường không giỏi nói Không. Có bốn cách chống lại điều này:

  • Giao tiếp với mọi người trong công ty để không ai có thể lợi dụng một cơ hội như vậy.
  • Học cách ước lượng và lập lịch có phòng bị rõ ràng và cho mọi người xem điều đó.
  • Học cách nói Không, và cả nhóm nói Không, và
  • Cứ về nếu bạn phải thế

Lập trình viên thương thích làm nhiều việc, nhưng có một sức ỳ tâm lý trong lúc khởi động lúc giải quyết một vấn đề, và lúc bị chìm sâu vào vấn đề đó. Đa số các lập trình viên cảm thấy họ cần có một khoảng thời gian dài, không ngắt quảng để khởi động và tập trung. Nhưng ai cũng phải ngủ, và còn nhiều việc khác. Mỗi người cần tìm cách thỏa mãn cả nhịp điệu sinh học và nhịp điệu làm việc của mình, và tạo được giai đoạn làm việc hiệu quả.

Khi tôi có con, tôi đã thử ở với con về đêm, vì nhịp điệu làm việc hiệu quả của tôi là một ngày rất dài, và ngủ tại ngay văn phòng, chiều hôm sau thì về nhà sớm với các con trước khi chúng đi ngủ. Thực tôi cũng không thoải mái khi phải như vậy, nhưng mà đó là cách thỏa hiệp tốt nhất của tôi. Bạn cần phải về nhà nếu bạn đang mang bệnh có thể lây. Về nhà ngay khi bạn có ý nghĩ tự sát. Bạn cũng nên về nhà khi thoáng có ý nghĩ phải giết ai đó trong đầu. Bạn cũng nên ép ai đó về nhà nếu người ấy có biểu hiện tâm thần không bình thường hơn là chỉ chán nản mệt mỏi. Nếu bạn có những ý nghĩ không tốt vì mệt mà thường bạn không có, bạn cũng nên nghỉ. Đừng dùng thuốc an thần và đừng nghiện cà phê.

I.2.11 LÀM VIỆC VỚI NHỮNG NGƯỜI KHÓ TÍNH NHƯ THẾ NÀO

Bạn có thể sẽ gặp những người khó tính, hoặc chính bạn cũng có thể là người khó tính. Nếu bạn là kiểu người có nhiều mâu thuẫn với đồng nghiệp hay các nhân vật có quyền lực, bạn phải tự vui với sự độc lập mà cá tính bạn mang lại, và tìm cách làm việc với nhiều người mà không phải hy sinh các nguyên tắc và suy nghĩ của mình.

Điều này có thể rất phiền toái với một số lập trình viên, những người ít kinh nghiệm với kiểu người khó tính, và cuộc sống của họ có những kiểu cách không hợp lắm với không gian công việc Những người khó tính thường là người quen với những ý kiến bất đồng và ít bị ảnh hưởng bởi áp lực xã hội hơn những người khác. Chìa khóa ở đây là tôn trọng họ đúng mức: nhiều hơn bạn muốn, nhưng không nhiều như họ muốn.

Lập trình viên làm việc theo nhóm, và khi có bất đồng, không nên để lâu. Người khó tính thường lại là những người rất thông minh và họ có những cách rất hiệu quả. Điều rất quan trọng là bạn lắng nghe những người này mà không có định kiến gì. Tìm cách trao đổi một cách trầm tĩnh và chân thành, đừng mắc vào những cớ gây mâu thuẫn lớn hơn. Sau khi đã tìm cách hiểu hãy quyết định.

Đừng nghe theo sức ép của những kẻ bắt nạt. Nếu bạn là team-leader, làm điều bạn nghĩ là tốt nhất. Đừng quyết định vì lý do cá nhân, và chuẩn bị để giải thích quyết định của mình. Nếu cùng nhóm với một người khó tính, đừng để leader phải quyết định mang tính chất cá nhân, và nếu không đi con đường của bạn được thì đi con đường kia một cách thành tâm.

Những người khó tính vẫn có thay đổi và cải thiện. Tôi đã thấy, nhưng điều đó hiếm. Ai cũng có những lúc lên, xuống tạm thời. Và điều khó khăn, nhất là leader phải làm là làm sao cho những người khó tính bận bịu. Họ thiên về các công việc họ yêu thích và phản ứng tiêu cực hơn những người khác.

 

 

II      CHO TRÌNH ĐỘ TRUNG BÌNH

II.1.   CÁC KỸ NĂNG CÁ NHÂN

II.1.1. LÀM SAO ĐỂ LUỐN CÓ THÁI ĐỘ TÍCH CỰC

Điều ngạc nhiên và kỳ diệu trong giới lập trình viên là họ luôn bị thúc đẩy bởi mong muốn tạo ra những sự vật đẹp, có ích, thuận tiện. Điều này khá phổ biến trong giới lập trình viên và do đó phân biệt họ với những người khác, trong những vai trò khác.

Điều này có những hệ quả quan trọng và thực tế. Nếu bắt lập trình viên làm việc gì không đẹp, không ích lợi, họ sẽ cảm thấy miễn cưỡng khi làm. Làm những việc xấu xí, ngu ngốc, nhàm chán thì có nhiều tiền, nhưng tôi tin rằng, cuối cùng làm những việc vui vẻ sẽ mang lại nhiều lợi ích cho công ty nhất. Có những điều rất riêng biệt cho các lập trình viên giỏi:

  • Dùng ngôn ngữ tốt nhất cho công việc.
  • Tìm cơ hội áp dụng các kỹ thuật, công nghệ mới.
  • Tìm cách học hay dạy những điều mới, cho dù nhỏ.
  • Cuối cùng, tự quan sát công việc của mình dưới các khía cạnh khác. Ví dụ như khi tôi fix bug, số các bug fix được chẳng bao giờ làm tôi vui, vì nó chẳng nghĩa lý gì so với số bug còn phải fix, và chẳng đóng góp gì mấy về phía công ty. Nhưng với một bug nào đó, sự hài lòng của khách hàng cũng là một phần thưởng.

II.1.2 LÀM SAO ĐỂ ĐƯỢC TIN TƯỞNG RỘNG RÃI

Đầu tiên phải có mặt. Nếu chẳng ai thấy bạn thì không ai tin bạn được. Có những phản hồi nhiều thông tin với người khác. Nhiều khi người khác sẽ làm phiền bạn với sự tin cậy này, và có những đòi hỏi vô lý, khi đó hãy giải thích cho họ hiểu bạn phải bỏ điều gì khi phải đáp ứng họ. Đừng giả vời biết những điều bạn không biết. Với những người không ở trong nhóm của bạn, đôi khi phải phân biệt rõ giữa không thể biết được ngaydù sao cũng không có cách nào biết được.

II.1.3 CÂN BẰNG GIỮA KHÔNG GIAN VÀ THỜI GIAN NHƯ THẾ NÀO

Bạn có thể làm một lập trình viên giỏi mà không cần phải qua đại học. Nhưng một người có trình độ trung bình trong nghề này phải biết những kiến thức căn bản, như là lý thuyết độ phức tạp của tính toán chẳng hạn. Bạn không cần phải biết big O notation là gì, nhưng bạn cần phân biệt được tuyến tính với thời gian, n log n, và n bình phương khác nhau như thế nào. Bạn cũng vẫn có thể biết cách cân bằng giữa không gian và thời gian, nhưng cũng khó để giao tiếp với đồng nghiệp nếu như bạn không biết những điều trên.

Cải tiến việc cân bằng giữa không gian (bộ nhớ) và thời gian (thời gian chạy CPU) có thể thay đổi nhiều điều một cách ngoạn mục. Nhưng đầu tiên, cần phải xem có cần phải cải tiến không. Vì cải tiến một cái không phải là vấn đề thực sự chẳng làm nên điều khác biệt nào, ngoài việc tạo thêm một khối lượng test. Bộ nhớ máy tính càng ngày càng rẻ, và việc tiêu phí nó không dễ thấy như là thời gian của CPU, cho đến khi chi phí đụng trần, và tai họa xảy đến. Cần cân nhắc khi bạn bán không gian để mua thời gian (tốc độ).

II.1.4. STRESS TEST NHƯ THẾ NÀO

Stress test là thử nghiệm hệ thống với tải. Thực tế, rất nhiều khi hệ thống làm việc tốt với một tải nhất định, và chỉ bắt đầu có vấn đề với một tải trọng nào đó, tức hệ thống đụng trần (hit the wall). Và stress test thực sự là để tìm ra xem cái trần này là ở đâu, và tìm xem có cách nào dỡ trần lên cao hơn không.

Kế hoạch cho việc stress test cần phải được làm ở giai đoạn đầu của dự án, vì như vậy cũng là xác định chúng ta mong đợi đến chừng nào ở sản phẩm: 2 giây cho việc một yêu cầu một trang web có phải là một thất bại hay không hay là một thành công rực rỡ?. Kế đến, stress test cần được thực hiện trong một môi trường đủ gần với môi trường thực.

Khi tiến hành stress test, bắt đầu với tải nhẹ, và nâng dần tải trọng lên theo một số chiều nào đó, cho đến khi bạn đụng trần. Và nếu trần quá thấp thì bạn gặp phải vấn đề về hiệu suất hệ thống, nghĩa là thường thì có một bottleneck ở đâu đó. Sau đó thì bạn tìm cách nâng dần trần lên, nhưng nhớ rằng một hệ thống chịu được tải nặng không có nghĩa là hệ thống đó chạy tốt với tải nhẹ. Sau đó thì làm test trên các chiều khác nữa. Có nhiều kỹ thuật khác nhau, như các hệ thống log thường cho biết nhiều điều về thời gian dùng CPU, nhưng ít khi cho được cái nhìn đúng về tình trạng bộ nhớ. Trong các hệ thống hiện đại, nhiều phần mềm và nhiều máy tính có thể cùng tương tác, khi bạn đụng trần đâu đó thì các hệ thống khác cũng bị ảnh hưởng theo, do đó theo dõi tất cả các máy cũng sẽ rút được nhiều thông tin.

Cuối cùng, biết được trần ở đâu không có nghĩa là phải nâng trần lên, chỉ là để có cái nhìn mang tính dự đoán để giúp cho mặt kinh doanh của sản phẩm.

II.1.5 CÂN BẰNG GIỮA TRỪU TƯỢNG VÀ KHÚC CHIẾT NHƯ THẾ NÀO

Trừu tượng hóa là chìa khóa của lập trình. Nhưng bạn cần cân nhắc mức độ trừu tượng hóa, người mới vào nghề thường trừu tượng vấn đề nhiều hơn cần thiết. Dấu hiệu nhận biết điều này là tạo nhiều lớp không thực sự chứa đoạn mã nào và chỉ để phục vụ cho việc trừu tượng hóa một điều gì đó. Dĩ nhiên điều này là hấp dẫn, nhưng bạn cũng cần đến tính khúc chiết, ngắn gọn trong code.

Đôi khi, chúng ta thấy những lỗi lầm của những người nhiệt thành và lý tưởng: tại giai đoạn sơ khởi của dự án, nhiều lớp được định nghĩa cho thấy viễn cảnh có thể xử lý mọi tình huống có thể xảy ra. Sau đó thì phần thân của các hàm càng ngày càng dài, code càng ngày càng hỗn độn, và nhiều lớp trống không được viết tài liệu vì mọi người đều rất bận. Kết cục đó có thể tránh được nếu để dành công sức cho sự trừu tượng hóa này vào việc giữ mọi thứ ngắn gọn và đơn giản. Tôi đề nghị đọc Succinctness is Power của Paul Graham.

Có một số giáo điều với các kỹ thuật như che giấu thông tin (information hiding) hay lập trình hướng đối tượng (object oriented programming). Những kỹ thuật này giúp lập trình viên code những đoạn mã có tính trừu tượng cao và thích nghi với thay đổi. Nhưng, theo cá nhân tôi, bạn không nên viết quá nhiều code như thế.

II.1.6 HỌC CÁC KỸ NĂNG MỚI NHƯ THẾ NÀO

Học các kỹ năng mới, nhất là các kỹ năng không phải là kỹ thuật là điều thú vị nhất. Phần nhiều các công ty sẽ có chính sách tốt hơn nếu họ hiểu những lập trình viên muốn điều này như thế nào. Đọc sách, dự các khóa học cũng là một cách, nhưng thực sự bạn có thể kính trọng một lập trình viên nếu như anh ta chưa viết một chương trình nào không? Nhưng để học một kỹ năng, bạn phải tự đặt mình vào cái vị thế đáng thương nơi bạn có thể thực tập kỹ năng đó. Một cố vấn kinh nghiệm thường tốt hơn sách vở nhiều, nhưng điều đó cũng không thay thế được việc bạn tự học. Tìm cách bắt sếp cho bạn học các lớp chính thức nhiều hơn, nhưng cũng nên hiểu rằng điều đó cũng chẳng tốt hơn việc bạn từ mày mò là bao nhiêu. Vì thường là đòi có lớp học thì dễ hơn đòi được nghĩ xả hơi, còn lớp học thì nhiều khi là những bài giảng ngái ngủ để đợi đến giờ ăn.

Nếu bạn lãnh đạo người khác, hãy hiểu họ học như thế nào và khuyến khích bằng cách giao những việc đúng tầm và đúng kỹ năng. Nhớ rằng các kỹ năng quan trọng lại không phải là các kỹ năng kỹ thuật và để mọi người có cơ hội giao tiếp, và nâng cao tình bằng hữu và sự mạnh dạn trong công việc.

II.1.7. TẬP CÁCH GÕ BÀN PHÍM

Đây là kỹ năng trung cấp, vì viết code thường khó và thường bạn không đủ thời gian để gõ những gì bạn nghĩ. Và trong công việc, càng ngày bạn càng viết lách nhiều hơn (mà ít phải gõ code hơn). Giai thoại kể lại rằng khi Michael Tiemann ở MCC, người đứng ngoài cửa có thể nghe được tiếng vo ve của các phím bấm, nhanh đến nỗi chẳng phân biệt được các phím với nhau.

II.1.8. INTERGRATION TESTING NHƯ THẾ NÀO

Intergration testing (IntT) là khi bạn tích hợp tất cả các phần khác nhau của hệ thống đã được unit-test. IntT thường tốn kém, và bạn phải tính thời gian làm điều này trong lịch làm việc của bạn. Tốt nhất là làm sao không có giai đoạn IntT này vào cuối mỗi chu kỳ, bạn tích hợp dần dần mọi thứ và kiểm tra dần cho đến lúc hệ thống thành hình.

II.1.9 NGÔN NGỮ GIAO TIẾP

Có một số ngôn ngữ không phải là ngôn ngữ lập trình, nhưng là ngôn ngữ giao tiếp giữa các chương trình, đã được hình thành và dần chuẩn hóa như UML, XML, SQL… Bạn cần phải biết những ngôn ngữ này cũng như biết dùng chúng lúc cần.
UML rất đẹp ở chỗ nó vừa trực quan, lại vừa hình thức. XML là chuẩn để định nghĩa những chuẩn mới. Nó không phải là giải pháp cho vấn đề trao đổi dữ liệu như bạn nghĩ, dù là nó được nói đến như vậy. Nó chỉ là việc tự động hóa cho phần chán nhất của trao đổi dữ liệu: biến đổi toàn bộ cấu trúc của dữ liệu thành tuyến tính để gởi đi và ngược lại. XML có những phương pháp kiểm tra kiểu và kiểm tra tính chính xác, nhưng lần nữa, cũng chỉ là một phần của những cái bạn sẽ cần đến trong thực tế. SQL không thực sự là một ngôn ngữ lập trình, và là ngôn ngữ chung của các cơ sở dữ liệu quan hệ. Có thể bạn không làm việc liên quan đến cơ sở dữ liệu, nhưng cũng nên có hiểu biết cơ bản về cú pháp và ngữ nghĩa của SQL.

II.1.10 CÁC CÔNG CỤ HẠNG NẶNG

Theo đà phát triển, công nghệ phần mềm tiến từ chỗ không thể hiểu nỗi đến nghiên cứu, đến sản phẩm mới, đến các sản phẩm chuẩn hóa, đến các sản phẩm giá rẻ. Do đó các công cụ công nghệ phần mềm nặng ký thường đòi hỏi nhiều đầu tư để hiểu và sử dụng chúng. Các lập trình viên hạng trung cần biết sử dụng chúng khi cần thiết. Theo tôi, một số công cụ nặng ký cần có:

  • Cơ sở dữ liệu quan hệ.
  • Các máy tìm kiếm toàn văn (full-text search engine).
  • Các thư viện toán học.
  • OpenGL.
  • Các bộ phân tích cú pháp XML (XML-parser).
  • Các chương trình bảng tính.

II.1.10 PHÂN TÍCH DỮ LIỆU NHƯ THẾ NÀO

Phân tích dữ liệu nằm ở giai đoạn sớm của dự án, khi bạn phân tích các hoạt động kinh doanh và tìm ra các yêu cầu đối với phần mềm. Định nghĩa hình thức này có thể làm cho bạn, lập trình viên, nghĩ rằng cần phải tập trung vào coding và để công việc đó cho ai đó làm thiết kế. Nếu theo đúng các tiến trình làm phần mềm thì có thể là như vậy. Nhưng lập trình viên kinh nghiệm thường trở thành người thiết kế, và người thiết kế sắc bén thường trở thành người phân tích kinh doanh. Và họ được trao cái quyền thu thập yêu cầu dữ liệu và đặt các yêu cầu đó trên bàn cho bạn làm. Nhưng vì dữ liệu nằm ở trung tâm của hoạt động lập trình, người phân tích kinh doanh phân tích dữ liệu ở cấp cao, kế đến người thiết kế bóp nặn các phân tích đó sao cho khi nó đến bàn của bạn, bạn chỉ việc áp dụng những thuật toán thông minh nhất để giải quyết công viêc. Sự việc không hoàn toàn như vậy, vì dù ở công đoạn nào dữ liệu cũng là điều chính yếu cần quan tâm. Nếu bạn tìm hiểu xem tay phân tích kinh doanh làm gì để lấy yêu cầu từ khách hàng, bạn sẽ thấy họ vẽ những data flow diagram, định vị các nguồn thông tin, cũng như định hình các dòng thông tin lưu chuyển. Có được yêu cầu cần phải tích hợp luồng thông tin nào vào hệ thống, người thiết kế sẽ xây dựng các nguồn thông tin theo các thuật ngữ của cơ sở dữ liệu quan hệ, của các protocol trao đổi thông tin, của các định dạng file….để công việc có thể được giao xuống cho lập trình viên. Tuy nhiên quá trình chưa dừng ở đây, vì bạn, lập trình viên, sau quá trình tinh lọc dữ liệu này, cần phải phân tích dữ liệu để có thể làm điều đó theo cách tốt nhất. Cái dòng bên dưới công việc của bạn là gì nếu không phải là câu của Niklaus Wirth: Algorithms + Data Structures = Programs. Không có thuật toán nào tự đứng một mình, tự nó làm điều gì đó với chính nó. Do không có thuật toán nào chạy trong chân không nên bạn cần biết phân tích dữ liệu ai đó đã đem đến cho bạn để có thể viết code.

Ví dụ: tìm xem từ nào trong từ điển có nhiều hơn 3 anagram có nghĩa (tức là cũng có trong từ điển) (anagram: một cách đảo các chữ cái của từ đó). Nếu bạn làm bằng cách xem xét tất cả hoán vị có thể có thì dường như bạn đã chọn cách làm tệ nhất.

 

II.2   CÁC KỸ NĂNG NHÓM

II.2.1 QUẢN LÝ THỜI GIAN PHÁT TRIỂN NHƯ THẾ NÀO

Để quản lý thời gian phát triển, luôn duy trì một kế hoạch ngắn gọn và cập nhật. Kế hoạch là một tập các ước lượng, các lịch biểu, các cột mốc (milestone) đê đánh dấu tiến độ. Trong kế hoạch đó cần có tất cả những thứ bạn cần làm, các buổi họp, các buổi làm việc với QC, tài liệu, đặt mua thiết bị… Nếu là kế hoạch cho nhóm, thì cả nhóm phải đồng ý với kế hoạch đầu và trong mỗi lúc thực hiện.

Kế hoạch dự án là để giúp ra quyết định, chứ không phải để phô bày cách tổ chức. Kế hoạch phải cập nhật, để cùng với phán đoán của bạn, có thể dịch chuyển các tác vụ từ người này sang người khác. Nếu để lỡ một milestone, phải có hành động ngay, như là báo cho ông chủ biết. Vì ước lượng và lập lịch không bao giờ là hoàn hảo, và có thể tạo ra ảo tưởng bạn có thể bù những ngày đã lỡ trong những ngày còn lại.

II.2.2 QUẢN LÝ RỦI RO CỦA CÁC GÓI PHẦN MỀM DO HÃNG THỨ 3 VIẾT NHƯ THẾ NÀO

Có những rủi ro liên quan đến các phần mềm do một hãng thứ 3 viết:

Đừng đặt hy vọng vào các thứ chưa có, các phần mềm được hứa là sẽ có. Dĩ nhiên là không nên hoàn toàn hoài nghi về lời hứa của một công ty về một sản phẩm nào đó trong một hạn thời gian nào đó, nhưng khôn ngoan hơn là làm lơ như là chưa nghe lời hứa đó. Và đừng đưa nó vào các văn kiện viết.

Ngay cả khi các lời hứa có thể tin được, nó vẫn chứa rủi ro. Nếu bạn dùng phần mềm của một hãng thứ ba, nhớ là hãy đánh giá nó sớm, sớm hơn rất nhiều trước khi tích hợp. Hiểu được mức độ của các phần mềm do hãng thứ ba viết là một kiến trúc rất đặc biệt, và thường chỉ có chuyên gia mới có được. Và bạn tiết kiệm được rất nhiều thời gian nếu có những người như vậy. Tìm cách có một kế hoạch dự phòng trong trường hợp bất khả kháng.

II.2.3 QUẢN LÝ CÁC CỐ VẤN NHƯ THẾ NÀO

Dùng các cố vấn (consultant), nhưng đừng dựa hẳn vào họ. Họ là những người tuyệt vời và xứng đáng được kính trọng. Vì họ tham gia vào nhiều dự án, họ sẽ biết nhiều về các công nghệ đặc biệt, hay ngay cả các kỹ thuật lập trình nhiều hơn bạn. Cách tốt nhất sử dụng họ là nhờ họ như những gia sư: dạy học các bằng ví dụ. Hơn nữa, họ có thể dễ đến và dễ đi hơn. Họ thường được ít hơn nếu công ty làm việc tốt hơn. Một số thật giỏi, một số trung bình, số còn lại thì kém. Nhưng thường thị bạn chọn họ không kỹ như là chọn lập trình viên, nên thường bạn có nhiều người dỡ hơn. Nếu cố vấn đi viết code, thì bạn cần phải cân nhắc hơn, vì bạn không thể kết thúc dự án với một khối code lớn không có ai review.

II.2.4 GIAO TIẾP ĐÚNG MỨC NHƯ THẾ NẦO

Cân nhắc chi phí của các buổi họp. Chi phí của nó bằng thời gian nhân cho số người tham gia. Họp hành thì cần, nhưng ít hơn nghĩa là tốt hơn. Khuyến khích các giao tiếp ít hình thức, vì thường là có nhiều việc được làm hơn trong giờ ăn trưa hơn các giờ khác. Thật xấu hổ là nhiều công ty không nhận ra và hỗ trợ điều này.

II.2.5 TỎ THÁI ĐỘ BẤT ĐỒNG MỘT CÁCH LỊCH SỰ VÀ QUÊN NÓ ĐI NHƯ THẾ NÀO

Bất đồng là cơ hội để có được một quyết định tố, nhưng phải được xử lý không khéo. Nếu bạn cảm thấy mình đã diễn đạt tốt và được mọi người chú ý lắng nghe thì không có gì nhiều để nói. Nhưng nếu bạn không thể bênh vực cho quyết định mà bạn bất đồng, thì hãy cứ nói vậy. Điều này chứng tỏ bạn là người có suy nghĩ độc lập và có trách nhiệm. Trong một số trường hợp, bất đồng có thể đưa đến công việc được xử lý theo cách của các cá nhân, khi người ra quyết định cảm thấy bất an và cảm thấy đây là một thách thức với uy quyền của cá nhân mình, hãy nhớ rằng trong những trường hợp đó, họ phản ứng với phần có nguồn gốc bò sát trong não họ, bạn nên trình bày những lý lẽ của mình ở một nơi riêng. Nhưng cho dù quyết định có được đảo ngược hay không, ban không bao giờ được nói: Tôi đã nói với anh mà!.

II.3.   CÁC KỸ ĐÁNH GIÁ

II.3.1 CÂN BẰNG THỜI GIAN VÀ CHẤT LƯỢNG NHƯ THẾ NÀO

Phát triển phần mềm đã luôn là cân bằng giữa việc làm gì và việc phải hoàn thành nó. Cái chính là bạn sẽ bị đòi hỏi hy sinh chất lượng cho thời gian theo cách làm tổn thương các kỹ sư cũng như các nhân viên kinh doanh. Nếu điều này xảy ra, hãy thông báo cho các thành viên của nhóm cái giá của việc giảm bớt chất lượng, vì dù sao bạn cũng hiểu điều này hơn là ông chủ. Hãy là rõ cái gì mất và cái gì được. Nếu nó ảnh hưởng đến phía QA, hãy làm rõ nó ra, nếu nó để lại nhiều bug về sau, cũng chỉ ra điều đó. Nếu như bạn được yêu cầu gói cái đống kém chất lượng này vào một component nào đó để chuẩn bị làm nó ở các phase sau, hãy giải thích điều đó với nhóm của bạn để họ có chuẩn bị.

NinjaProgrammer ở Slashdot có nói:

Nhớ rằng thiết kế tốt sẽ có tác dụng chống lại code kém. Nếu như các phần trừu tượng, giao diện (interface) tốt có nhiều trong code, thì việc viết lại mớ code đó sẽ ít khó khăn hơn. Nếu như khó viết code khó sửa thì hãy xem xem điều gì sai trong thiết kế.

II.3.2 QUẢN LÝ SỰ PHỤ THUỘC HỆ THỐNG NHƯ THẾ NÀO

Các hệ thống phần mềm hiện đại càng phụ thuộc nhiều vào các component không trực tiếp nằm trong vòng kiểm soát của bạn. Điều này tăng hiệu suất nhờ vào việc tái sử dụng. Tuy vậy các component cũng mang đến vài vấn đề:

  • Sửa lỗi trong các component này thế nào?
  • Component có làm bạn phụ thuộc vào hệ thống hay phần mềm khác không?
  • Bạn làm gì nếu như component không làm việc?

Nên luôn cần phải gói các component này bằng một cách nào đó, cô lập nó và thay thế khi cần thiết. Hơn nữa việc gói này cũng khiến cho porting phần mềm (từ hệ thống này sang hệ thống khác) cũng dễ hơn.

Có được source code của các component làm rủi ro giảm đi khoảng 4 lần. Nếu bạn fix lỗi của các component này, nhớ đưa nó lại cho người sản xuất chúng, để họ tích hợp các fix vào các bản phát hành sau, nếu không bạn sẽ không vui vẻ gì khi phải hỗ trợ một phiên bản không chính thức.

II.3.3. QUYẾT ĐỊNH LÀM SAO NẾU PHẦN MỀM QUÁ TỆ

Dùng các gói phần mềm người khác viết là cách hay nhanh để tạo nên hệ thống, nhưng rủi ro cần phải cân nhắc. Bạn phải cân nhắc xem gói phần mềm đó đã đủ trưởng thành chưa (vì thường thì các gói phần mềm trưởng thành cùng với quá trình sử dụng):

  • Gói đó có thực sự có được không?
  • Bạn đã biết gì về gói đó?
  • Bạn có phải là người dùng đầu tiên?
  • Có lý do mạnh nào để tiếp tục không?
  • Gói đó có được bảo trì không?
  • Nếu những người đang bảo trì “bỏ chạy” thì nó có tiếp tục sống không?
  • Có gói nào khác thay thế được chỉ tốt bằng nửa thế không?
  • Công ty bạn có thực sự muốn nó không ?
  • Nếu nó thực sự tốt, bạn có thể thuê người làm tiếp trên nó không?

Cân nhắc tất cả những tiêu chí này mới thấy giá trị lớn lao của các gói phần mềm mã nguồn mở được phát hành tốt trong vai trò giảm rủi ro cho các doanh nghiệp.

II.3.4 QUYẾT ĐINH MUA HAY LÀM NHƯ THẾ NÀO

Các doanh nghiệp thường luôn phải quyết định: mua hay làm. Những quyết định này thường đáng tiếc ở những điểm sau: nó thường bỏ lơ các gói mã nguồn mở (vì chúng không cần phải mua). Điều quan trọng hơn là một quyết định như vậy thường bỏ qua chi phí tích hợp, mà chi phí này không nhỏ:

  • Những gì bạn cần có giống những thứ đã được thiết kế sẵn đó không?
  • Bạn sẽ cần phần nào của cái bạn mua?
  • Chi phí của việc tích hợp?
  • Chi phí cho đánh giá việc tích hợp?
  • Mua sẽ gia tăng hay giảm bớt chi phí bảo hành về lâu về dài?
  • Nếu phải tự làm, điều đó có đặt bạn vào một vị trí kinh doanh bạn không muốn không?

Bạn phải nghĩ rất kỹ nếu như làm một cái gì đó rất lớn đủ để xây cả một doanh nghiệp khác. Những ý tưởng như vậy thường được đề nghị bởi những người giỏi và lạc quan, những người sẽ cống hiến rất nhiều cho nhóm của bạn. Nếu nó hấp dẫn, bạn cũng có thể thay đổi kế hoạch kinh doanh, nhưng đừng đầu tư lớn hơn cho cả doanh nghiệp của bạn mà không suy nghĩ tỉnh táo.

Sau đó bạn xây dựng hai kế hoạch, một tự làm và một mua và so sánh chi phí. Và những chi phí này phải tính trên thời gian dài.

II.3.5 LÀM SAO ĐỂ PHÁT TRIỂN MỘT CÁCH CHUYÊN NGHIỆP

Tưởng tượng bạn có trách nhiệm vượt quá thẩm quyền của bạn. Đóng cái vai bạn muốn làm. Biết ơn những đóng góp cho công ty cũng như cho cá nhân. Nếu bạn muốn thành leader, hãy tìm cách tập trung sự hưởng ứng. Nếu bạn muốn là manager, hãy có trách nhiệm với lịch biểu. Ngay cả khi đang làm việc với leader hay manager của mình, bạn vẫn có thể làm vậy, vì làm vậy giúp họ rảnh hơn. Lên kế hoạch học các kỹ năng: kỹ thuật cũng như xã hội.

II.3.6 TUYỂN DỤNG NHÂN VIÊN MỚI NHƯ THẾ NÀO

Tuyển dụng luôn không được quan tâm đúng mức. Thuê một người không thích hợp cũng giống như một hôn nhân có vấn đề.

Có nhiều kiểu phỏng vấn khác nhau. Một số có tính “giày vò”, giao cho ứng viên một khối lượng khổng lồ. Điều này cũng giúp cho việc phát hiện các điểm mạnh và yếu của ứng viên khi phải chịu sức ép. Ứng viên sẽ không thành thật với chính mình hơn là với người phỏng vấn, và các khả năng tự lừa dối mình thật đáng ngạc nhiên.

Bạn nên hỏi miệng các ứng viên các vấn đề kỹ thuật trong khoảng 2 giờ. Với thực hành, bạn sẽ biết cách tìm ra họ biết và không biết những gì, và chỉ ra cho họ thấy. Các ứng viên thường tôn trọng điều này. Tôi đã đôi lần nghe các ứng viên nói rằng chất lượng của các kỳ sát hạch là một trong những động lực cho việc chọn công ty làm việc của họ. Những người tốt muốn được thuê vì khả năng, chứ không phải vì nơi họ làm việc sau cùng, hay vì một đặc tính không quan trọng nào khác. Bạn cũng cần đánh giá khả năng học hỏi của ứng viên, và điều này quan trọng hơn chúng ta tưởng.

Phỏng vấn cũng là một quá trình bạn: bạn bán công ty hay dự án cho ứng viên. Tuy nhiên, khi nói chuyện với lập trình viên, cũng đừng cố tô bóng sự thật, nói về những thứ không tốt trước, sau đó về các thứ tốt hơn.

II.3.7. KHI NÀO DÙNG CÁC KỸ THUẬT TIN HỌC TINH VI

Có một phần của khoa học máy tính gồm cả thuật toán, cấu trúc dữ liệu, toán… những lập trình viên biết nhưng ít dùng. Thực tế, những thứ này quá phức tạp và không cần thiết lắm. Ví dụ như không ích lợi gì trong việc cải tiến một thuật toán nếu như phần lớn thời gian là gọi cơ sở dữ liệu một cách không hiệu quả. Phần đáng thương của lập trình là làm cho các hệ thống nói chuyện được với nhau và dùng các cấu trúc dữ liệu đơn giản để xây dựng các giao diện đẹp.
Khi nào thì công nghệ cao là công nghệ thích hợp? Khi nào thì bạn nên cày một cuốn sách để tìm một thuật toán không có gì đặc biệt? Đôi khi làm điều này cũng có ích nhưng cũng với đánh giá cẩn thận.

Ba cân nhắc quan trọng nhất đối với các kỹ thuật khoa học máy tính có tiềm năng là:

  • Nó có được gói cẩn thận để ít gây rủi ro cho các hệ thống khác, và chi phí toàn bộ cho bảo trì có thấp không?
  • Lợi ích có đáng chú ý không?
  • Bạn có thể kiểm tra và đánh giá nó đúng được không?

Nếu như một sửa đổi thuật toán có thể làm hiệu suất toàn hệ thống tăng gấp đôi (hay giảm chi phí phần cứng đi một nữa) thì đúng là tội ác nếu không cân nhắc nó. Chìa khóa khi biện hộ cho sự thay đổi là: rủi ro thật sự ít, công nghệ này đã được nghiên cứu kỹ, chỉ còn rủi ro khi tích hợp.

II.3.8 NÓI CHUYỆN VỚI NHỮNG NHÂN VIÊN KHÔNG KỸ THUẬT NHƯ THẾ NÀO

Kỹ sư, lập trình viên thường được liệt vào một loại người, một loại văn hóa khác với những người khác. Điều này có nghĩa là những người khác thì khác chúng ta. Khi phải trao đổi với những nhân viên không kỹ thuật, hãy luôn nhớ rằng: tìm cách hiểu họ.

Những nhân viên không kỹ thuật cũng thông minh, nhưng không có chung nền tảng kỹ thuật với chúng ta. Chúng ta làm ra sản phẩm, họ bán, đếm, quản lý sản phẩm… họ cũng không giỏi làm việc nhóm như chúng ta (điều này hiển nhiên không có ngoại lệ). Kỹ năng xã hội của họ tệ lắm cũng bằng chúng ta, nhưng công việc của họ không đòi hỏi họ phải thực tập cách hành xử thân mật, cách ăn nói chính xác, cách chia nhỏ sự việc như chúng ta. Những người này thường dễ bằng lòng hơn, cũng như chúng ta, họ có thể nói mà không thực sự hàm ý vậy.

Những người không kỹ thuật vẫn có thể hiểu các vấn đề kỹ thuật, nhưng họ không có cái mà với chúng ta cũng là một điều khó: đánh giá kỹ thuật. Họ vẫn có thể kỹ thuật vận hành như thế nào, nhưng lại không thể hiểu tại sao làm theo cách này lại mất 3 tháng trong khi cách kia lại mất 3 ngày (lập trình viên cũng có những huyền thoại kiểu như vậy thôi), và đây cũng là một cách để tìm tiếng nói chung với họ.

Khi nói chuyện với người trong nhóm, bạn thường dùng một vài kiểu viết tắt có liên quan đến kinh nghiệm làm việc của bạn. Cần phải có chút nỗ lực để không dùng các dạng này với người không hiểu chúng, nhất là khi có thành viên khác của nhóm bạn ở đó. Với nhóm bạn, những điều ngầm định và mục đích cơ bản không cần phải nhắc lại nhiều, phần lớn thời gian dành cho các chi tiết. Với người ngoài nhóm, câu chuyện phải ngược lại. Họ thường không hiểu những gì bạn không bỏ qua, và làm cho hai bên nghĩ rằng mình hiểu nhau, nhưng thực ra sự không thông hiểu lại càng lớn. Bạn sẽ phải nghĩ rằng bạn sẽ không giao tiếp tốt và tìm hiểu tại sao như vậy. Tìm cách bắt họ tóm tắt những gì bạn nói để chắc rằng họ hiểu.

Tôi thích làm việc với những thành viên không kỹ thuật. Bạn thường có được lợi thế vì bạn biết nhiều ví dụ và ngôn ngữ của bạn rõ ràng. Bạn được đào tạo để tìm trật tự trong hỗn loạn, và họ thích điều đó ở chúng ta. Vì chúng ta hiểu biết các lý luận kỹ thuật, chúng ta cũng sẽ dễ hiểu các khoản liên quan đến kinh doanh, và chúng ta thường tìm được giải pháp cho vấn đề. Những nhân viên không kỹ thuật thường đề xuất các giải pháp họ nghĩ là sẽ dễ hơn cho chúng ta, nhưng thực tế, những giải pháp sau cùng thường chỉ được tìm thấy bằng cách tổng hợp các cái nhìn ngoài cuộc với các đánh giá kỹ thuật. Cá nhân tôi thích Extreme Programming vì nó đã đề cập đến sự không hiệu quả này; kết nối các lượng giá với các ý tưởng sẽ dễ dàng tìm được các kết hợp tốt nhất giữa chi phí và lợi ích hơn.

 

 

III    CHO TRÌNH ĐỘ CAO CẤP

III.1.  ĐÁNH GIÁ KỸ THUẬT VÀ CÔNG NGHỆ

III.1.1 BIẾN ĐIỀU KHÔNG THỂ THÀNH ĐIỀU KHÓ

Việc của chúng ta là làm những điều khó và thăm dò những điều không thể. Từ quan điểm của hầu hết lập trình viên, một điều là không thể khi nó không thể có được từ hệ thống hiện tại hay nó không thể đánh giá được một cách chính xác. Nếu theo định nghĩa này thì tất cả những việc nghiên cứu là không thể.

Sự phân biệt không khôi hài như ta nghĩ, vì thực sự đôi khi bạn đã được đòi hỏi phải làm điều không thể (từ quan điểm khoa học hay từ quan điểm công nghệ phần mềm). Thực sự thì đó chỉ là việc giúp tìm ra một giải pháp cho một vấn đề thực sự khó và hoàn tất phần quan trọng của giải pháp đó. Và một giải pháp được gọi đơn thuần chỉ là khó khi nó có thể được lập lịch một cách tự tin và các rủi ro được hiểu rõ.

Một yêu cầu như thế này thì rất khó có thể thỏa mãn: xây dựng một hệ thống tính toán được kiểu tóc và màu tóc hấp dẫn nhất cho một người. Nhưng vấn đề có thể trở thành đơn thuần chỉ là khó nếu nó có thể được phát biểu sinh động hơn: xây dựng một hệ thống tính được các kiểu tóc và màu tóc hấp dẫn cho một người, cho phép họ xem trước và thay đổi, để sau một hồi thay đổi, họ thấy kiểu ban đầu rất đạt và do đó chúng ta có thể kiếm tiền từ đó. Bạn không thể thành công nếu bạn không có các định nghĩa sinh động về chữ thành công.

III.1.2  DÙNG CÁC NGÔN NGỮ NHÚNG NHƯ THẾ NÀO

Nhúng một ngôn ngữ vào hệ thống là công việc gợi tình và sáng tạo nhất bạn có thể làm. Nó làm cho hệ thống trở nên rất mạnh. Ví dụ như các text-editor tốt nhất đều có các ngôn ngữ nhúng. Nó có thể được sử dụng để người dùng có thể sử dụng sản phẩm với nhiều tính năng hơn. Dĩ nhiên là chức năng này cần phải được xem là tùy chọn, để người đã quen dùng và không ai khác phải dùng đến nó. Tôi và nhiều lập trình viên khác đã rơi vào cái bẫy này nhiều lần. Đã có nhiều ngôn ngữ nhúng và bạn cần cân nhắc kỹ khi tạo ra một cái mới.

Câu hỏi thực sự cần cân nhắc là: điều này ủng hộ hay chống lại văn hóa của người sử dụng? Nếu người dùng hoàn toàn không phải là lập trình viên, liệu điều đó sẽ có ích gì không? Nếu người dùng là lập trình viên, tốt hơn chăng nếu bạn xài một tập các hàm API? Lập trình viên thường không muốn học các ngôn ngữ ít người dùng, nhưng nếu ngôn ngữ đó “khớp” vào trong môi trường của họ thì họ chẳng phải tốn nhiều thời gian để học nó.

III.1.3. CHỌN NGÔN NGỮ

Một lập trình viên đơn độc thích chọn ngôn ngữ phù hợp nhất cho công việc. Số còn lại không có ý thức nhiều về ngôn ngữ họ sẽ dùng. Thường thì việc quyết định điều này sẽ do các ông chủ chẳng mấy am hiểu kỹ thuật, và không đủ can đảm ủng hộ các công cụ không quy ước, mặc dù họ biết rằng các công cụ ít được chấp nhận nhất thường là những thứ tốt nhất. Dĩ nhiên sẽ là một lợi điểm lớn nếu như một nhóm có lựa chọn của riêng mình, bỏ ngoài tai tiếng nói của một cá nhân, vì ông chủ thường muốn thuê các lập trình viên dễ kiếm, và do đó phải là một ngôn ngữ phổ biến.

Nhưng điều gì cũng có nhiều mặt, ngay khi ngôn ngữ chính được chọn, các công cụ và chương trình khác vẫn nên được viết bằng một ngôn ngữ khác. Và nếu ngôn ngữ đó sẽ được nhúng, sự quyết định sẽ phụ thuộc vào văn hóa của cộng đồng lập trình. Việc học ngôn ngữ mới đối với người mới khởi đầu thường là đáng sợ, nhưng với người đã có kinh nghiệm, nó cũng như việc làm quen một thư viện mới. Thường thì người ta nghĩ một hệ thống lớn viết bằng 3, 4 ngôn ngữ thật là hỗn độn, nhưng theo ý tôi, thường thì các hệ thống đó mạnh hơn các hệ thống đơn ngữ.

III.2.  THỎA HIỆP MỘT CÁCH KHÔN NGOAN

III.2.1 CHỐNG LẠI ÁP LỰC CÔNG VIỆC NHƯ THẾ NÀO

Áp lực công việc nếu hiểu theo nghĩa bình thường thì đó là một dấu hiệu tốt, nó thể hiện khả năng và sức khỏe của hệ thống của bạn. Nhưng một khi áp lực đó được lập lịch thì điều đó có nghĩa là bạn buộc phải giao hàng sớm hơn bạn có thể, và điều đó thường không tốt, nhưng lại phổ biến. Áp lực được lập lịch thường có vài lý do: những lập trình viên không cảm thấy yêu thích công việc của mình, cũng có thể là từ khách hàng, họ nghĩ đòi hỏi sản phẩm sớm hơn sẽ khiến chúng ta làm việc chăm hơn. Điều này có thể là đúng, nhưng hiệu quả thực sự lại nhỏ, và thiệt hại lại lớn. Khách hàng thường không biết nội bộ của công việc như thế nào, do đó họ càng đặt thêm nhiều áp lực lên chúng ta. Điểm chính để chống lại áp lực được lập lịch là hiểu nó như một áp lực kinh doanh thông thường, giám sát quan hệ giữa các nguồn lực ta có và sản phẩm, Ước tính chi tiết, hào hiệp về tất cả nhân lực chúng ta có. Và điều này cho phép có những quyết định quản lý tốt về các khả năng cân bằng, co giãn.

Điều then chốt bên trong việc ước lượng này là: sức lao động là thứ chất lỏng hầu như không nén được. Hiểu theo cách khác, một lập trình viên sẽ không nói Không nhưng có thể nói: Khi nào ông sẽ từ bỏ thứ ông muốn?. Đánh giá rõ ràng, chính xác cũng là cách để được các lập trình viên kính trọng, và đây cũng là cách những người chuyên nghiệp hành xử. Thiết lập một lịch trình không tưởng rõ ràng sẽ gây đau đớn cho mọi người. Extreme Programming đã nói rõ về điều này, và tôi nghĩ ai cũng có thể dùng nó.

III.2.2 HIỂU NGƯỜI DÙNG NHƯ THẾ NÀO

Trách nhiệm của bạn là hiểu những người dùng, và giúp ông chủ của bạn cũng hiểu như vậy. Vì người dùng không liên quan mật thiết đến quá trình sản xuất, họ sẽ cư xử khác so với bạn:

  • Người dùng thường tuyên bố ngắn gọn
  • Người dùng có công việc riêng, họ thường nghĩ về các cải tiến nhỏ trong sản phẩm, chứ không phải các cải tiến lớn.
  • Người dùng thường không có được cái nhìn về chính cộng đồng người dùng của họ.

Nhiệm vụ của bạn là đem lại thứ họ muốn, chứ không phải là thứ họ nói họ muốn. Tốt hơn, hãy đề nghị và kiểm chứng họ đồng ý về đề nghị của bạn trước khi bắt đầu. Bạn phải coi chừng tính kiêu ngạo cũng như tính khiêm tốn giả tạo khi muốn biết khách hàng cần gì. Lập trình viên được đào tạo để thiết kế và code. Nghiên cứu viên thị trường được đào tạo đế biết người khác muốn gì. Hai kiểu người này, hay hai trạng thái này trong cùng một con người phải làm việc hòa hợp với nhau để tạo ra được viễn cảnh tốt nhất. Và bạn hãy kiểm tra các suy nghĩ, ý kiến của bạn càng nhiều càng tốt.

III.2.3 LÀM SAO ĐỂ THĂNG TIẾN

Muốn thăng tiến đến một vị trí, hãy hành xử như là bạn đang ở trong vị trí đó. Muốn thăng tiến đến một chức danh, tìm hiểu xem người khác chờ đợi điều gì từ chức danh đó và làm chúng. Để được tăng lương, hãy thương lượng với đầy đủ thông tin. Nếu bạn cảm thấy bạn bị bỏ qua quyền được thăng tiến, hãy nói chuyện với ông chủ về điều đó, hỏi rõ ràng bạn cần phải làm gì để được như vậy và hãy làm chúng. Nghe có vẻ nhàm chán, nhưng thường thì những điều bạn thấy cần phải làm lại khác với ý kiến của ông chủ bạn. Và điều này cũng giúp chốt ông chủ của bạn lại ở một vài điểm. Hầu hết các lập trình viên đều có cái nhìn phóng đại về khả năng của mình. Dù sao, không phải ai cũng ở trong top-ten. Nhưng tôi đã thấy nhiều người không được đánh giá đúng mức, nhưng thường thì mọi người xung quanh tương đối vừa phải, bạn không thể được đánh giá đúng nếu như không làm cho ai thấy rõ ràng điều đó trong công việc. Đôi khi do nguyên nhân thói quen cá nhân, một số người sẽ không được để ý đến nhiều…

III.3.  PHỤC VỤ NHÓM CỦA BẠN

III.3.1 PHÁT TRIỂN TÀI NĂNG NHƯ THẾ NÀO

Nietschze đã cường điệu khi nói: Cái gì không huỷ diệt tôi sẽ làm tôi mạnh hơn. Trách nhiệm lớn nhất của bạn là với nhóm của bạn. Bạn phải hiểu rõ mọi người. Và tìm cách mở rộng công việc hơn là làm họ quá tải với chúng. Nói chuyện với mọi người về sức ép công việc, và cách nó đang ép họ. Nếu lập trình viên cảm thấy mình chịu được một dạng sức ép, họ sẽ cảm thấy có động lực từ đó. Bạn cũng nên tìm hiểu về động cơ làm việc của những người khác, cái gì làm cho họ thấy công việc thú vị. Nhiều khi bạn cũng không thể thỏa mãn được họ, nhưng ít ra bạn cũng biết được họ mong muốn điều gì.

Bạn cũng nên cho phép người khác (và cả chính bạn) thất bại đôi lần, và chuẩn bị có một số thất bại trong kế hoạch. Nếu không có thất bại nào, bạn sẽ không có được cảm giác phiêu lưu, hay là bạn đang không cố gắng đúng mức. Nếu ai đó cố tình không làm việc ở mức đúng với họ, hãy kiên nhẫn tìm cách làm cho họ hoạt bát hơn. Nhưng khi kiên nhẫn cạn hết thì hãy cứ sa thải. Bạn không thể tiếp tục giữ anh ta vì như vậy không công bằng với các thành viên khác.

Với những thành viên giỏi, hãy công khai tán dương họ trước mọi người, và giữ những lời phê bình ở chỗ riêng tư. Người giỏi thường làm những việc khó hơn, và điều này là tự nhiên, chẳng ai để ý gì đến điều đó nếu ai cũng làm việc chăm chỉ. Một thực tế ít khi nhìn thấy là 1 lập trình viên giỏi thường tốt hơn cả 10 lập trình viên kém. Nên có tình huống là, bạn sẽ đi nhanh hơn nếu bỏ những người yếu hơn ở lại phía sau. Nhưng thường thì như vậy chỉ mang lại các lợi ích ngắn hạn, về lâu về dài, cộng đồng cần những dạng ích lợi khác: sự đào tạo những người kém hơn, sự phổ biến tri thức trong mọi người, và khả năng đứng vững khi những người giỏi ra đi.

III.3.2. CHỌN NHỮNG THỨ ĐỂ LÀM NHƯ THẾ NÀO

Bạn cân bằng nhu cầu cá nhân với nhu cầu của nhóm khi chọn các phương diện của dự án để tham gia. Bạn nên làm những gì bạn giỏi nhất, nhưng cũng nên học các kỹ năng mới. Kỹ năng lãnh đạo và giao tiếp quan trọng hơn kỹ năng kỹ thuật. Nếu bạn rất giỏi, hãy nhận phần khó và rủi ro nhất của công việc, và làm nó sớm nhất có thể.

3.3   LÀM SAO ĐỂ CÓ ĐƯỢC NHIỀU NHẤT TỪ NHÓM CỦA BẠN

Xây dựng tinh thần đồng đội và giữ cho mọi người có liên quan với nhau. Để xây dựng tinh thần đồng đội, những thứ như áp quần, logo, đồng phục cũng hay, nhưng không bằng những kính trọng cá nhân. Tinh thần này có được khi mọi người quyết định hy sinh vì tập thể và nghĩ rằng những hy sinh đó cũng là vì lợi ích của họ. Là leader, bạn không thể đòi hỏi điều này nhiều hơn bạn có thể cung cấp chúng. Chìa khóa của việc lãnh đạo là tạo sự đồng tâm nhất trí giữa mọi người.

III.3.4 LÀM SAO ĐỂ MỖ XẺ VẤN ĐỀ

Nhiều giám đốc nghĩ rằng lên kế hoạch và không cần để ý đến những người sẽ làm chúng. Điều này là không thể vì khả năng và năng suất của mọi người khác nhau.

Cũng như một nhạc trưởng cần cân nhắc các loại gỗ làm ra các nhạc cụ trong giàn nhạc, leader thường không thể tách rời các thành viên ra khỏi các công việc đã được chia. Đây cũng là lý do không nên phá vỡ các nhóm đang có hiệu suất cao.

Cũng có một nguy cơ tiềm tàng là mọi người sẽ chán những việc họ thường làm mà không được học các kỹ năng khác và cải thiện các điểm yếu của họ. Dù sao, chuyên môn hóa vẫn tốt nếu không bị lạm dụng.

III.3.5. XỬ LÝ CÁC CÔNG VIỆC NHÀM CHÁN THẾ NÀO

Nhiều khi không thể tránh được các công việc nhàm chán, vì nó quan trọng với sự thành công của dự án. Những công việc này có thể làm tổn thương những người làm chúng. Hãy tìm cách bắt máy tính làm giùm, hay giúp các thành viên khác làm nó. Làm một chương trình làm những công việc nhàm chán trong một tuần hay tự làm việc đó cũng trong một tuần, dĩ nhiên cách làm tự động hóa sẽ tốt hơn. Nếu không thể khác được thì cũng phải làm thôi, nhưng đừng để những người phải làm việc đó một mình, ít nhất hãy giao việc đó cho một nhóm hai người.

III.3.6 TÌM TÀI TRỢ CHO DỰ ÁN NHƯ THẾ NÀO

Tạo ra một viễn cảnh và minh họa giá trị của viễn cảnh đó với cả tổ chức. Cho phép người khác có phần trong viễn cảnh đó. Tìm ra các nhà tài trợ chính riêng rẽ, làm một mô hình để minh họa các ý tưởng. Mô hình, hình mẫu luôn tốt hơn, nhất là trong ngành phần mềm.

III.3.7 PHÁT TRIỂN MỘT HỆ THỐNG NHƯ THẾ NÀO

Hạt giống chứa những ý tưởng từ những người đã trưởng thành nhưng chưa được thực hiện. Hạt giống phát triển thành phôi, và lớn lên. Và cuối cùng thì đơm hoa kết trái. Về sau thì cây chết và xác nó dùng để nuôi những sinh vật khác. Phần mềm cũng vậy. Một cây cầu thì không thể như vậy, chúng ta có một chiếc cầu chưa hoàn tất, chứ không có một chiếc cầu “trẻ em”, vì cầu đơn giản hơn phần mềm nhiều.

Bạn nên nghĩ về phần mềm như một sinh vật phát triển, nó cho phép chúng ta có những bước tiến dài trước khi thấy được hình ảnh sau cùng. Phải có được phản hồi từ phía người dùng về phần mềm. Phát triển và tỉa bớt các cành yếu. Lập trình viên là những người phát triển một sản phẩm hoàn chỉnh, nhưng lập trình viên giỏi phải phát triển được con đường phát triển cho đến hệ thống sau cùng.

Những cách tiếp cận thường có dạng xoắn ốc, và nhớ đặt những milestone trên đó. Và trên đường phát triển, không chỉ phát triển hệ thống mà phát triển nhóm và con người.

Rob Hafernik đã gửi cho tôi những ghi chú này, và tôi không thể làm tốt hơn là trích dẫn lại ở đây:

Đó không phải chỉ là hệ thống, mà là thuật toán, giao diện người dùng, mô hình dữ liệu, vân vân… Điều sống còn là bạn làm việc trên toàn hệ thống để biết được nó đạt những mục tiêu trung gian. Không gì tệ hơn việc xây dựng tất cả mọi thứ để cuối cùng biết rằng nó không làm việc (như thất bại gần đây ở Voter News System). Vì điều đó là do một quy luật tự nhiên: không hệ thống phức tạp nào được xây từ đầu, nó chỉ có thể tiến hóa từ hệ thống đơn giản lên hệ thống phức tạp qua những bước có chủ ý.

III.3.8 GIAO TIẾP TỐT NHƯ THẾ NÀO

Giao tiếp tốt rất khó, nó là một kỹ năng thuộc về chính nó. Càng khó hơn, vì người mà bạn giao tiếp ai cũng có thiếu sót. Thường họ không cố hiểu bạn, họ diễn đạt nghèo nàn. Họ thường làm việc quá nhiều, hay quá chán công việc, và thường chú trọng vào việc của họ hơn những điều bạn đề cập. Bạn càng viết, nghe, nói giỏi, bạn càng dễ tìm hiểu xem vấn đề nằm ở đâu và làm sao để giải quyết chúng.

Lập trình viên là một sinh vật có xã hội và sống phụ thuộc vào giao tiếp với cộng nhóm mình. Lập trình viên giỏi là những sinh vật xã hội chỉ bằng lòng với việc giao tiếp nhiều hơn ra ngoài nhóm của mình. Và ông chủ (nếu không phải là lập trình viên) cần lập trình viên vì họ là một phần của chiếc cầu nối giữa các ý tưởng và thực thể trong quần thể.

Tôi không hẳn đã giao tiếp tốt, nhưng tôi thường làm các cách sau: chuẩn bị các ý tưởng, nói cho người khác nghe, giao cho họ một văn bản viết, cho họ xem demo, và lặp đi lặp lại như vậy. Và không nên thất vọng khi các ý tưởng của bạn chưa được chấp nhận.

III.3.9 NÓI VỚI NGƯỜI KHÁC NHỮNG ĐIỀU HỌ KHÔNG MUỐN NGHE THẾ NÀO

Nhiều khi bạn phải nói với một người những điều sẽ làm họ khó chịu. Nhớ rằng bạn làm vậy có lý do, ngay cả khi không thể làm được gì khác thì hãy cố nói với họ sớm. Cách thông báo tốt nhất là kèm theo luôn một giải pháp. Cách thứ nhì là nhờ họ giúp với chính vấn đề đó. Và có nguy cơ là người ta sẽ không tin bạn, và bạn cần hậu thuẫn cho sự quyết đoán của mình.

Một trong những điều khó chịu nhất bạn thường nói là: kế hoạch phải trễ một thời gian. Ai có lương tâm cũng ghét những câu này, vậy nên hãy nói nó sớm. Không gì tệ hơn tiếp tục trì hoãn khi đã trễ. Bạn cũng có thể tìm cách nói điều đó với sự hậu thuẫn của một nhóm.

III.3.10 LÀM VIỆC VỚI CÁC “CHUYỆN HOANG ĐƯỜNG” CỦA VIỆC QUẢN LÝ

“Chuyện hoang đường” hàm nghĩa không có thật, nhưng nó có những ý nghĩa sâu xa hơn. Nó có nghĩa như là những câu chuyện của lòng tin, những câu chuyện giải thích quan hệ giữa con người và vũ trụ. Những giám đốc thường quên họ đã học những gì khi còn là lập trình viên, và tin vào những chuyện hoang đường ấy dễ dàng. Bạn cần phải nhận ra những điều đó:

  • Nhiều tài liệu hơn là tốt hơn (họ muốn có tài liệu, nhưng họ không muốn bạn mất thời gian để làm chúng).
  • Có thể coi mọi lập trình viên như nhau (thật sự các lập trình viên rất khác nhau).
  • Có thể thêm tài nguyên vào một dự án trễ để tăng tốc (chi phí giao tiếp với những người mới nhiều khi nhiều hơn là những người đó có thể giúp).
  • Có thể ước lượng chi phí phát triển phần mềm chính xác (điều này ngay cả về mặt lý thuyết cũng không làm được).
  • Có thể ước lượng hiệu suất của lập trình viên bằng một số lượng giá đơn giản, như số dòng code (nếu như ngắn gọn là sức mạnh, thì có lẽ càng ít code càng tốt).

Nếu có cơ hội, hãy tìm cách giải thích những điều này, nhưng đừng thất vọng nếu không thành công, và đừng chiến đấu một cách ngoan cố. Những huyền thoại này chỉ cũng cố ý kiến của các giám đốc là mình phải cố kiểm soát mọi việc. Sự thật là người ta đã ủng hộ nếu nó tốt và chống lại nếu nó xấu.

III.3.11 ĐƯƠNG ĐẦU VỚI TÌNH TRẠNG HỖN LOẠN TỔ CHỨC NHƯ THẾ NÀO

Có những lúc công ty sẽ có vấn đề: ngừng sản xuất, công ty bị mua lại… Những điều này không làm ai yên tâm, nhưng có lẽ ít tác động đến lập trình viên hơn, vì tính cách lập trình viên thiên về khả năng hơn là vị trí. Nếu bạn không phải là lập trình viên, xin dừng ở đây.

Các kỹ sư có năng lực sáng tạo, và chống đỡ. Những người không phải là kỹ thuật có thể ra lệnh cho người khác xung quanh, nhưng họ chẳng làm gì được nếu không có các kỹ sư. Và đây là nền móng để tạm thời chống đỡ các tình trạng hỗn loạn trong tổ chức. Nếu bạn lâm vào tình trạng đó, tốt nhất làm lơ và tiếp tục công việc như chẳng có gì xảy ra. Rất thường thấy một kẻ xả stress nào đó không có năng lực sẽ tìm cách bảo bạn làm những điều ngu ngốc, tốt nhất là hãy cười và chẳng làm gì hết cho đến khi hắn đi khỏi, và tiếp tục làm những gì bạn nghĩ là tốt nhất lúc đó. Đây là điều tốt nhất có thể làm cho bạn, và cho cả dự án và công ty.