項目 | 內容 |
---|---|
這個作業屬於哪個課程 | 2020春季計算機學院軟件工程(羅傑 任建) |
這個作業的要求在哪里 | 提問回顧與個人總結 |
我在這個課程的目標是 | 學習軟件工程相關知識,培養自己獨立和團隊開發能力 |
這個作業在哪個具體方面幫助我實現目標 | 回顧並反思自己之前提出的問題,總結一學期以來在軟件工程實踐中的收獲 |
作業正文...... | 見下文 |
其他參考 | 我以前的提問鏈接 |
1、回答以前的提問
(1)關於goto的用法
當時的問題如下:
在4.3節,講代碼設計規范的時候提到了 goto的用法,書中這樣寫道:
函數最好有單一的出口,為了達到這一目的,可以使用goto。只要有助於程序邏輯的清晰體現,什么方法都可以使用,包括goto。
然而,在大一的C語言課程中,任何一個老師在講到循環的時候都會特別強調“盡量不要使用goto”,並且在Dijkstra的這篇文章中也提到了使用goto有着諸多害處,甚至想要提議在高級編程語言中廢除goto。
由此我產生了疑問:是否應該使用goto語句呢?或者說什么時候使用goto是合適的呢?注意到書中提到了一個比較模糊的標准,即“只要有助於程序邏輯的清晰體現”,那么具體來講什么樣的goto才有助於體現程序的邏輯呢?(因為C語言課上老師們的觀點一直都是“goto”會破壞程序的邏輯和可讀性)
對於這個問題,現在看來是有點太鑽牛角尖了。實際上,在我這一學期的開發過程中,很少遇到一定要用goto不可的場景,而且我擔任的一直都是后端開發的任務,相比前端可以說在語句的邏輯上是更加復雜的。即使在這種情況下,我的循環語句中也基本用不到goto,簡單的break和continue已經足夠解決絕大部分的循環問題。出現這種情況,一方面歸功於現有的開源項目框架非常多,這些框架往往有着完善的方法調用接口,很少需要我們寫太多的復雜邏輯;另一方面也可以說明實踐中必須用goto的情況確實比較少。
(2)關於類的使用
當時的問題如下:
在4.3.4節,談到如何處理C++中的類的時候,作者提到了“僅在必要時才使用類”。但是在面向對象的編程中,提倡的是“萬物皆類”的思想,這就產生了矛盾。固然,面向對象編程並不是在所有條件下都適用,但是C++本身是一門面向對象的語言,采用面向對象編程的方法無可厚非。那么作者這樣“一刀切”式的下結論是否太過絕對了呢?
在個人項目和結對項目中,我確實使用了類,例如把直線、圓等圖形都分別建立一個類,這樣做的好處首先在於可以通過實現類中的方法來方便地進行功能的增加,此外,在進行單元測試的時候,也可以直接新建一個類的實例來調用其中的方法進行測試,達到測試某個特定函數的目的。現在再來看這個問題,我覺得我當時對“僅在必要時才使用類”的說法理解可能有些偏差。現在我的理解是,如果認為確實需要用到類那么就放心大膽的去用。C++本身雖然是一門面向對象的語言,但它還是兼容了C語言一些特性,因而不能做到完全的面向對象,所以要像java一樣,甚至連main函數都要設為一個類那樣的形式,在C++中本身就是不太可能實現的(如果不是有意而為之的話)。書中的這句話的初衷或許是要告誡我們類固然好用,但也不能濫用——像java一樣把一切都設為類的做法在C++中是不可取的。
這里總結一下前兩個問題。現在看來這兩個問題都太注重文字的細節了,實際上軟件工程是一門講授工程化方法的課程,是要教我們如何開發出一個好用軟件的工程化方法的,這其中包括項目管理、代碼管理、質量管理等等。我認為,前兩個問題可以歸結為代碼管理中的代碼規范部分,而代碼規范一般是由項目組在項目開始之前就已經制定好了的,不同的項目有着不同的要求,因而其代碼規范也不盡相同。我們在實際進行軟件工程開發的過程中,只要做到遵循代碼規范開發即可,對於一些過於細節的部分可以不去或是少去關心一些。如何制定並遵循代碼規范進行代碼編寫、誰以什么流程來審查代碼是否符合規范,這是軟件工程這門課更加關心的內容,而不是代碼規范細節上的的內容如何。
(3)關於“創新者”和“先行者”的關系
當時的問題如下:
在16.1.4節,作者探討了創新者和先行者的關系。作者提出,“大部分成功的創新者都不是先行者”,並舉了很多領域的多家公司的例子來佐證這個觀點。但我並不完全認同這個觀點。我認為,成功的創新者之所以能夠成功,是因為他們在某一領域做出了大膽的創新,這個創新是其他公司沒有並且符合用戶的需求和偏好的,例如一個新的商業模式、一個令人耳目一新的用戶界面等等。從這個角度講,它們也可以說是這個領域的先行者。教材上的“先行者”似乎被界定為了僅僅指技術上的先行者,我認為這是不夠全面的,畢竟技術並不是關乎一個創新成功與否的最重要因素。
我現在其實能理解“大部分成功的創新者都不是先行者”這句話了。我們的團隊項目,DDL Killer,我認為做的還是相當成功的,這一點從Alpha和Beta階段的用戶量和用戶反饋都可以看出。但我們的團隊項目其實沒有用什么新技術,全是基於已有的框架——前端基於Vue,后端基於Django,因此在技術上並談不上是“先行者”。但我們在解決用戶需求這個層面上確實實現了創新,在這方面我認為是這個領域的“先行者”。例如,我們觀察到北航課程中心存在的大量用戶需求與使用起來諸多不便的矛盾,因此就想做一個app來優化同學們的課程中心體驗,之后又結合Microsoft Todo的優點,開發出了我們現在的DDL Killer,可以說吸收了多個軟件的優點而融合成了我們現在的項目。但是必須要注意到的是,如果不是有課程中心的使用復雜,我們是不太可能想到要優化這一點而推出我們的項目的;如果不是有Microsoft Todo的簡單易用,我們也不會想到仿照它的一些功能去做我們的項目。這樣看來,正是有了那些“先行者”的前車之鑒,我們才能在此基礎上改進並創新,以推出更好的產品,這樣與同類產品對比起來就會更有競爭優勢,也往往更容易成功。
(4)關於創新的時機
當時的問題如下:
在16.2節,作者探討了創新的時機,並提出了新技術基本都要經歷的幾個發展階段,鼓勵我們在觀察到一門新技術出現或者正在被炒作的時候,能思考其正處於哪個發展階段。但是我們知道,市場是有滯后性的,有可能大眾正在追捧一門技術的時候,它卻已經處於下降期了。那么如何才能真正地辨別出一個新技術所處的發展階段呢?我認為,如果不是親自去了解和參與到這門技術中,是很難得知它的前景到底如何的。
關於這個問題,我本學期沒有什么機會去實際體會新技術發展的各個階段,因此現在還難以回答。但軟件工程是一門非常講究實踐的課程,這一點我在這學期的項目中體會是很深的,所以我現在認為如果想要徹底了解一門技術的前景如何,是要親身去實踐的。
(5)關於小故事“魔方的創新”
當時的問題如下:
在16.4節中,作者使用一個小故事,來講述我們在創新的過程中要明確目標用戶,並時刻注意自己是否在面向目標用戶進行創新。故事之中有這么一小段情節:
果凍是學校里第一個學會了魔方口訣的,在學校這個小范圍里姑且算一種創新,但是你的競爭力有護城河么——你能否保持只有你會背這個口訣?
在故事中,果凍和其他競爭者采用了發表論文的方式來實現這個“護城河”。但我有一個疑問:為什么不通過申請專利的方式來實現這個“護城河”呢——你要用我的技術可以,但得給我交專利費。這是不是一種更好的保護自己的創新的方式呢?
對於這個問題,其實在提問的博客剛發布不久,我就已經和老師在評論區討論過了,當時討論的截圖如下:
經過討論,我最終得出的觀點是,雖然申請專利可能用處不大,但這也是保護自己技術的一種手段,我仍然認為申請專利是有必要的,畢竟能多一個證明的手段總不是件壞事。
2、新的問題
(1)有關前端和后端對接的問題
前端和后端對接的問題是一個相當費時費力的問題,我們組在Alpha階段也因為這個問題而耗費了大量時間,直接導致了我們Alpha版本推遲了近一周才發布。
一開始,我們認為只要定好前端和后端交互的api和json格式,對接起來就能萬無一失了,但實際上並不是這樣。下面的這張圖雖然可能有些誇張,但多少能反應一些前后端對接的問題:

