女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【RT-Thread】show-me-bad-code

嵌入式物聯(lián)網(wǎng)開發(fā) ? 來源:嵌入式物聯(lián)網(wǎng)開發(fā) ? 作者:嵌入式物聯(lián)網(wǎng)開發(fā) ? 2022-07-24 16:36 ? 次閱讀

1. 題外話

在本活動(dòng)開始之前,非常榮幸地收到RRT小師弟的邀請, 看能否幫忙想想1024程序員節(jié)的論壇活動(dòng)好點(diǎn)子,在此非常感謝對我的信任。 想起早年在瀏覽一些博文的時(shí)候,對國外代碼社區(qū)舉辦的"爛代碼比賽"印象深刻, 看到那些牛人提交的"眼花繚亂的bad-but-work-well的代碼,簡直是佩服得五體投地。 自然我們大部分的程序員還很難提供出這么的代碼, 所以基于這個(gè)原則,結(jié)合我們的實(shí)際情況, 修改了下比賽規(guī)則,重在娛樂參與,旨在代碼提升。

更多關(guān)于此次show-me-bad-code活動(dòng)的介紹,請點(diǎn)擊這里。

2. 我來提供一段代碼

2.1 代碼背景

這段代碼的原型來自于早幾年在一家POS行業(yè)內(nèi)頭部企業(yè)供職時(shí)的真實(shí)案例代碼,基于這套代碼也是過了各種POS機(jī)的行業(yè)認(rèn)證, 經(jīng)過10多年的沉淀,基于該模板代碼移植/改造而來的應(yīng)用程序,罐裝的POS機(jī)累計(jì)裝機(jī)量應(yīng)該在KW級別,可謂就是傳說中妥妥的【祖?zhèn)鞔a】。

早期代碼的運(yùn)行環(huán)境是嵌入式Linux系統(tǒng),總內(nèi)存高達(dá)128MB,還是非常富余的;后面才慢慢切為RTOS系統(tǒng),內(nèi)存也銳減到64MB,但即便這樣,給到應(yīng)用程序的內(nèi)存也是非常充足的。

2.2 代碼功能

這段代碼的主要功能就是在POS機(jī)觸發(fā)交易時(shí)的界面(帶LCD顯示)下,能夠自動(dòng)識(shí)別出當(dāng)前要使用的各種交易方式,其中包括:

除這些功能外,因?yàn)镻OS機(jī)交易是需要保存最近N筆交易記錄的,所以這個(gè)處理交易的流程中,還得維護(hù)交易記錄的保存。而代碼中用于保存交易記錄的結(jié)構(gòu)體也是非常非常非常的龐大,大到一個(gè)結(jié)構(gòu)體就占用接近2KB,這是非常恐怖的。

2.3 代碼片段

