學生三年,職場兩年。五年之內,雖無大成,然心中有感,不禁自發。
我不清楚具體有多少人初入大學確定專業時就感覺上錯了船,但我覺得不在少數。轉專業似乎是條出路,但是很奇怪的邏輯是:
一般只有專業成績前10~20%才有機會。
不過這只是一個託辭,自身渾渾噩噩才是問題的根本。
記得很清楚,大一課堂上,清醒的時候不多,從來也沒坐過前幾排。被輔導員批評過,也在期末等成績的時候膽戰心驚,但從沒想過自己要做什麼。就這樣,一年。
謝謝通識教育有幸學校開設了較多的通識教育課,作為水利水電工程專業的學生,雖然不少同學對《C/C++語言程序設計》和《電工與電子技術》這兩門課不感興趣,但是幫我打開了一扇窗。
初次接觸 C 語言,讓我看到了程序世界的精彩。慢慢地,我沉迷其中,如痴如醉。那本教材,是我讀過最多的課本,細節之處都寫下筆記,或是心得,亦有不解。作業和考試不再是應付,最終也取得不錯的成績。
後來報考計算機二級,也毫不猶豫地選擇 C 語言,並順利通過。
而《電工與電子技術》這門課,真正讓我接觸硬體知識。我很喜歡開設的電子實驗課,理論用於實踐,動手完成各種硬體電路的搭建。
弱水三千,只取一瓢飲信息技術領域有眾多行業和職業方向,當初我也是面臨諸多選擇。往上,可以選擇純軟體;往下,可以選擇軟硬體結合。在探究和調研職業方向的路上,我接觸了較多的東西。
那段時間,我泡在圖書館,在計算機科學那麼多排的書架前,如饑似渴翻閱著。這期間,我學習了網站建設、計算機輔助技術、嵌入式開發、自動化與工業控制以及數字電路等等。我沒有特別仔細的研讀,也刻意不去了解技術細節,目的是抽絲剝繭找到自己的最終方向。
選擇嵌入式軟體,看重的是物聯網,也因為自己喜歡底層開發,與硬體打交道樂此不疲。在單片機和嵌入式 Linux 這兩塊,我優先選擇了單片機開發,將 Linux 往後放一放。
1.2 堅定轉行魚與熊掌不可兼得。本專業的學習在自己看來也算不上魚,給自己定下的目標就是專業不掛科,一身心撲到正業上。
課堂上,埋頭看《微機原理》;宿舍中,學習單片機開發。只有在期中或期末的考試周,才將時間用在專業考試準備上。
當然,自我學習並沒有那麼順利,遇到諸多的問題,自我管理的能力也有一定的問題。
1.3 尋求出路臨近畢業之時,便不得不尋求自己的出路。首先,本專業的工作是不愁的,但並非心之所願;而後有兩條路:跨專業考研和跨專業找工作。
深思熟慮過後,決定兩條路同時走。無論何時,好好學習是不會錯的。以備考之學,滋求職之事,齊頭並進,較為穩妥。事後證明,這樣的選擇是正確的。
在備考的過程中,系統地學習了計算機科學幾門基礎課程,例如《計算機組成原理》、《計算機作業系統》、《計算機網絡》、《資料庫原理及應用》和《數據結構與算法》等等。這些知識內容對後面的應聘面試大有裨益,順利獲得心儀的職位。
至於考研之事,初試表現平平,後因求職定局,複試的心思有所浮動,最終並未被錄取。倒也沒有太多的後悔,當時家裡房貸壓力較大,也有意早日工作為父母分擔。
工作兩年遙記得畢業不到幾天,便入職新公司。公司深耕工業網際網路領域,致力於工業生產設備安全與可靠性管理的研究與開發,我在終端開發部門擔任嵌入式軟體助理工程師一職。
2.1 職場新人公司為客戶提供端到端——硬體產品端到系統平臺端——的解決方案。作為新人,工作之初並沒有直接參與終端產品軟體開發,而是負責各個項目硬體終端到系統平臺的配置和數據接入,以及終端設備的測試工作。
這樣的崗位安排有助於自己了解整個公司的業務架構,若只是參與某項終端產品的開發,則猶如管中窺豹。而測試的工作也讓自己熟悉了終端設備,並且深刻體會到測試工作的意義和重要性。
至此半年,完成了職場新人之蛻變。
2.2 獨當一面2020年不易,不僅是生活上,還有工作。在這一年裡,我完成了一款量產產品和三款試產產品的軟體開發。說是四款產品,其實大部分的軟硬體設計是一樣的,所以以下從其中之一詳述,並解釋其他三款產品設計的不同點。
第一款產品
前文說到,公司致力於工業生產設備安全與可靠性管理的研究與開發,其重點就是設備振動分析,因此終端開發部門的產品大多是振動檢測器。無線振動溫度檢測器是我經手的第一個項目,也並不是從零開始的,是從初代產品軟硬體迭代而來。
無線振動溫度檢測器採集振動溫度傳感器數據,進行初步的邊緣計算,然後將原始數據和分析數據通過無線通信方式傳輸到網關設備。具體的硬體設計方案不便闡述,這裡作簡單介紹。
振動數據採集電路中,微控制器提供給模數轉換晶片的時鐘信號控制後者的採樣頻率,提供給濾波器的時鐘信號控制其截止頻率;
加速度傳感器的模擬信號通過濾波器濾波後作為模數轉換晶片的輸入信號,模數轉換晶片自動將模擬信號轉換為數位訊號;
微控制器和模數轉換晶片通過串行外設接口(SPI)總線通信,讀取振動數位訊號。溫度數據採集電路中,微控制器和溫度晶片通過集成電路總線(I2C)通信,獲取溫度數據。
微控制器和 ZigBee 通信模組之間通過通用異步收發傳輸器(UART)進行通信,將傳感器原始數據或者處理過的數據上傳至網關設備;
同時 ZigBee 通信模組也可以接收網關設備下發的各種指令,通過UART接口發送給微控制器。
軟體上採用多線程設計方案,基於國產實時作業系統 RT-Thread OS。主線程負責硬體初始化、數據採集和上傳應用以及休眠管理,通信線程由主線程在進行數據上傳業務時創建,看門狗線程在軟體異常時進行系統復位。以黑盒的角度觀察,設備周期喚醒採集和上傳數據,然後進入休眠。參數配置也通過無線通信進行修改。
其餘三款產品第二款產品設計時,在第一款產品硬體基礎上更換了新的加速度傳感器,可以直接輸出三軸加速度數位訊號,因此也搭配了更大內存容量的微控制器。軟體設計上和之前沒有太多差別,通信協議上作了兼容修改,以滿足多軸振動數據。
第三款產品設計時,在第一款產品硬體基礎上採用 NB-IoT 通信模組進行數據傳輸。軟體重新進行設計,主線程負責硬體初始化和休眠管理,主線程創建指令線程和通信線程;
指令線程負責從指令隊列取指執行,指令類型分為內部指令和遠程指令,同時也可能產生通信任務;
通信線程負責從通信任務隊列中獲取任務執行,同時接收伺服器遠程指令;
看門狗線程在軟體異常時進行系統復位。
因為指令執行時可能產生通信任務,通信時也可能收到新的指令,所以在指令線程和通信線程中,用到了優先級翻轉,確保這兩個線程始終是第一和第二優先級。
當無指令且無通信任務時,才由主線程接管控制權進行休眠和喚醒管理。由於更換了通信模組,因此驅動層和網絡層重新編寫代碼,好在 RT-Thread OS 有現成的 AT 組件,方便了驅動層的設計和編碼。
協議方面,參照選用的物聯網平臺文檔和實際應用重新設計,充分考慮未來的擴展性。
第四款產品也是基於第一款產品的設計,從低成本的角度出發,在其他硬體原理不變的情況下,使用復用器,將振動增加到四通道。
軟體上大部分內容可以從之前代碼移植甚至不需要修改,但是仍然帶來一些變化。
首先,之前的時間管理和參數管理是一維的,即數據上傳周期和各類參數都只需要一個。例如原先有電池電量、溫度、振動時域數據和特徵數據四個獨立的上傳周期,那麼對於現在四通道的產品,需不需要十六個獨立的上傳周期?
同樣的,對於參數管理,某些與傳感器個體特性相關的參數(如靈敏度)則必須擴展成四個,其他的參數則需要單獨評估。
其次,四通道的使能和失能是否應該是可配置的。例如通過修改通道選擇參數的二進位編碼,可以靈活控制使用哪些通道,但這同時又涉及到傳輸協議。
因為有些技術細節沒有介紹,因此難免會引起讀者的困惑抑或是質疑,這裡不過多闡述,總之這是一款需要短時間交付、只有簡單的需求文檔、限於技術要求的產品。
2.3 二三心得這一年半的工作當中,確實學到了很多,也踩過不少的坑。有一些摸索出來的淺顯經驗,也有一些一直都懂但沒做好的道理,在此將這二三心得付諸文字,與君共勉。
軟體需要設計,且需要好好設計也許是帶我的良師覺得我開發經驗尚淺,害怕我寫出來的軟體 Bug 頻出,又或許他有意識培養我先設計後實現的良好習慣,總之在這過程中我明白了一個直白的道理——良好的軟體是設計出來的,當軟體被設計好過後,程式設計師只是在用具體的程序設計語言翻譯它罷了。
如果設計和構思階段不能理清自己的思路,那麼實現時也不可能清晰明了,這不僅僅是軟體開發領域的原則。
儘早測試和自動化測試在工作的一年半內,我做過相當多的測試工作。除了自己的軟體需要充分的測試,其他的產品也需要,但是這過程不是很輕鬆和順意。資料缺失,人工投入較多,沒有良好的測試規範和指導,這些都是弊病。
測試驅動開發不是所有人能玩得轉的,但開發中持續測試應當重視。儘早測試可以在代碼體量不龐大的時候抓住害蟲,試想在幾百行代碼和幾萬行代碼中找出問題,哪個更加簡單?
自動化測試則是把人從繁雜的工作中解放出來,單元測試、集成測試、系統測試和回歸測試都是必需且重要的,據我了解,這些在嵌入式軟體開發領域還不是很流行。
文檔不知道你有沒有遇到以下這些問題:
產品使用者總是詢問開發人員某些細節,是不是讓你很苦惱?
聯調時,和同事的交流是不是佔用你太多的時間?
工作交接的過程中,有沒有足夠的資料讓接手人員快速進入工作?
諸如此類的問題數不勝數,解決問題的核心要素就是文檔,詳盡有用的文檔。
缺乏文檔已經是程式設計師日常工作中排名前幾的難題。代碼文檔化也是近年來風靡的概念,並且有較多工具可以幫助我們快速實現這一目標。
在寫代碼時,依據特定的規則添加注釋,便可以藉助類似 Doxygen 這樣的工具生成開發文檔,非常有助於提高工作效率和進行信息交換。
文檔代碼化也同樣值得注意,將文檔以類代碼的領域特定語言的方式編寫,並借鑑軟體開發的方式(如源碼管理、部署)進行管理。
二進位文檔的優勢和劣勢都相當明顯,而使用 Markdown 這類標記語言寫出來的文檔,雖然缺乏豐富的表現力(因為設計目標就是輕量),但對於軟體開發領域絕對夠用,並且可以解決二進位文檔版本管理難的問題。
2.3.4 最快的成長是學習優秀的人,而不是自己領悟沒人一開始就能領悟各種設計模式和開發原則,養成良好的代碼風格和習慣。在沒有學習和別人斧正的情況下,也許工作一輩子還只是個代碼民工。為了較好地闡明這兩句話其中的含義,在這分享一次我閱讀別人代碼的真實經歷。
有一次老闆讓我和一位硬體同事重新生產一款早期的終端產品,用於公司創立初期承接的項目中損壞產品的替換。
需要強調的是,小公司創業初期沒有完善的產品設計開發和生產的流程,資料也是混亂不堪。
本以為不需要做什麼事情,但很明顯我低估了這項任務,因為生產出來的產品工作異常,深入調試過後才解決問題。
我打開從同事那拷貝過來的工程文件,沒錯,資料都是拷貝的,沒有使用版本管理工具。這是一份 MDK Keil 工程文件,主控是 STM32 系列,一個幾百行的主函數包含了所有應用邏輯。單從主函數就能看出相當多的問題。
Hal 庫和寄存器混用
整個工程應該是使用 STM32CubeMX 生成的,基於 Hal 庫,但摻雜著大量的寄存器操作,並絕不是因為效率。
標識符命名停留在初學者水平
uint32_t ii 和 uint16_t i 讓人無語;大小駝峰命名和小寫字母下劃線命名混用;
隨處可見的幻數,可讀性極差,容易出錯
毫無章法的餵看門狗,感覺像是調試時隨性加上
條件語句濫用,根本沒考慮擴展性
沒有架構設計,直接處理通信協議的組包和拆包
我一個初出茅廬的職場新人都看出這麼多問題,簡直可以當作 Code Review 的反面教材,據說當時的開發人員也是有好幾年工作經驗的。
站在巨人的肩膀上才能看得更遠。
因此,多逛逛 Github,深入學習優秀的案例,多看書。
2.3.5 適當參加面試面試可以為了跳槽,也可以為了增長見識,摸摸自己的底,這裡我主要想談談後者。
在公司,可能沒有人會考察你的基礎知識是否紮實,但面試時一定會。工作一年多,慢慢忘了大小端和字節對齊的一些細節,也沒有再寫基礎數據結構和算法代碼。
而面試就是考場,能夠讓自己清楚自己的不足,同時也能知道企業需要什麼樣的人才,有助於找到自己的職業方向甚至是事業。
寫在最後五年,很慶幸自己仍然熱愛選定的方向。
五年,自認為沒有虛度如金的光陰。
新的一年,我們的故事還將繼續。