可以看到,前后端雖然規定了使用RESTful api進行交互,並且前后端的開發人員分別都做出了他們認為的自行車的“前端”和“后端”部分,但兩方對於前后端交接處顯然沒有商量好怎么做,導致最后做出這么一個有兩個座椅的自行車。這種問題在軟件開發的過程中是很常見的。
對於這種問題,我們小組采用的是開視頻會議的方式,相當於讓前端和后端人員“面對面”地溝通,盡量在視頻會議中就將前后端交接的細節問題解決好,最好是能直接成功地進行前后端交互。這是我們組只有6個開發人員時的解決方案。但是,在真正的項目開發中,一個項目組顯然不止這么多人,這樣多人面對面溝通的時候就會有困難,甚至一個后端人員可能都不知道該找哪個前端人員去商量前后端對接的問題。於是我就想提出這個問題:
在真正的軟件項目開發中,前后端對接具體是怎么做的呢?有沒有一個規范的流程去確保前后端連接的正確性?或者有沒有專門的組內幾個成員來負責對接這部分呢?
3、學到的知識點
(1)需求階段
進行NABCD的分析,盡可能全面地了解用戶的需求,最好能確定哪些需求最重要,是用戶的痛點,接下來就以這個需求為核心功能進行計划。
(2)設計階段
設計主要分功能設計和規格設計。前者是給用戶看的,即讓用戶了解產品的頁面原型大致是什么樣的、都能實現哪些功能;后者是給開發人員看的,目的是讓開發者明確需要實現哪些接口以及實現的整體邏輯。設計階段的設想可能很豐富,但要注意哪些是核心功能,這些功能在計划中應該盡快實現,最理想的情況是先設計出一個最小可用版本就發布。
(3)實現階段
每天都要進行Scrum Meeting,了解各個組員的開發進度。作為PM,還需要把控項目的整體進度,為組員分配任務以及了解組員開發過程中遇到的困難,想辦法及時給予幫助,以保證項目能如期交付。作為開發者,要嚴格按照技術規格說明書開發,並保證自己的代碼符合代碼規范。此外,要善用GitHub或是Gitee上的issue和pull request,及時記錄自己的進度並遷入代碼。
(4)測試階段
進行單元測試,以快速定位可能出現bug的地方。每添加一個功能或是修復一個bug,最好進行回歸測試,以保證其他功能未受影響,仍可正常使用。如果是訪問量持續較高的網站,還要進行壓力測試,確保高訪問量的時候網站不會崩潰。
(5)發布階段
要針對在計划階段的目標用戶進行推廣和發布,發布時一定要重點宣傳項目的核心功能、項目是如何解決目標用戶的痛點問題的。此外,還要注意給用戶方便快捷的反饋途徑,以更好地改進項目。
(6)維護階段
及時與用戶溝通,根據收集上來的用戶反饋進行維護和改進。如果有很大的更新,必要時可以重新發布新版本,或是在網頁中以通知的形式及時告知用戶更新內容。
4、理解和心得
(1)個人項目
個人項目中,我初步學會了使用GitHub進行個人代碼倉庫的管理,以及如何對自己的項目進行簡單的單元測試。但是,由於是自己根據自己思路進行的測試,測試樣例的覆蓋范圍和強度也有限,這導致了我的附加題還是出現了bug,而這個bug甚至是在結對編程的過程中才由我的同伴發現。這也反映了一個人編程時容易犯的錯誤,即思路比較片面,更容易出現bug。
(2)結對項目
結對項目中,我基本沿用了個人項目中的代碼,並在此基礎上進行了功能的增加。由於是我自己的代碼,我的結對編程伙伴可能對代碼並不熟悉,因此一開始我們采用視頻會議的方式,由我為他講解我的代碼思路,之前提到的個人項目中的bug也是在這個過程中發現的。
我認為,結對編程最大的好處就在於能讓一個人在打代碼的同時另一個人可以進行代碼審查,這樣在編程過程中就可能會發現並修復很多bug,很大程度上減少了出錯的可能。實際上,在團隊項目期間,我們小組也將這樣結對編程的優點融合了進去,采取了一種“多人結對編程”的方式,取得了不錯的效果。當然,結對編程也有其局限性,最明顯的就是它需要兩個人約好了時間,並且在這段時間內都全神貫注地投入到代碼中,這點有時候是比較難實現的,畢竟我們除了軟工這門課程之外,還有很多其他課程也很耗費時間,兩個人結對編程的時間也比較難約好。
(3)團隊項目
關於團隊項目的心得,我印象最深的就是我們團隊自創的“多人結對編程”的開發方式了。具體來說,就是使用騰訊會議+共享屏幕的方式,一個人打代碼的同時,其他幾個相關的人同時進行代碼檢查。例如,一個前端同學如果編程過程中遇到困難,可以叫上另外幾個前端人員和一個后端人員,來一起“多人結對編程”,這樣前端同學可以為其指導前端的語法怎么寫、組件如何調用,而后端的同學可以解決在前后端交互json格式上的一些問題,如果進展順利,代碼完成之后還可以直接部署在自己的服務器上,前后端同學一起測試,加快了debug的效率。
這也再次印證了軟件工程是一門需要實踐的學科。我們的“多人結對編程”就是在實踐中摸索出來的一種適合我們組員的編程方式,其實軟件工程的理論中,可能並沒有規定得那么具體每個人要如何編程,很多東西都需要我們親身去實踐、親身去嘗試。書上說的方法可能只是前人的經驗中效果還不錯的方法,但不一定是最適合的方法,只有經過實踐證明最有效的方法才是最適合一個團隊的編程方法。
最后,我真的很高興能和團隊一起做出一個如此受歡迎的項目。雖然在開發的過程中遇到了不少困難,也有過不少熬夜的經歷,但最后看到注冊人數不斷增長的時候的欣喜真的是無可比擬的。有很多同學都反饋說我們的項目很實用,會一直用下去,我們組員自己也一直在用我們的DDL Killer,尤其是現在這個大作業特別多的時期,它能夠幫助我整理各科作業的ddl,並幫助我規划好自己的時間。
我們團隊開發軟件的初衷就是做出一個像樣的、能流傳的、實用的軟件,現在看來這個初衷是實現了。