為了僅說明情況,而不透露具體的技術(shù)細(xì)節(jié),這里我僅提供偽代碼,注意代碼里的注釋,是我為了輔助介紹而自己添加的,原來的代碼中,注釋比這少得可憐。

  1. /**
  2. * 保存交易記錄的結(jié)構(gòu)體定義
  3. */
  4. typedef struct _transaction_log_t {
  5. char time_stamp[32];
  6. uint8_t trans_type;
  7. uint8_t trans_no;
  8. /* 各式各樣的數(shù)據(jù)定義長達(dá)20-30個(gè)變量 */
  9. uint8_t data1[64];
  10. ...
  11. uint8_t datan[128];
  12. } transaction_log_t;
  13. /* 全局的交易log變量,被各個(gè)處理流程的文件引用 */
  14. transaction_log g_log_info;
  15. /**
  16. * 支持的交易方式的掩碼
  17. */
  18. #define TRANSACTION_SWIPE_CARD 0x01
  19. #define TRANSACTION_INSERT_CARD 0x02
  20. #define TRANSACTION_TAP_CARD 0x04
  21. #define TRANSACTION_CODE_PAY 0x08
  22. /**
  23. * 處理交易的流程總?cè)肟?/code>
  24. */
  25. int all_transaction_process(int timeouts_ms, int transaction_flag)
  26. {
  27. int start_time, end_time;
  28. end_time = 0;
  29. start_time = get_local_time();
  30. /* 循環(huán)判斷需要支持的交易方式,直到觸發(fā)了某種交易或者超時(shí) */
  31. while (1) {
  32. if (transaction_flag & TRANSACTION_SWIPE_CARD) {
  33. /* 判斷刷卡:阻塞式的接口,帶超時(shí)時(shí)間 */
  34. ret = get_swipe_card(10);
  35. if (ret == ok) {
  36. /* 處理刷卡流程 */
  37. ...
  38. return 0;
  39. }
  40. } else if (transaction_flag & TRANSACTION_SWIPE_CARD) {
  41. /* 判斷插卡:阻塞式接口,帶超時(shí)時(shí)間 */
  42. ret = get_insert_card(10);
  43. if (ret == ok) {
  44. /* 處理插卡流程 */
  45. ...
  46. return 0;
  47. }
  48. } else if (transaction_flag & TRANSACTION_SWIPE_CARD) {
  49. /* 判斷揮卡:阻塞式接口,帶超時(shí)時(shí)間 */
  50. ret = get_tap_card(10);
  51. if (ret == ok) {
  52. /* 處理揮卡流程 */
  53. ...
  54. return 0;
  55. }
  56. } else if (transaction_flag & TRANSACTION_SWIPE_CARD) {
  57. /* 判斷條碼支付 */
  58. ret = get_code(10);
  59. if (ret == ok) {
  60. /* 處理?xiàng)l碼流程 */
  61. ...
  62. return 0;
  63. }
  64. }
  65. end_time = get_local_time();
  66. if (start_time + timeous_ms == end_time) {
  67. /* timeout */
  68. return -1;
  69. }
  70. /* 界面顯示倒計(jì)時(shí) */
  71. lcd_update_timetous();
  72. /* 循環(huán)延時(shí) */
  73. delay_ms(10);
  74. }
  75. }
  76. /**
  77. * main函數(shù)總?cè)肟?/code>
  78. */
  79. int main(int argc, const char *argv[])
  80. {
  81. /* 應(yīng)用初始化 */
  82. system_init();
  83. /* 處理備份及系統(tǒng)異常斷電引發(fā)的沖正交易 */
  84. handle_bakup();
  85. /* main loop */
  86. while (1) {
  87. /* 每10ms獲取下當(dāng)前有沒有按鍵觸發(fā)交易 */
  88. key = get_key_ms(10);
  89. if (key1 == key) {
  90. /* 有觸發(fā)交易需求 */
  91. ret = all_transaction_process(60*1000, );
  92. } else if (key2 == key) {
  93. /* 其他菜單操作 */
  94. ...
  95. } else {
  96. /* 超時(shí)或未知按鍵輸入 */
  97. ...
  98. }
  99. /* 刷新顯示在LCD上的時(shí)間 */
  100. update _time_dispaly();
  101. }
  102. return 0;
  103. }

2.4 "爛"的理由

這里說上面的代碼"爛"并不是說它工作得不行,相反,它的確工作得可以,從裝機(jī)量和各種行業(yè)認(rèn)證就可以看得出來,還是扛得住市場對它的考驗(yàn)。這里提出它"爛"的原因,主要考慮是從代碼設(shè)計(jì)和代碼維護(hù)的角度來看。

3. 改善既有代碼的設(shè)計(jì)

3.1 改善代碼前的思考

大家都戲稱祖?zhèn)鞔a,請勿隨意改動(dòng),但我覺得真正優(yōu)秀的代碼,是慢慢被迭代,被重構(gòu)而來的,否則的代碼就會(huì)被一步步地堆砌起來,直到有一天,沒人能夠再修改維護(hù)了,那一刻就如同一棟大廈轟然倒塌,這是非常糟糕的。

正是基于這些的考慮,當(dāng)時(shí)我也是很大膽地向主管提出,我們應(yīng)該從小面積開始做代碼重構(gòu),逐漸改善一些有缺陷的代碼設(shè)計(jì)。

比較遺憾的是,主管是相對保守的,沒有接受后面大面積重構(gòu)的實(shí)施,主要還是擔(dān)心期間的風(fēng)險(xiǎn),影響外面的程序升級。從商業(yè)的角度上,我是支持他的;但是,從代碼的角度,我還是堅(jiān)持我的觀點(diǎn);當(dāng)然這并不影響我們的共事。

3.2 我要如何改善這些代碼

先說下,主管答允我的小面積重構(gòu)部分,我是怎么做的!

代碼維護(hù)上:全局變量全盤引用,亂串于各個(gè)文件中,可讀性非常差

