NOTICE

 任何跟文章無關的閒聊,請愛用 留言板(Guestbook)

 想要快速瀏覽主題,請點選單 目錄 標籤。

 停止更新ing,請見諒。 <(_ _)>


10月 26, 2008

【解題】Clock Hands

@
ACM Volume V 579 - Clock Hands


The Problem

The medieval interest in mechanical contrivances is well illustrated by the development of the mechanical clock, the oldest of which is driven by weights and controlled by a verge, an oscillating arm engaging with a gear wheel. It dates back to 1386.

Clocks driven by springs had appeared by the mid-15th century, making it possible to con- struct more compact mechanisms and preparing the way for the portable clock.

English spring-driven pendulum clocks were first commonly kept on a small wall bracket and later on a shelf. Many bracket clocks contained a drawer to hold the winding key. The earliest bracket clocks, made for a period after 1660, were of architectural design, with pillars at the sides and a pediment on top.

In 17th- and 18th-century France, the table clock became an object of monumental design, the best examples of which are minor works of sculpture.

The longcase clocks (also called grandfather clocks) are tall pendulum clock enclosed in a wooden case that stands upon the floor and is typically from 6 to 7.5 feet (1.8 to 2.3 m) in height. Later, the name ``grandfather clock'' became popular after the popular song "My Grandfather's Clock," written in 1876 by Henry Clay Work.


One of the first atomic clocks was an ammonia-controlled clock. It was built in 1949 at the National Bureau of Standards, Washington, D.C.; in this clock the frequency did not vary by more than one part in 108.

Nuclear clocks are built using two clocks. The aggregate of atoms that emit the gamma radiation of precise frequency may be called the emitter clock; the group of atoms that absorb this radiation is the absorber clock. One pair of these nuclear clocks can detect energy changes of one part in 1014 , being about 1,000 times more sensitive than the best atomic clock.

The cesium clock is the most accurate type of clock yet developed. This device makes use of transitions between the spin states of the cesium nucleus and produces a frequency which is so regular that it has been adopted for establishing the time standard.


The history of clocks is fascinating, but unrelated to this problem. In this problem, you are asked to find the angle between the minute hand and the hour hand on a regular analog clock. Assume that the second hand, if there were one, would be pointing straight up at the 12. Give all angles as the smallest positive angles. For example 9:00 is 90 degrees; not -90 or 270 degrees.


Input

The input is a list of times in the form H:M, each on their own line, with 1 ≦ H ≦ 12 and 00 ≦ M ≦ 59. The input is terminated with the time 0:00. Note that H may be represented with 1 or 2 digits (for 1-9 or 10-12, respectively); M is always represented with 2 digits (The input times are what you typically see on a digital clock).


Output

The output displays the smallest positive angle in degrees between the hands for each time. The answer should between 0 degrees and 180 degrees for all input times. Display each angle on a line by itself in the same order as the input. The output should be rounded to the nearest 1/1000, i.e., three places after the decimal point should be printed.


Sample Input

12:00
9:00
8:10
0:00


Sample Output

0.000
90.000
175.000


解題思考

  這一題在判斷某時分針與時針角度的差。

  首先是資料輸入方面,我嫌處理麻煩,就直接使用 scanf("%d:%d", &h, &m) 的方式抓取 hour 跟 minute 了。

  接著在處理角度差的時候,我們需要將 hour 乘以 30、minute 乘以 6 來換算成角度。需要注意的是,當分針不是指向 00 的時候,還需要將時針加上些微的移動。

  因為每個小時的角度差為 30 度,所以我們將 30 除以 60(每小時 60 分),便可以得到:準點過後,每過一分鐘時針的移動為 0.5 度。整理一下,便可以得到角度差為 h * 30 + m * 0.5 - m * 6 = h * 30 - m * 5.5。

  接著再將角度值做個調整,以符合題目要求的「非負數的最小角度」,就可以了。


參考解答(C++)

#include <iostream>
#include <iomanip>

using namespace std;

