1. 程式人生 > >技術債務終於還得差不多了

技術債務終於還得差不多了

這周把License授權給改了,由8個檔案變成了3個,由2個工具變成1個,1515行觥籌交錯的程式碼變成了1175行秩序井然的程式碼,維護難度由沒有維護的無窮大變成很容易看得懂,支援的license長度由117位元組變成無限,支援的授權方式由檔案變成檔案和網路。

這標誌著我們技術債務還得差不多了,很快都是容易維護的社會主義產物了。無債一身輕啊!無債一身輕啊!無債一身輕啊!重要的事情說三遍,重要的事情說三遍,重要的事情說三遍。

貼一段非關鍵程式碼對比下,RSA加密然後用BASE64加密,之前的程式碼估計是被車輪戰碾壓過了,每個人都改一次,改得都不知道要幹啥了:


}


char* aes_encipher(const
char *in_buf, const char* password, RSA* rsa_shield, int random_salt) { char* out_buf = NULL; int rsa_in_len = 0; char* rsa_in_buf = NULL; int rsa_out_len = 0; char* rsa_out_buf = NULL; char salt[PKCS5_SALT_LEN] = {0}; int
in_buf_len = strlen(in_buf); BIO* write_bio = NULL; BIO* cipher_bio = NULL; BIO *b64_bio = BIO_new(BIO_f_base64()); BIO *mem_bio = BIO_new(BIO_s_mem()); if (!mem_bio) { error_log("BIO_new(BIO_s_mem()) error\n"); goto end; } if (!b64_bio) { error_log("BIO_f_base64 can't be created\n"
); goto end; } write_bio = BIO_push(b64_bio, mem_bio); if (random_salt) { if (RAND_pseudo_bytes((unsigned char*)salt, sizeof(salt)) < 0) { error_log("PRNG error\n"); goto end; } } else { strncpy(salt, magic, sizeof(salt)); } if (!rsa_shield) { if (!(BIO_write(write_bio, magic, magic_len) == magic_len && BIO_write(write_bio, (char *)salt, sizeof(salt)) == sizeof(salt))) { error_log("error writing salt to output\n"); goto end; } } else { //include the '\0' end of password rsa_in_len = magic_len + PKCS5_SALT_LEN + strlen(password) + 1; rsa_in_buf = (char*)OPENSSL_malloc(rsa_in_len); memcpy(rsa_in_buf, magic, magic_len); memcpy(rsa_in_buf + magic_len, salt, PKCS5_SALT_LEN); strcpy(rsa_in_buf + magic_len + PKCS5_SALT_LEN, password); if (rsa_encrypt_or_decrypt(rsa_shield, rsa_in_buf, rsa_in_len, &rsa_out_buf, &rsa_out_len, ENCRYPT) != 0) { error_log("rsa encrypt aes key error\n"); goto end; } if (!(BIO_write(write_bio, rsa_out_buf, rsa_out_len) == rsa_out_len)) { error_log("write encrypted aes key error\n"); goto end; } } cipher_bio = get_aes_cipher_bio(salt, password, ENCRYPT); if (cipher_bio == NULL) { error_log("get cipher bio error\n"); goto end; } /* chain wbio and cipher_bio filter BIO */ write_bio = BIO_push(cipher_bio, write_bio); if (BIO_write(write_bio, in_buf, in_buf_len) != in_buf_len) { error_log("error writing content to output\n"); goto end; } if (BIO_flush(write_bio) != 1) { error_log("error flush to output\n"); goto end; } out_buf = copy_mem_bio_data(mem_bio); end: BIO_free_all(write_bio); if (rsa_in_len) { OPENSSL_free(rsa_in_buf); } if (rsa_out_buf) { OPENSSL_free(rsa_out_buf); } return out_buf; }

誰要是能看懂就真的要跪地上給磕頭,當然license嘛,就是要看不懂防止破解——額,無語。這個程式碼的問題是:

  1. 最開頭那個{後面,就是函式宣告那裡,竟然換了兩行,其他地方就只有一行,這種就是隨機的程式碼。
  2. rsa_shield為NULL時,就用password,也就是這個函式其實有可能用rsa,有可能用aes,反正這個用什麼是說不太清除的。
  3. end標籤,這種c語言的GOTO,其實用結構體儲存指標,然後釋放會好些(模擬C++的解構函式)。
  4. 變數宣告在最開頭,其實現在的C編譯器都支援在用的地方宣告變數。變數寫在一坨,擴大了作用域,都不知道幹啥。可能是因為goto導致的。
  5. copy_mem_bio_data,這種也算個函式?直接讀就好了,就幾行程式碼,不是看著幾行程式碼湊齊了就搞個函式,那初中生的水平就知道怎麼劃分函式。
  6. write_bio這種變數命名,像是個函式,動詞加名詞。好神奇的名字。而且型別作為字尾,真的是太初級了,我想起了vhost_listapp_arrayrefer_vector長篇累牘的鬼名字。
  7. error_log每個日誌函式後面都加\n,這種用巨集定義展開自動加不好麼?查查__VA_ARGS__這個巨集定義就知道了。
  8. 返回值是char*,要是有錯誤咋辦?返回NULL?咋知道是啥錯誤?應該用錯誤碼的,輸出的buf用指標嘛。
  9. 整個函式的職責不清晰,裡面的程式碼混合了太多引數,各種資料流都不知道幹啥的。

總之,這種程式碼就是小學生的水平,或者是喝醉了的程式設計師寫的吧。反正時代久遠,也不知道誰寫的了。

看水平高點的猴寫的程式碼:

int SrsRsa::encrypt_hwinfo(string hwinfo, string& ehwinfo)
{
    int ret = ERROR_SUCCESS;

    if (bio) {
        BIO_free_all(bio);
    }

    BIO* mem_bio = BIO_new(BIO_s_mem());
    if (!mem_bio) {
        ret = ERROR_LICENSE_GENERATION;
        srs_error("BIO_new memory io failed. ret=%d", ret);
        return ret;
    }
    bio = mem_bio;

    BIO* b64_bio = BIO_new(BIO_f_base64());
    if (!b64_bio) {
        ret = ERROR_LICENSE_GENERATION;
        srs_error("BIO_new base64 io failed. ret=%d", ret);
        return ret;
    }
    bio = BIO_push(b64_bio, bio);

    // encrypted by segment RSA.
    string encrypted;
    if ((ret = srs_segment_rsa_encrypt(rsa, hwinfo, encrypted, false)) != ERROR_SUCCESS) {
        return ret;
    }

    // write to bio.
    if (BIO_write(bio, encrypted.data(), encrypted.length()) != encrypted.length()) {
        ret = ERROR_LICENSE_GENERATION;
        srs_error("BIO_write failed. ret=%d", ret);
        return ret;
    }

    if (BIO_flush(bio) != 1) {
        ret = ERROR_LICENSE_GENERATION;
        srs_error("BIO_flush failed. ret=%d", ret);
        return ret;
    }

    BUF_MEM* raw;
    BIO_get_mem_ptr(bio, &raw);
    ehwinfo.append(raw->data, raw->length);

    return ret;
}

臥草,不言自明吧?將硬體資訊用RSA加密後用BASE64加密,就這麼簡單。維護這種清楚的程式碼,就是一種休閒,和遊山玩水一樣自在。一看到垃圾程式碼,就像吃垃圾一樣,噁心頭痛,腿抽筋。

各位看這個文章的程式猴們,能不能認真寫好程式碼?提升水平,多看看經典的書,多學習,多改變?能不能不要一副年紀太大什麼都懂,一聽意見就狡辯?本人30歲了還學了go和scala,是在已經做完SRS之後(還沒有驕傲自滿),大學我就把經典的軟體書籍都好好讀了(MFC深入淺出我每個例子都敲過程式碼理解過,資料結構我都實現過,人月敏捷我認真讀過,設計模式我都能畫出來),你基礎差我這麼多,積累也差我這麼多,有什麼理由不好好學習?

不好好學習不長進的程式猴就是不要臉。