針對這一點(diǎn),我重新整理了部分的C代碼規(guī)劃,明確要求非十分必要的設(shè)計(jì),不允許全局變量在多個(gè)C文件中修改傳遞,盡量控制在一個(gè)C文件,同時(shí)關(guān)鍵的數(shù)據(jù)都封裝成get/set接口,減少通篇修改數(shù)據(jù)的可能性。

在code review環(huán)境,著重對此類代碼做重點(diǎn)審查,一經(jīng)發(fā)現(xiàn),務(wù)必打回重新修改提交。

代碼設(shè)計(jì)上:數(shù)據(jù)結(jié)構(gòu)沒有規(guī)劃設(shè)計(jì),導(dǎo)致結(jié)構(gòu)體定義太復(fù)雜,太過龐然大物,冗余空間浪費(fèi)大

針對這一點(diǎn),我的方法就是重新梳理,我們需要用到的必備數(shù)據(jù),把所有非必須的數(shù)據(jù)全部刪除,同時(shí)一些數(shù)據(jù)buffer的長度,再嚴(yán)格評估其真正的內(nèi)存需求空間,而不是一上來就定義32字節(jié)/64字節(jié)/128字節(jié)。

還有一個(gè)方面,就是盡量考慮字節(jié)對齊的問題,定義結(jié)構(gòu)體的時(shí)候,多考慮考慮。

最后的實(shí)踐方案,省下了一半的空間。

再說下,當(dāng)時(shí)我提出的實(shí)施方案,但是被按下的重構(gòu)方案!

代碼設(shè)計(jì)上:所有交易流程的判斷處理,太過于死板,一個(gè)if-else判斷到底,耦合嚴(yán)重,可擴(kuò)展性非常差

代碼設(shè)計(jì)上:LCD顯示與核心業(yè)務(wù)流程跳轉(zhuǎn)參雜在一起,沒有解耦,往往改了業(yè)務(wù)功能的同時(shí)還要改UI實(shí)現(xiàn)

代碼性能上:流程處理中,大量使用帶超時(shí)時(shí)間的阻塞式函數(shù),導(dǎo)致整個(gè)流程響應(yīng)的時(shí)效性不是很理想

這三點(diǎn),我認(rèn)為都應(yīng)該通過改善整體的代碼架構(gòu)來提升,下面簡單說說的重構(gòu)思路。

為了解決此類有業(yè)務(wù)處理流程,又有UI輸入和UI顯示的處理場景了,有一個(gè)比較成熟的軟件模型,叫MVC模型。

MVC 模式代表 Model-View-Controller(模型-視圖-控制器) 模式。

  • Model(模型) - 模型代表核心業(yè)務(wù)處理模塊。它也可以帶有邏輯,在數(shù)據(jù)變化時(shí)更新控制器。
  • View(視圖) - 視圖代表模型包含的數(shù)據(jù)的可視化,即UI部分。
  • Controller(控制器) - 控制器作用于模型和視圖上。它控制數(shù)據(jù)流向模型對象,并在數(shù)據(jù)變化時(shí)更新視圖。它使視圖與模型分離開。
img

根據(jù)這個(gè)理論模型,應(yīng)用到我的工程上就是:

Controller:控制器,對應(yīng)在這里就是,各式各樣的事件監(jiān)聽器,把各種用戶可能輸入的方式抽象成一個(gè)個(gè)事件,而每個(gè)事件都有對應(yīng)的監(jiān)聽器,當(dāng)監(jiān)聽器識(shí)別到了對應(yīng)事件的發(fā)生,立馬觸發(fā)事件給到模型層。

Model: 模型,這應(yīng)該整個(gè)設(shè)計(jì)中代碼最重的部分,主要是各個(gè)處理事件的處理,獨(dú)立抽象成一個(gè)個(gè)模型,這些模型層互不干擾,也易于擴(kuò)展,有新的事件需要處理就重新定義個(gè)模型即可。

View:視圖,就是最簡單的UI界面,它負(fù)責(zé)對Model提供的數(shù)據(jù)最UI界面的更新,比如刷新時(shí)間,比如顯示倒計(jì)時(shí),比如提示用卡信息等等。

它的整一個(gè)示意圖如下所示:

image-20211025153225831

應(yīng)用MVC框架的最大好處就是把M和V分離開來,數(shù)據(jù)和視圖解耦,使得數(shù)據(jù)易于處理并存儲(chǔ),同時(shí)也易于擴(kuò)展,這里的擴(kuò)展包括視圖擴(kuò)展和模型擴(kuò)展,從一變N變得更加容易。