int main(void)
{
    // 設定顯示至小數點第三位
    cout << setiosflags(ios::fixed) << setprecision(3);

    while (1)
    {
        int h, m;
        scanf("%d:%d", &h, &m);

        if (!h && !m) { break; }

        // 分針每前進 1 度, 時針就前進 0.5 度
        double angle = (double)h * 30 - (double)m * 5.5;
        if (angle < 0)      { angle *= -1; }
        if (angle > 180)    { angle = 360 - angle; }

        cout << angle << endl;
    }

#ifndef ONLINE_JUDGE
    system("pause");
#endif
}

10月 25, 2008

【解題】Above Average

@
ACM Volume CIII 10370 - Above Average


The Problem

It is said that 90% of frosh expect to be above average in their class. You are to provide a reality check.


Input

The first line of standard input contains an integer C, the number of test cases. C data sets follow. Each data set begins with an integer, N, the number of people in the class (1 <= N <= 1000). N integers follow, separated by spaces or newlines, each giving the final grade (an integer between 0 and 100) of a student in the class.


Output

For each case you are to output a line giving the percentage of students whose grade is above average, rounded to 3 decimal places.


Sample Input

5
5 50 50 70 80 100
7 100 95 90 80 70 60 50
3 70 90 80
3 70 90 81
9 100 99 98 97 96 95 94 93 91


Sample Output

40.000%
57.143%
33.333%
66.667%
55.556%


解題思考

  這一題只是給與一定數量的「分數」,要求你計算出比全體平均分數高的百分率而已。

  首先,我們在輸入的分數的同時,計算出總分之後,就是要計算比平均高的人數。

  為求精準,我是將每個人的分數乘以人數再與總分比較,而不是先由總分求出平均分數再跟每個人的分數比較。

  最後,根據人數求出百分率。完成!


參考解答(C++)

#include <iostream>
#include <iomanip>

using namespace std;

int main(void)
{
    int c;
    cin >> c;

    // 設定顯示至小數點第三位
    cout << setiosflags(ios::fixed) << setprecision(3);

    for (int i = 0; i < c; i++)
    {
        int n, *score, total = 0;
        cin >> n;

        // 輸入分數, 並計算總和
        score = new int[n];
        for (int j = 0; j < n; j++)
        {
            cin >> score[j];

            total += score[j];
        }

        // 得到有多少人比平均高分
        int man = 0;
        for (int j = 0; j < n; j++)
        {
            if (score[j] * n > total)
            {
                man++;
            }
        }

        cout << (((double)man * 100) / n) << "%" << endl;

        delete [] score;
    }

#ifndef ONLINE_JUDGE
    system("pause");
#endif
}

【解題】All in All

@
ACM Volume CIII 10340 - All in All


The Problem

You have devised a new encryption technique which encodes a message by inserting between its characters randomly generated strings in a clever way. Because of pending patent issues we will not discuss in detail how the strings are generated and inserted into the original message. To validate your method, however, it is necessary to write a program that checks if the message is really encoded in the final string.

Given two strings s and t, you have to decide whether s is a subsequence of t, i.e. if you can remove characters from t such that the concatenation of the remaining characters is s.


The Input

The input contains several testcases. Each is specified by two strings s, t of alphanumeric ASCII characters separated by whitespace. Input is terminated by EOF.


The Output

For each test case output, if s is a subsequence of t.


Sample Input

sequence subsequence
person compression
VERDI vivaVittorioEmanueleReDiItalia
caseDoesMatter CaseDoesMatter


Sample Output

Yes
No
Yes
No


解題思考

  這一題主要是給兩個字串 s 跟 t,問你 t 有沒有可能在移去某些字元後,能夠得到 s。

  既然如此,我們可以直接利用 string::find() 函式,依序從 t 中去找 s 的每一個字元。假如都找得到,就輸出 "Yes",否則輸出 "No"。這樣就完成了。


參考解答(C++)

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
    string s, t;
    while (cin >> s >> t)
    {
        int pos = -1;
        bool ok = true;
        for (int i = 0; i < s.size(); i++)
        {
            // 搜尋 s 的元素是否依序存在 t 中
            if ((pos = t.find(s[i], pos + 1)) == string::npos)
            {
                ok = false;
                break;
            }
        }

        cout << (ok ? "Yes" : "No") << endl;
    }

#ifndef ONLINE_JUDGE
    system("pause");
#endif
}

9月 16, 2008

【筆記】Using Qt Designer

