iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 2
2
Software Development

保持前進、持續優化程式碼內涵系列 第 2

02. 看的懂的程式碼,才是好的程式碼

在開發時,為了快速或是避免麻煩,可能會用簡單的代號,例如 aa 這種名稱,來暫時做為變數的名稱。這無可厚非,但是...假若在完成該功能當下,沒有進行最基本的重構—改名。

也許三個月後,也許一年後的某一天,突然發現程式有需求變動,不管你是要修改自己開發的程式,還是要維護前人遺留下來的軟體。這時,你將程式專案開啟,花費了一番苦戰,好不容易找到要修改變動的程式區塊。

看著程式碼中,各種無意義的命名,苦苦的思考,為什麼當初會這樣寫?這個變數是什麼意義?邊改寫程式,邊幹譙當初寫下這段程式的人。

上面的經驗,想必有許多人都有過這種經驗。

下面,我將以前接手,研究所學弟的原始碼分享給大家看,後面幾篇文章,都會做為範例操作。
老實說,當時,第一眼看到下面的程式碼時,只有傻眼二個字

這是天書嗎?

public int[,] ga(int[,,] im_1, int[,,] im2_1)
{
    int h = im_1.GetLength(1); int w = im_1.GetLength(0);
    //Bitmap bimage = new Bitmap(w*3, h*3);

    int[,] k = new int[2, ggg];

    int[] k1 = new int[ggg];
    int[,] k2 = new int[3, ggg];

    for (int ie = 0; ie < ggg; ie++)
    {
        k1[ie] = 1000;
    }

    Random innerRnd = new Random(Guid.NewGuid().GetHashCode());
    Random innerRnd1 = new Random(Guid.NewGuid().GetHashCode());

    for (int j = 0; j < ggg; j++)
    {
        k[0, j] = (innerRnd.Next(255)) - Val01;
        k[1, j] = (innerRnd1.Next(255)) - Val02;
    }

    progressBar1.Maximum = 26;

    int iu, ju, temp, temp1, temp2;
    int score = 0;

    while (score <= 25)
    {
        score = score + 1;
        progressBar1.Value = score;

        for (int score1 = 0; score1 <= 15; score1++)
        {
            int[,] k111 = k;
            Random innerRnd8 = new Random(Guid.NewGuid().GetHashCode());
            int a1 = innerRnd8.Next(ggg);
            Random innerRnd9 = new Random(Guid.NewGuid().GetHashCode());
            int a2 = innerRnd9.Next(ggg);

            double rrr = _RRR(k[0, a1], k[1, a1], im_1, im2_1);
            double rrr_1 = _RRR(k[0, a2], k[1, a2], im_1, im2_1);

            if (rrr > rrr_1)
            {
                k[0, a1] = k[0, a2];
                k[1, a1] = k[1, a2];
                k1[a2] = Convert.ToInt32(rrr_1);
                k1[a1] = Convert.ToInt32(rrr_1);
            }
            else if (rrr <= rrr_1)
            {
                k[0, a2] = k[0, a1];
                k[1, a2] = k[1, a1];
                k1[a1] = Convert.ToInt32(rrr);
                k1[a2] = Convert.ToInt32(rrr);
            }

            Random innerRnd33 = new Random(Guid.NewGuid().GetHashCode());
            int Crossover = innerRnd33.Next(10);
            if (Crossover <= 7)
            {
                Random innerRnd2 = new Random(Guid.NewGuid().GetHashCode());
                int a4 = innerRnd2.Next(ggg);
                Random innerRnd3 = new Random(Guid.NewGuid().GetHashCode());
                int a5 = innerRnd3.Next(ggg);

                int k_33 = (k[0, a4]) + Val01;
                int k_44 = (k[1, a4]) + Val02;

                int k_55 = (k[0, a5]) + Val01;
                int k_66 = (k[1, a5]) + Val02;

                string k_33_old = Convert.ToString(k_33, 2);
                string k_33_old1 = k_33_old.PadLeft(8, '0');

                string k_55_old = Convert.ToString(k_55, 2);
                string k_55_old1 = k_55_old.PadLeft(8, '0');

                Random innerRnd30 = new Random(Guid.NewGuid().GetHashCode());
                int a44 = innerRnd30.Next(8);

中略

            for (iu = 0; iu < ggg; iu++)
            {
                for (ju = 1; ju < ggg; ju++)
                {
                    if (k2[2, ju - 1] > k2[2, ju])
                    {
                        temp = k2[2, ju - 1];
                        temp1 = k2[0, ju - 1];
                        temp2 = k2[1, ju - 1];

                        k2[2, ju - 1] = k2[2, ju];
                        k2[0, ju - 1] = k2[0, ju];
                        k2[1, ju - 1] = k2[1, ju];

                        k2[2, ju] = temp;
                        k2[0, ju] = temp1;
                        k2[1, ju] = temp2;
                    }
                }
            }

            int ddd1 = 0;

            for (iu = 0; iu < gggzz; iu++)
            {
                ddd1 = ddd1 + (k2[2, iu]);
            }
            int ddd_1 = Convert.ToInt16(ddd1 / gggzz);
            dddd_2 = 0;

            for (iu = 0; iu < gggzz; iu++)
            {
                dddd_2 = dddd_2 + Math.Abs(ddd_1 - k2[2, iu]);
            }
        }

        if (Math.Sqrt(dddd_2) <= 0.005 && k2[2, 0] <= 5)
        {
            score = 26;
            progressBar1.Value = 26;
        }
    }

    int gg = 0;
    int gg1 = 0;
    int[,] good = new int[2, ggg];

    for (int j111 = 0; j111 < gggzz; j111++)
    {
        gg = gg + k2[0, j111];
        gg1 = gg1 + k2[1, j111];
    }

    int x_new = Convert.ToInt16(gg / gggzz);
    int y_new = Convert.ToInt16(gg1 / gggzz);

    int[,] x_y = new int[2, 1];

    x_y[0, 0] = x_new;
    x_y[1, 0] = y_new;
    return x_y;
}

問題點

上面的程式碼,簡單來說,是使用基因演算法(Genetic Algorithm, GA),找出兩張影像的最佳疉合點。
若是要對這段程式進行維護或修改,其實花費額外的時間,在了解程式碼本身所代表的意義。

不易閱讀的因素,大致上包含

  • 大量無意義的變數名
  • 區域變數與全域變數無法識別
  • 程式的邏輯與介面高耦合性
  • 函數名稱與實際動作內容有差異

遊戲規則

為了持續精進程式可讀性,我訂下了一些遊戲規則(原則)

  1. 請使用有意義的命名
  2. 在上版或釋出前,請刪除無意義或無用的註解。

上一篇
01. 精進程式碼永遠不嫌晚,千裡之行,始於足下。
下一篇
03. 工欲善其事、必先利其器 !英雄王,武器的儲備足夠嗎?
系列文
保持前進、持續優化程式碼內涵24
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言