另外很重要的一點(diǎn),在性能上,處理的實(shí)時(shí)性大大提升了,而不是簡單的阻塞、延時(shí)這種粗暴的方法,取之而來的各種異步監(jiān)聽,快速響應(yīng),這一點(diǎn)我覺得在涉及到UI的應(yīng)用場景下,都是應(yīng)該要著重考慮的部分。

4. 更多思考

代碼是無止境的,沒有最好的代碼實(shí)現(xiàn),但是往往有更好的代碼實(shí)現(xiàn)。

很多奇奇怪怪的BUG,在代碼設(shè)計(jì)和代碼編寫階段其實(shí)已經(jīng)埋下了隱患,只不過短時(shí)間沒有暴露出來而已。

這也就要求我們這些代碼工作者,在敲代碼之前,多想想設(shè)計(jì)思路,盡量把你的思路,你的流程通過圖表的形式表達(dá)出來,

再不濟(jì),也應(yīng)該要形成文檔,以便于隨時(shí)可以復(fù)盤你的代碼實(shí)現(xiàn)是否偏離了你原本的設(shè)計(jì)。

毫不夸張地說,一個(gè)在設(shè)計(jì)階段就有缺陷的代碼架構(gòu),再怎么修飾也將于事無補(bǔ)。

這也是我目前轉(zhuǎn)入軟件架構(gòu)師崗位,得出的最直接的心得。

最后愿這個(gè)世界的程序越來越強(qiáng),BUG越來越少;

不過,這樣的話,那我們豈不是要失業(yè)了?

代碼性能上:流程處理中,大量使用帶超時(shí)時(shí)間的阻塞式函數(shù),導(dǎo)致整個(gè)流程響應(yīng)的時(shí)效性不是很理想

代碼設(shè)計(jì)上:LCD顯示與核心業(yè)務(wù)流程跳轉(zhuǎn)參雜在一起,沒有解耦,往往改了業(yè)務(wù)功能的同時(shí)還要改UI實(shí)現(xiàn)

代碼設(shè)計(jì)上:所有交易流程的判斷處理,太過于死板,一個(gè)if-else判斷到底,耦合嚴(yán)重,可擴(kuò)展性非常差

代碼設(shè)計(jì)上:數(shù)據(jù)結(jié)構(gòu)沒有規(guī)劃設(shè)計(jì),導(dǎo)致結(jié)構(gòu)體定義太復(fù)雜,太過龐然大物,冗余空間浪費(fèi)大

代碼維護(hù)上:全局變量全盤引用,亂串于各個(gè)文件中,可讀性非常差

是否在規(guī)定的時(shí)間內(nèi)(一般60S)沒有任何的交易發(fā)生,導(dǎo)致超時(shí)?

是否按下了【取消鍵】,用戶主動(dòng)退出了交易?

是否掃描到了微信/支付寶這類的支付條碼?(條碼支付與標(biāo)準(zhǔn)銀行卡交易是完全不一樣的流程)

是否使用了IC卡做非接觸交易(俗稱:揮卡)?(揮卡交易,走銀聯(lián)的IC卡快速交易,行內(nèi)稱qPBOC流程)

是否插入了IC卡?(插入IC卡,走銀聯(lián)的IC卡交易流程,行內(nèi)稱PBOC流程)

是否刷了磁條卡?(刷了磁條卡,走刷磁條卡的交易流程)

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • RTOS
    +關(guān)注

    關(guān)注

    24

    文章

    840

    瀏覽量

    120737
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4886

    瀏覽量

    70234
  • RT-Thread
    +關(guān)注

    關(guān)注

    32

    文章

    1368

    瀏覽量

    41497