@
  既然 Qt (大概)多少會用了,這次我要來試試其附帶的所見即所得編輯器,也就是 Qt Designer。說實在這個我還不是很會用,所以這裡只做個很簡單的測試:如何將 Qt Designer 製作出來的檔案(.ui 檔)與實際編寫的 C++ 程式結合的方式。




  首先,打開 Qt Designer 會出現這樣一個畫面:選擇一個樣版或是元件作為「頂層」的視窗。看過網路上的範例,滿多人都是選擇 "Widget",所以這裡我也先照著做了。




  因為目前都還不會寫到元件功能,所以就隨便亂做畫面了。哈哈,偽月曆一份!




  完成之後,按下存檔,存在我預先建立的 Qt Designer 的資料夾裡。


  接著就是程式的部份了:

#include <QApplication>
#include "ui_design.h"

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);
    QWidget *widget = new QWidget;

    Ui::Form ui;
    ui.setupUi(widget);

    widget->show();

    return app.exec();
}

  首先,比較要注意的是第二行,需要引括由 .ui 檔建立的標頭檔。

  不過其實,現在這個標頭檔還是不存在的。這個檔案會在編譯時,由 qmake 根據 Qt Designer 所建立的 .ui 檔產生。其中就包含了剛剛我所建立元件擺設。

  另外呢,還有中間 "Ui::Form ui" 的那兩行,是利用 Ui_Form::setupUi() 函式將我自行建立的 widget 作為包含了我剛剛建立的元件以及擺放位置的類別實體。有了實體之後,我們就可以簡單的利用 QWidget::show() 函式來顯示它了。


  接著,使用以下命令編譯程式:

qmake -project
qmake
make

  執行之後的結果:




  總之,好像又是個滿無聊的小測試。所以之後,再來試看看怎麼寫各個元件的處理程式吧。

9月 14, 2008

【筆記】Creating a Event Label

@
  接續前一篇筆記的內容。目前的程式有點普通,所以乾脆順便來寫一個(鍵盤或滑鼠)事件處理器。


  因為需要一個能夠接受事件的標籤元件,所以我定義了一個繼承自 QLabel 的物件:

class QEventLabel : public QLabel
{
    public:
        explicit QEventLabel(QWidget *parent = 0, Qt::WindowFlags f = 0);
        explicit QEventLabel(const QString &text, QWidget *parent = 0,
                                Qt::WindowFlags f = 0);
        ~QEventLabel();

    protected:
        void mouseMoveEvent(QMouseEvent *event);
        void mousePressEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
        void keyPressEvent(QKeyEvent *event);
};


QEventLabel::QEventLabel(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f)
{
}

QEventLabel::QEventLabel(const QString &text, QWidget *parent,
                            Qt::WindowFlags f) : QLabel(text, parent, f)
{
}

QEventLabel::~QEventLabel()
{
}

  建構子與解構子基本上都不需要做更動。


void QEventLabel::mouseMoveEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>%d, %d</center>", event->x(), event->y());
    this->setText(msg);
}

void QEventLabel::mousePressEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>Press</center>");
    this->setText(msg);
}

void QEventLabel::mouseReleaseEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>Release</center>");
    this->setText(msg);
}

  在這裡的滑鼠是利用 QString 物件搭配 QString::sprintf() 函式來建立字串,以顯示標籤接收到的事件。

  當滑鼠移動,標籤會顯示滑鼠的座標;當滑鼠按鍵被按下,標籤會顯示"Press";當滑鼠按鍵被釋放,標籤會顯示"Release"。

  其中,滑鼠的座標可以由 QMouseEvent::x() 與 QMouseEvent::y() 取得。


