技術的浪潮奔騰不息,浪潮退去之後,留給我們自己的是方法論?還是過時的技術?
----
我們程序員,總喜歡談論所謂“35歲魔咒”,好像“35歲魔咒”成了程序員的專利。然而事實上,35歲,是各行各業的職場人都會面臨的問題。
究其根本,35歲是人到中年的轉折點,如果我們在工作中的價值產出,更多依靠體力,那麼就勢必面臨職業發展開始走下坡路的困境。
編程,原本是一種極富創造力,重視抽象思維與邏輯推演的工作,但我們相當一部分人,把編程做的像事務性工作,平淡如水,如果這樣,“35歲魔咒”就會困擾我們。
在一個社會羣體中,不同的人有不同的選擇,我無意也無法改變大的環境,但希望幫助有意願與“35歲魔咒”鬥爭的程序員,找到一點方向,多幹幾年!
從一道面試題說起
楊輝三角是我在面試中經常會問的一個問題,”請編程,按照指定格式輸出前N行的楊輝三角"。
大部分候選人,拿到問題之後,就開始編碼,首先寫一個兩層的循環,然後開始思考循環的終止條件,經過一番思考,給出一個自己都不相信的答案。我印象比較深刻的一次,候選人來自微信支付,也僅給出了獲取前N行數據的方法,仍然未能找到按照指定格式打印的方法。
很多人會說,離開學校好幾年了,算法早都忘記了,這種問題應該去問校招的同學。我不以爲然,我在意的不是一個具體的算法,而是分析和解決問題的思路。我們可以忘記一些具體的算法,但忘記的同時,應該把算法中蘊含的解決問題的思路內化成自己的武器。
接下來,我和大家介紹下我如何看待這個問題。
圖靈獎得主N.Wirth提出"程序 = 算法 + 數據結構",我更習慣說“程序 = 數據 + 過程”。
數據視角
首先,我們站在數據的視角,來審視這道面試題,可以發現:
1、可以使用二維數組(以php語言爲例)描述楊輝三角的前N行數據
[
[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
]
2、行的數據之間,存在如下規則:
1)每行兩邊數字恆爲1
2)每行中間的數字,是上一行交叉位置兩個數字的和
因此,可以用一個僞代碼描述這種關係:
F(1) = [1]
F(N) = [
1,
F(N-1)[0] + F(N-1)[1],
F(N-1)[1] + F(N-1)[2],
...,
F(N-1)[N-2] + F(N-1)[N - 1],
1
]
過程視角
接下來,我們站在過程視角,審視這道面試題。首先,它的過程可以分爲兩個步驟:1)獲取前N行楊輝三角的數據;2)按照圖示對齊的方式進行打印。
第一步,基於我們前面對數據的分析,可以輕易的得出對應的方法設計:
function yanghui_datas($n); // 獲取前N行楊輝三角數據
function yanghui_line_datas($prev_line_data); // 依據前一行數據獲取下一行數據
第二步,依據圖示對齊方式進行打印。單純的打印是很簡單的,所以,關鍵在於“對齊”。
解決對齊的方法,無非就是給相應的位置留白。但我們發現,該怎麼留白是不清晰的。那就進一步思考,導致留白邏輯不清晰的難點問題是什麼?
通過分析,可以看到,如果只需要輸出前5行,那麼每個數字都是個位數,如果要輸出第6行,那麼就開始有十位數。因此,是數字寬度的不確定性,產生了這裏的困難。
逆向思維,如果數字的寬度確定,那就沒有這個困難。所以:
我們把每個數字放到一個等寬的格子中。這樣,整個問題就清晰了:
格子寬度 = 最大數字寬度 + 1
行前留白 = (LINE_COUNT - LINE_NO) * 格子寬度 / 2
格子內部: (數字居中)
左留白 = (格子寬度 - 數字寬度) / 2
右留白 = 格子寬度 - 左留白 - 數字寬度
編碼
經過上面的分析,代碼幾乎就躍然紙上了。
// 獲取前N行楊輝三角數據
function yanghui_datas($n_line) {
$datas = [];
$prev_line_datas = [];
while ($n_line -- > 0) {
$line_datas = yanghui_line_datas($prev_line_datas);
array_push($datas, $line_datas);
$prev_line_datas = $line_datas;
}
return $datas;
}
// 通過前一行數據獲取下一行數據
function yanghui_line_datas($prev_line_datas) {
if (empty($prev_line_datas)) {
return [1];
}
$line_datas = [];
array_push($line_datas, 1); // 行首
for ($i = 1; $i < count($prev_line_datas); $i ++) {
array_push($line_datas, $prev_line_datas[$i - 1] + $prev_line_datas[$i]);
}
array_push($line_datas, 1); // 行尾
return $line_datas;
}
// 打印指定的楊輝三角數據
function yanghui_print($datas) {
$space = ' '; // 留白字符
$newline = '<br />'; // 換行符
$max_num = yanghui_max_num($datas); // 最大數字
$max_num_width = yanghui_num_width($max_num); // 最大寬度
$unit_width = $max_num_width + 1; // 格子寬度
$line_count = count($datas); // 行數
foreach ($datas as $idx => $line_datas) {
$line_no = $idx + 1; // 行號
$line_prefix_width = ($line_count - $line_no) * $unit_width / 2; // 行前留白數
echo str_repeat($space, $line_prefix_width);
foreach ($line_datas as $num) {
$num_width = yanghui_num_width($num); // 數字寬度
$left_width = intval(($unit_width - $num_width) / 2); // 格子內左留白寬度
$right_width = $unit_width - $left_width - $num_width; // 格子內右留白寬度
echo str_repeat($space, $left_width);
echo $num;
echo str_repeat($space, $right_width);
}
echo $newline;
}
}
// 獲取最大數
function yanghui_max_num($datas) {
$max = 0;
foreach ($datas as $line_datas) {
foreach ($line_datas as $num) {
$max = max($max, $num);
}
}
return $max;
}
// 獲取數字的寬度
function yanghui_num_width($num) {
return strlen(strval($num));
}
最後,過程的兩部分組裝起來,就是想要的結果。
function yanghui_dump($n) {
$datas = yanghui_datas($n);
yanghui_print($datas);
}
補充
有人說,楊輝三角中的數字,可以依據座標直接計算得到,沒關係,替換掉獲取數據的對應部分即可。
啓示
當我們面對問題時,有兩種思維模式:經驗型和能力型。
經驗型思維,搜索自己的知識庫,發現楊輝三角應該要一個兩層循環,就開始執行;執行了一步之後,發現卡住了,下一個問題自己的知識庫中沒有,然後就陷入了沉思!
能力型思維,先分析問題的本質構成,對問題進行分解,將複雜的大問題轉換成多個簡單的小問題,抽絲剝繭,在自己的知識庫中搜索每個小問題的答案,最終解決問題。
兩種思維模式的優劣勢顯而易見,經驗型思維適合解決確定的、已知的、簡單的問題,效率更高;能力型思維適合解決不確定的、未知的、複雜的問題,適應性更廣。
通過程序設計鍛鍊能力型思維
編程,是一項極富創造力,注重邏輯和推演的工作。
當我們開始編程之前,首先需要站在具體問題的層面,對目標系統進行分析,然後,又需要站在抽象視角層面,把目標系統拔高一層進行演繹。在具體與抽象之間,不斷的推敲,找到合理的對現實的抽象描述。
這個分析推演的過程,就是尋找事物本質的過程。只不過,我們的日常工作,面對大量繁雜的需求,沒有過多的時間進行設計層面的思考。現實,把我們磨成了需求翻譯機器。
大部分程序員其實不甘於此,所以,我想通過一份教程,幫助有意願尋求改變的同學,促進這種改變的達成。
2014年,我編寫了目前公司使用的框架,已經穩定運行超過5年,支撐了超過60萬行業務代碼,但它自身只有6000行代碼。接下來一段時間,我會以它爲藍本,站在重新編寫一個框架的角度上,全面的復現編寫框架的思考、分析、設計、實現整個過程,並將其整理爲一份視頻教程,以期能幫助大家尋找到程序設計的感覺。(自願付費,可自由分享與傳播)
整個教程大致分12講,每講有一個獨立的主題,每講時間1-3小時不等,並配以一篇公衆號文章發佈。大的層面框架分爲3個部分:與外部環境的交互、對業務層的封裝約束、ORM之類的輔助工具。
教程
因文字表現力有限,本文僅作爲一個引子,具體關於職業發展的分析、教程想要傳遞的價值、以及傳遞價值採用的方法,請下載視頻教程深入學習。
【十年一劍,透過框架理解抽象思維】是我錄製的一套系列教程,通過重現開發一套框架的思考、分析、設計、實現全過程,幫助大家尋找程序設計的靈感(自願付費,可自由傳播分享)。教程會通過公衆號《抽象思維》發佈。
今天發佈的是第一講《錄製教程的意義》,感興趣想要深入學習的同學,請掃碼下載視頻教程(下載地址: https://pan.baidu.com/wap/init?surl=IZ24Az5GFpQoQSD4WbfR8g 提取密碼:rcga)