收藏 人收藏

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    RT-Thread記錄(二、RT-Thread內(nèi)核啟動(dòng)流程)

    在前面我們RT-Thread Studio工程基礎(chǔ)之上講一講RT-Thread內(nèi)核啟動(dòng)流程.
    的頭像 發(fā)表于 06-20 00:30 ?5466次閱讀
    <b class='flag-5'>RT-Thread</b>記錄(二、<b class='flag-5'>RT-Thread</b>內(nèi)核啟動(dòng)流程)

    使用RT-Thread Master+QEMU模擬器進(jìn)行RT-Thread原型快速開發(fā)

    前段時(shí)間分別在Win和Mac M1/M2 Silicon硬件環(huán)境下折騰了VS Code + RT-Thread的編譯問題。
    的頭像 發(fā)表于 09-27 14:50 ?3383次閱讀
    使用<b class='flag-5'>RT-Thread</b> Master+QEMU模擬器進(jìn)行<b class='flag-5'>RT-Thread</b>原型快速開發(fā)

    RT-Thread編程指南

    RT-Thread編程指南——RT-Thread開發(fā)組(2015-03-31)。RT-Thread做為國內(nèi)有較大影響力的開源實(shí)時(shí)操作系統(tǒng),本文是RT-Thread實(shí)時(shí)操作系統(tǒng)的編程指南
    發(fā)表于 11-26 16:06 ?0次下載

    RT-Thread用戶手冊

    RT-Thread用戶手冊——本書是RT-Thread的編程手冊,用于指導(dǎo)在RT-Thread實(shí)時(shí)操作系統(tǒng)環(huán)境下如何進(jìn)行編 程。
    發(fā)表于 11-26 16:16 ?0次下載

    RT-Thread全球技術(shù)大會(huì):螢石研發(fā)團(tuán)隊(duì)使用RT-Thread的技術(shù)挑戰(zhàn)

    RT-Thread全球技術(shù)大會(huì):研發(fā)團(tuán)隊(duì)使用RT-Thread的技術(shù)挑戰(zhàn) ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 11:36 ?1469次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):螢石研發(fā)團(tuán)隊(duì)使用<b class='flag-5'>RT-Thread</b>的技術(shù)挑戰(zhàn)

    RT-Thread全球技術(shù)大會(huì):Kconfig在RT-Thread中的工作機(jī)制

    RT-Thread全球技術(shù)大會(huì):Kconfig在RT-Thread中的工作機(jī)制 ? ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 14:49 ?1749次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):Kconfig在<b class='flag-5'>RT-Thread</b>中的工作機(jī)制

    RT-Thread全球技術(shù)大會(huì):在RT-Thread上編寫測試用例

    RT-Thread全球技術(shù)大會(huì):在RT-Thread上編寫測試用例 ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:28 ?1671次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):在<b class='flag-5'>RT-Thread</b>上編寫測試用例

    RT-Thread全球技術(shù)大會(huì):RT-Thread測試用例集合案例

    RT-Thread全球技術(shù)大會(huì):RT-Thread測試用例集合案例 ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:34 ?2295次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):<b class='flag-5'>RT-Thread</b>測試用例集合案例

    RT-Thread學(xué)習(xí)筆記 RT-Thread的架構(gòu)概述

    RT-Thread 簡介 作為一名 RTOS 的初學(xué)者,也許你對 RT-Thread 還比較陌生。然而,隨著你的深入接觸,你會(huì)逐漸發(fā)現(xiàn) RT-Thread 的魅力和它相較于其他同類型 RTOS
    的頭像 發(fā)表于 07-09 11:27 ?4895次閱讀
    <b class='flag-5'>RT-Thread</b>學(xué)習(xí)筆記 <b class='flag-5'>RT-Thread</b>的架構(gòu)概述

    RT-Thread文檔_RT-Thread 簡介

    RT-Thread文檔_RT-Thread 簡介
    發(fā)表于 02-22 18:22 ?5次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 簡介

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南
    發(fā)表于 02-22 18:23 ?10次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread SMP 介紹與移植

    RT-Thread文檔_RT-Thread SMP 介紹與移植
    發(fā)表于 02-22 18:31 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> SMP 介紹與移植

    基于RT-Thread Studio學(xué)習(xí)

    前期準(zhǔn)備:從官網(wǎng)下載 RT-Thread Studio,弄個(gè)賬號(hào)登陸,開啟rt-thread學(xué)習(xí)之旅。
    的頭像 發(fā)表于 05-15 11:00 ?4987次閱讀
    基于<b class='flag-5'>RT-Thread</b> Studio學(xué)習(xí)

    RT-Thread中的Github Actions

    (.github/workflows/static_code_analysis.yml) 下面分別講解這五個(gè)Github Action。 RT-Thread BSP build check 總的來說,這個(gè)
    的頭像 發(fā)表于 06-01 03:10 ?998次閱讀
    <b class='flag-5'>RT-Thread</b>中的Github Actions

    RT-Thread v5.0.2 發(fā)布

    RT-Thread 代碼倉庫地址: ●? https://github.com/RT-Thread/rt-thread RT-Thread 5.0.2 版本發(fā)布日志詳情: ●? htt
    的頭像 發(fā)表于 10-10 18:45 ?1819次閱讀
    <b class='flag-5'>RT-Thread</b> v5.0.2 發(fā)布