void QEventLabel::keyPressEvent(QKeyEvent *event)
{
    QString msg;

    if (event->key() == '<')
    {
        msg = "<center>Type: &lt;</center>";
    }
    else if (event->key() >= Qt::Key_Space && event->key() <= Qt::Key_AsciiTilde)
    {
        msg = "<center>Type: " + event->text() + "</center>";
    }
    else
    {
        msg.sprintf("<center>Type: <font color=red>%d</font></center>", event->key());
    }

    this->setText(msg);
}

  這裡的鍵盤處理器也與滑鼠處理器相同,利用了 QString 物件與 QString::sprintf() 函式來顯示接收到的事件。

  當鍵盤被按下時,若是可以直接印出的字元('D'、' '、'!'、'3'等符號),我利用了 QKeyEvent::text() 取得鍵盤代號所對應的符號,並將之顯示在標籤上;而若是不能印出的功能鍵(Enter、Shift、Home 等),我則利用 QKeyEvent::key() 直接在標籤上顯示鍵盤代號。

  要特別注意的是,若鍵盤代號對應的是上角括號'<',直接利用 QKeyEvent::text() 會被判定為 html 標籤而不顯示。為了避免這種情況,我就將之改成直接輸出"&lt;",也就是'<'的字元實體(character entity)

  然後,別忘了在之前建立 QLabel 實體的地方做一點更動:
    QEventLabel *label = new QEventLabel("<center>No Event</center>", window);

  簡單來說,就是把 QLabel 改成 QEventLabel,並將標籤文字改成"No Event"就可以了。


  這樣應該完成了吧?試著先編譯執行看看。

  當滑鼠在標籤上移動,標籤成功的顯示滑鼠所在的座標。試著按看看滑鼠左右鍵,這個功能也正常運作了,看來一切完美。最後再按一按鍵盤......。等一等,為什麼按下鍵盤卻沒有反應呢?

  這個問題讓我修改又測試了一陣子,我猜想大概是標籤並沒有取得鍵盤的焦點(focus)。有了如此推測之後,又翻了一下官方的函式庫,發現這個 QWidget::setFocus() 函式似乎是我所需要的解答。

    label->setFocus();

  將這段程式碼加進去之後,編譯執行試看看。Bingo!現在標籤也能成功取得鍵盤事件囉。


  完整的程式碼如下:

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QKeyEvent>

#define WIDTH   290
#define HEIGHT  140

/**************************************
    創建一個能接收事件的 Label 類別
**************************************/
class QEventLabel : public QLabel
{
    public:
        explicit QEventLabel(QWidget *parent = 0, Qt::WindowFlags f = 0);
        explicit QEventLabel(const QString &text, QWidget *parent = 0,
                                Qt::WindowFlags f = 0);
        ~QEventLabel();

    protected:
        void mouseMoveEvent(QMouseEvent *event);
        void mousePressEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
        void keyPressEvent(QKeyEvent *event);
};

/**************************************
    QEventLabel 建構子
**************************************/
QEventLabel::QEventLabel(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f)
{
}

QEventLabel::QEventLabel(const QString &text, QWidget *parent,
                            Qt::WindowFlags f) : QLabel(text, parent, f)
{
}

QEventLabel::~QEventLabel()
{
}

/**************************************
    QEventLabel 事件處理
**************************************/
void QEventLabel::mouseMoveEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>%d, %d</center>", event->x(), event->y());
    this->setText(msg);
}

void QEventLabel::mousePressEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>Press</center>");
    this->setText(msg);
}

void QEventLabel::mouseReleaseEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>Release</center>");
    this->setText(msg);
}

void QEventLabel::keyPressEvent(QKeyEvent *event)
{
    QString msg;

    if (event->key() == '<')
    {
        // 避免上角括號被當作標籤而不顯示
        msg = "<center>Type: <</center>";
    }
    else if (event->key() >= Qt::Key_Space && event->key() <= Qt::Key_AsciiTilde)
    {
        msg = "<center>Type: " + event->text() + "</center>";
    }
    else
    {
        msg.sprintf("<center>Type: <font color=red>%d</font></center>", event->key());
    }

    this->setText(msg);
}

/**************************************
    Main 主函式
**************************************/
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget *window = new QWidget;
    window->setWindowTitle("Hello, Qt!");
    window->setMinimumSize(WIDTH, HEIGHT);
    window->setMaximumSize(WIDTH, HEIGHT);

    // 調整視窗至螢幕中央
    QSize size = app.desktop()->size();
    window->move((size.width() - WIDTH) / 2, (size.height() - HEIGHT) / 2);
 
    // 建立並設定元件
    QEventLabel *label = new QEventLabel("<center>No Event</center>", window);
    label->setFont(QFont("Courier New", 25, QFont::Bold));
    label->setGeometry(0, 0, 290, 70);

    QPushButton *quit = new QPushButton("&Quit", window);
    quit->setFont(QFont("Monotype Corsiva", 25, QFont::Bold));
    quit->setGeometry(5, 75, 280, 60);

    QObject::connect(quit, SIGNAL(clicked()), &app, SLOT(quit()));

    // 使 Label 變為焦點
    label->setFocus();

    window->show();

    return app.exec();
}

  編譯執行之後的結果:










  編譯出來的程式,我試著轉移到沒有裝 Qt 的電腦執行。沒想到還需要附帶 Qt 目錄下 lib 資料夾的 QtCore4.dll、QtGui4.dll 等動態函式庫。而這些動態函式庫的檔案也都不小,光一個 QtGui4.dll 就要將近 10 MB。

  不過怎麼說,還算是滿好學、好用的,有時間再寫些別的吧!或許來試用一下 Qt Designer。

【筆記】Small Test of Qt

@
  看完官方的 Qt Tutorial 文件之後,想自己實際寫一次 Qt 的程式。在這裡,我想盡量依照我寫的過程將程式碼列出來,所以內文的順序並不是實際程式碼的順序。建議可以對照著完整原始碼來看。


 #define WIDTH   290
 #define HEIGHT  140

  首先,為了方便起見,我直接使用前置處理器定義了程式的寬度(WIDTH = 290)與高度(HEIGHT = 140)。


int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
            .
            .
            .
    return app.exec();
}

  接著,建立一個 QApplication,並傳遞 main() 函式的 argc 與 argv 引數作為其建構子參數。

  然後在程式的最後,利用 QApplication::exec() 函式將 main() 函式的主控權交給 Qt,並將執行結果作為返回值。

    QWidget *window = new QWidget;
    window->setWindowTitle("Hello, Qt!");
    window->setMinimumSize(WIDTH, HEIGHT);
    window->setMaximumSize(WIDTH, HEIGHT);

  現在需要一個頂層元件來作為一個視窗。

  在這裡,我直接使用 QWidget 作為頂層元件。同時,指定其標題為"Hello, Qt!",並使用 setMinimumSize() 與 setMaximumSize 固定其寬度與高度。

  而這裡使用的 WIDTH 與 HEIGHT 就是在前面提到,使用前置處理器定義的。


  空空的視窗還滿無聊的。所以我加入了一個 QLabel 元件。

    QLabel *label = new QLabel("<center>Test</center>", window);
    label->setFont(QFont("Courier New", 25, QFont::Bold));
    label->setGeometry(0, 0, 290, 70);

  沒什麼作用,這個 Label 只是擺好看的。

  文字內容是"Test",並使用 HTML 標籤來作置中。然後使用 QWidget::setFont() 設定文字的字體,並使用 QWidget::setGeometry() 來設定標籤的位置。


    QPushButton *quit = new QPushButton("&Quit", window);
    quit->setFont(QFont("Monotype Corsiva", 25, QFont::Bold));
    quit->setGeometry(5, 75, 280, 60);

    QObject::connect(quit, SIGNAL(clicked()), &app, SLOT(quit()));

  這是模仿 Qt Tutorial 文件加入的 Quit 按鈕。同樣是設定好字體及標籤位置之後,使用 QObject::connect() 將 quit 的 clicked() signal 連結到 app 的 quit() slot。


     window->show();

  接著將把視窗設為可見。


  這樣差不多了吧?不過我想,只有一個沒用的標籤跟一個 Quit 按鈕的程式實在太無聊。所以現在,我還要對這個視窗做一點小手腳:

    QSize size = app.desktop()->size();
    window->move((size.width() - WIDTH) / 2, (size.height() - HEIGHT) / 2);

  首先,我藉由 QApplication::desktop() 取得一個 QDesktopWidget 元件,其提供了程式所在螢幕的相關資訊。接著就可以直接利用 QWidget::size() 取得螢幕的大小。

  需要注意的是,為了要使用 QApplication::desktop(),在這裡我們需要引入 <QDesktopWidget> 這個標頭檔。

  根據螢幕及視窗大小,計算出擺放位置後,再使用 QWidget::move() 做移動。這樣每次啟動程式時,視窗就會自動移動到螢幕的正中央了。


  實際的原始碼如下:

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QDesktopWidget>

#define WIDTH   290
#define HEIGHT  140

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget *window = new QWidget;
    window->setWindowTitle("Hello, Qt!");
    window->setMinimumSize(WIDTH, HEIGHT);
    window->setMaximumSize(WIDTH, HEIGHT);

    // 調整視窗至螢幕中央
    QSize size = app.desktop()->size();
    window->move((size.width() - WIDTH) / 2, (size.height() - HEIGHT) / 2);
 
    // 建立並設定元件
    QLabel *label = new QLabel("<center>test</center>", window);
    label->setFont(QFont("Courier New", 25, QFont::Bold));
    label->setGeometry(0, 0, 290, 70);

    QPushButton *quit = new QPushButton("&Quit", window);
    quit->setFont(QFont("Monotype Corsiva", 25, QFont::Bold));
    quit->setGeometry(5, 75, 280, 60);

    QObject::connect(quit, SIGNAL(clicked()), &app, SLOT(quit()));

    window->show();

    return app.exec();
}

  編譯執行之後的結果:




  有實際編譯出來的人可以試看看改變視窗大小,或是按下最大化按鈕。

  雖說到目前為止,這程式應該還滿無聊的。不過自己實際寫一遍,還是比看著範例打來得好一點?

9月 06, 2008

【轉貼】明星程設師的十大特質

@
Every company is a tech company these days. From software startups to hedge funds to pharmaceutical giants to big media, they're all increasingly in the business of software. Quality code has become not only a necessity, but a competitive differentiator. And as companies compete around software, the people who can make it happen - software engineers - are becoming increasingly important. But how do you spot the 'cream of the crop' programmers? In this post we outline the top ten traits of a rockstar developer.

We've written here before about the future of software development, in which a few smart developers can leverage libraries and web services to build large-scale systems of unprecedented complexity. It only takes a couple of smart engineers to create quality software of immense value, and below is a list of the top ten qualities you should look for when hiring a developer:


1. Loves To Code

Programming is a labor of love. Like any occupation, truly great things are achieved only with passion. It is a common misconception that writing code is mechanical and purely scientific. In truth, the best software engineers are craftsman, bringing energy, ingenuity, and creativity to every line of code. Great engineers know when a small piece of code is shaping up perfectly and when the pieces of a large system start to fit together like a puzzle. Engineers who love to code derive pleasure from building software in much the same way a composer might feel ecstatic about finishing a symphony. It is that feeling of excitement and accomplishment that makes rockstar engineers love to code.


2. Gets Things Done

There are plenty of technical people out there who talk about software instead writing it. One of the most important traits of a great software engineer is that they actually code. They actually get things done. Smart people know that the best way to solve problems is go straight at them. Instead of spending weeks designing complex, unnecessary infrastructure and libraries, a good engineer should ask: What is the simplest path to solving the problem at hand? The recent methodologies for building software, called Agile practices, focus on just that. The idea is to break complex projects into short iterations, each of which focuses on a small set of incremental features. Because each iteration takes just a few weeks to code, the features are manageable and simple. Teams that follow agile practices never create infrastructure for its own sake, instead they are focused on addressing a simple set of requirements. The secret is that when this approach is applied iteratively, a rich, complex piece of software arises naturally.


3. Continuously Refactors Code

Coding is very much like sculpting. Just like an artist is constantly perfecting his masterpiece, an engineer continuously reshapes his code to meet requirements in the best possible way. The discipline of reshaping code is known as refactoring and was formally described by Martin Fowler in his seminal book. The original idea behind refactoring was to improve code without changing what it does, moving pieces of the software around to ensure that the system is free of rot and also does what it is supposed to do based on current requirements. Continuous refactoring allows developers to solve another well-known problem - black box legacy code that no one wants to touch. For decades engineering culture dictated that you should not change the things that work. The issue, though, is that over time you become a slave to the old code, which grows unstable and incompatible. Refactoring changes that, because instead of the code owning you, you own the code. Refactoring establishes ongoing dialogue between the engineer and the code and leads to ownership, certainty, confidence, and stability in the system.


4. Uses Design Patterns

Ever since the so called Gang of Four published their famous Design Patterns book, world-class engineers have been talking about patterns. Patterns are ubiquitous in our world - both in nature and all human endeavors; software engineering is no exception. Patterns are recurrent scenarios and mechanisms that live across languages and systems. A good engineer always recognizes and leverages patterns, but is not driven by them. Instead of trying to fit the system into a set of patterns, the engineer recognizes opportunities in which to apply patterns. Applying a pattern ensures correctness since it leverages existing know-how: a method for solving a particular engineering problem that has worked before.

5. Writes Tests

Long gone are the days when engineers thought of testing as beneath them. After all, how can you be certain that your code is actually working if you never test it? An agile practice called Unit Testing has recently gained popularity because it focuses on writing tests to mirror the code. As the system grows, the body of tests grows with it, providing proof that the code actually works. Experienced engineers know and understand the value of tests, because their goal is to create a working system. Good engineers will always write a test once a bug has been exposed to make sure it does not come back again. But a good engineer also knows not to waste time writing trivial or greenundant tests, instead focusing on testing the essential parts of each component.


6. Leverages Existing Code

Reinventing the wheel has always been one of the biggest problems in the software industry. From inventing new languages to rewriting libraries, the strange drive to ignore and greeno what is already there and already works has been the cause of a lot of software failures. A rockstar engineer will focus on three essential kinds of reuse. First of all, the reuse of internal infrastructure, the code that he and his peers have written. Secondly, the use of third party libraries, for example, in Java, the libraries that are part of JDK or popular libraries provided by the Apache Foundation. And finally, a good engineer would look to leverage web-scale web service, like the ones offegreen by Amazon. Correct leveraging of existing infrastructure allows rockstar engineers to focus on what is most essential - the application itself.


7. Focuses on Usability

Good engineers always focus on the users. Whether the user is a business or an individual, whether the engineer works for a consumer software company or an investment bank, the focus is on working, usable software. How will users interact with the system? Does it provide a simple, intuitive, and smooth experience? The notion that because a software engineer is a techie, he or she thus can not relate to how other people interact with the system is deeply flawed. Good engineers work hard to make the system simple and usable. They think about customers all the time and do not try to invent convoluted stuff that can only be understood and appreciated by geeks.


8. Writes Maintainable Code

The other secret of good engineers is that it takes the same amount of time to write good code as it does to write bad code. A disciplined engineer thinks about the maintainability and evolution of the code from its first line. There is never any reason to write ugly code, a method that spawns multiple pages, or code with cryptic variable names. Rockstars write code which follows naming conventions, code which is compact, simple and not overly clever. Each line of code serves its purpose and resides in the right place. The bits that are difficult to understand are commented, but otherwise naming conventions are clear. Expressive names for methods and variables can make the code self-explanatory.


9. Can Code in Any Language

A good engineer might have a favorite programming language but is never religious about it. There are many great programming languages these days and to say that you only can code in one of them is to demonstrate a lack of versatility. In Java, C#, or C++ you can write any modern software. You can code the back end of any web site in PHP, in Perl, or in Ruby. At the end of the day, the language does not matter as much as the libraries that come with it. A good engineer knows that and is willing and able to learn new languages, new libraries and new ways of building systems.


10. Knows Basic Computer Science

The last, but certainly not the least trait of a great engineer is a solid foundation. A good engineer might not have a degree in computer science but must know the basics - data structures and algorithms. How can you build large scale software without knowing what a hashtable is? Or the difference between a linked list and an array? These are the basics that everyone should know. And the algorithms are just as important - from binary search to different sorts to graph traversals, a rockstar engineer must know and internalize the basics. These foundations are necessary to make the right design decisions when building any modern piece of software.


Conclusion

There are many traits that distinguish great software engineers. Among the ones we discussed, passion is certainly very important. Knowing the basics like code reuse, design patterns, fundamental data structures, and algorithms is necessary, while agile practices of refactoring and unit testing help engineers iteratively evolve complex software. Most importantly, rockstar engineers believe in simplicity and common sense. It is these beliefs that help them succeed in building the seemingly impossible, complex software systems that are necessary in today's world.

Let us know what other traits you think a rockstar software engineer should have, in the comments below.


  作者:Alex Iskold
  出處:Top 10 Traits of a Rockstar Software Engineer