整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          將代碼注釋轉(zhuǎn)換為過(guò)程規(guī)范

          將代碼注釋轉(zhuǎn)換為過(guò)程規(guī)范

          用:Arianna Blasi, Alberto Goffi, Konstantin Kuznetsov, Alessandra Gorla, Michael D. Ernst, Mauro Pezzè, and Sergio Delgado Castellanos. 2018. Translating Code Comments to Procedure Specifications. In Proceedings of 27th ACM SIG- SOFT International Symposium on Software Testing and Analysis (ISSTA’18). ACM, New York, NY, USA, 12 pages. https://doi.org/10.1145/3213846.3213872.

          摘要

          過(guò)程規(guī)范在許多軟件開(kāi)發(fā)任務(wù)中很有用。例如,在自動(dòng)生成測(cè)試用例的過(guò)程中,它們可以指導(dǎo)測(cè)試,充當(dāng)能夠發(fā)現(xiàn)錯(cuò)誤并識(shí)別非法輸入的測(cè)試先知。盡管實(shí)際上很少有正式的規(guī)范,但是對(duì)于開(kāi)發(fā)人員來(lái)說(shuō),使用半結(jié)構(gòu)化注釋來(lái)記錄其代碼是標(biāo)準(zhǔn)做法。這些注釋通過(guò)預(yù)定義標(biāo)簽和自然語(yǔ)言的組合來(lái)表達(dá)過(guò)程規(guī)范。本文介紹了 Jdoctor,該方法結(jié)合了模式,詞法和語(yǔ)義匹配,將 Javadoc 注釋轉(zhuǎn)換為以 Java 表達(dá)式編寫的可執(zhí)行過(guò)程規(guī)范。在實(shí)證評(píng)估中,將 Javadoc 轉(zhuǎn)換為過(guò)程規(guī)范時(shí),Jdoctor 的精度達(dá)到 92%,召回率達(dá)到 83%。

          我們還將 Jdoctor 衍生的規(guī)范提供給自動(dòng)測(cè)試用例生成工具 Randoop。規(guī)范使 Randoop 能夠生成測(cè)試案例,從而減少誤報(bào)并揭示更多缺陷。

          1 簡(jiǎn)介

          程序規(guī)范表達(dá)了預(yù)期的程序行為,因此可以啟用或自動(dòng)化許多軟件工程任務(wù)。在軟件測(cè)試中,它用作確定哪些輸入合法和哪些輸出正確的預(yù)言 [4, 17, 31, 37]。在調(diào)試中,它標(biāo)識(shí)錯(cuò)誤的語(yǔ)句 [29, 54]。在代碼合成中,這是合成器致力于的目標(biāo) [28, 47]。在重構(gòu)中,它確保轉(zhuǎn)換是一致的 [23]。在形式驗(yàn)證中,它區(qū)分正確和錯(cuò)誤的實(shí)現(xiàn) [53]。在運(yùn)行時(shí)監(jiān)視中,它可以識(shí)別異常行為 [15]。自動(dòng)化(部分)任務(wù)需要工具可以操縱的機(jī)器可讀格式。正式的規(guī)范很好地達(dá)到了這個(gè)目的。但是,很少有正式的規(guī)范,因?yàn)榫帉懸?guī)范不是常見(jiàn)的軟件開(kāi)發(fā)實(shí)踐。

          ? 相比之下,非正式規(guī)范很容易以自然語(yǔ)言編寫的半結(jié)構(gòu)化和非結(jié)構(gòu)化文檔的形式提供。程序員在過(guò)程文檔中指定前提條件、后置條件和特殊行為是標(biāo)準(zhǔn)做法。 Javadoc 標(biāo)記語(yǔ)言和工具于 1995 年在 Java 的第一個(gè)版本中出現(xiàn),而類似但跨語(yǔ)言的工具 Doxygen 在 2 年后出現(xiàn)了。 Java IDE 會(huì)自動(dòng)插入 Javadoc 注釋的模板。最重要的是,程序員已經(jīng)習(xí)慣于編寫這些注釋。結(jié)果,大量代碼包含了非正式的 Javadoc 規(guī)范。但是,軟件工程工具很少使用這些非正式規(guī)范。

          ? 本文介紹了 Jdoctor,它是一種從程序員已經(jīng)創(chuàng)建的工件(即 Javadoc 代碼注釋)自動(dòng)構(gòu)建可執(zhí)行過(guò)程規(guī)范的技術(shù),而無(wú)需程序員更改開(kāi)發(fā)實(shí)踐或做額外的工作。可執(zhí)行規(guī)范是可以執(zhí)行的規(guī)范,例如,因?yàn)樗怯镁幊陶Z(yǔ)言而不是其他某種邏輯編寫的。它也需要在過(guò)程上表達(dá),而不是(例如)聲明性地要求某些值的存在而不指示如何計(jì)算它。由 Jdoctor 生成的過(guò)程規(guī)范可用于多種軟件工程任務(wù)中,例如自動(dòng)生成測(cè)試用例,如本文所示。

          1.1 應(yīng)用:測(cè)試用例生成

          自動(dòng)生成測(cè)試用例可以降低開(kāi)發(fā)成本和軟件故障的社會(huì)成本 [5, 27, 44]。要自動(dòng)生成測(cè)試用例,測(cè)試生成器必須生成一個(gè)輸入,該輸入使被測(cè)程序執(zhí)行某些操作,并生成一個(gè) oracle 以確定程序是否正常運(yùn)行。

          ? 創(chuàng)建準(zhǔn)確的測(cè)試 Oracle 仍然是一個(gè)未解決的問(wèn)題。正如我們現(xiàn)在所解釋的,這將導(dǎo)致測(cè)試生成器同時(shí)遭受錯(cuò)誤警報(bào)(當(dāng)被測(cè)程序正確時(shí)測(cè)試失敗)和錯(cuò)過(guò)警報(bào)(當(dāng)被測(cè)程序有錯(cuò)誤時(shí)測(cè)試通過(guò))。例如,假設(shè)自動(dòng)生成的測(cè)試中的方法調(diào)用引發(fā)了異常。拋出此異常并不一定意味著所測(cè)試的方法有錯(cuò)誤。存在以下可能性:

          (1)引發(fā)的異常實(shí)際上揭示了實(shí)現(xiàn)缺陷。一個(gè)示例是在主題程序中觸發(fā)斷言,或者以其他方式無(wú)法完成所請(qǐng)求的操作。

          (2)拋出異常是預(yù)期的、期望的行為。一個(gè)示例是在不可變對(duì)象上調(diào)用變量時(shí)發(fā)生的IllegalOperationException

          .注釋標(biāo)記(<!--…-->)

          語(yǔ)法: <!--注釋內(nèi)容-->

          2.文件標(biāo)記(<html>…</html>)

          語(yǔ)法: <html>…</html>

          說(shuō)明:<html>這對(duì)標(biāo)記是HTML文件的標(biāo)記。<html>處于文件的最前面,表示HTML文件的開(kāi)始。即瀏覽器從<html>標(biāo)記開(kāi)始解釋,直到遇到</html>標(biāo)記為止。

          3.文件頭標(biāo)記(<head>…</head>)

          語(yǔ)法: <head>…</head>

          說(shuō)明:

          ①由head這組標(biāo)記定義的元素中,并不放置網(wǎng)頁(yè)的任何內(nèi)容,是放置關(guān)于這份HTML文件的信息。就是說(shuō),它并不屬于HTML文件的主體,它包含文件的標(biāo)題、編碼方式和URL等。這些信息大部分用于提供索引、辨認(rèn)或其他應(yīng)用。

          ②這對(duì)標(biāo)記在HTML文件中并不是必需的。如果某個(gè)HTML文件并不需要提供相關(guān)信息,則可省略<head>標(biāo)記。

          4.文件標(biāo)題標(biāo)記(<title>…</title>)

          語(yǔ)法: <title>文件標(biāo)題文字</title>

          說(shuō)明:此標(biāo)記用于設(shè)定HTML文件的標(biāo)題名稱,它將顯示在瀏覽器的標(biāo)題欄中。

          注意:<title>標(biāo)記用于<head>標(biāo)記中。但如果HTML文件中沒(méi)有使用<head>標(biāo)記,則<title>標(biāo)記仍然起作用。

          5.文件主體標(biāo)記(<body>…</body>)

          語(yǔ)法: <body>…</body>

          說(shuō)明:

          ①由<body>標(biāo)記所建立的元素是HTML文件的內(nèi)容主體,也是HTML文件的重點(diǎn)所在。HTML文件中要顯示在網(wǎng)頁(yè)上的所有內(nèi)容,也都放置在這個(gè)元素中。

          ②<body>具有一些特殊的屬性,可以設(shè)定背景及字符顏色等。

          【注釋】從技術(shù)上來(lái)說(shuō)沒(méi)有對(duì)錯(cuò),理論上,你想怎么寫就怎么寫,你愛(ài)怎么寫就怎么寫!

          但它確實(shí)也會(huì)對(duì)我們?cè)斐捎绊懀绕涫窃诙嗳藚f(xié)同開(kāi)發(fā)的系統(tǒng)中。雜亂的注釋也會(huì)讓你或你的隊(duì)友頭疼~

          所以,我們需要規(guī)范一下注釋。那什么才是好的注釋呢?我們先來(lái)看看什么是不好的注釋!

          注釋冗余

          我們往往會(huì)寫一段注釋來(lái)說(shuō)明“這是什么”。比如:

          // Find all the users
          let users=userHelper.findAll();
          
          // Add score to each user
          users.forEach((user)=> {
          	user.score++;
          }
          						
          // Return the users
          return users;
          

          但是這段代碼本身的意思就很清楚了,再附上注釋就有點(diǎn)多余了。

          所以我們應(yīng)該將其剔除。

          let users=userHelper.findAll();
          
          users.forEach((user)=> {
          	user.score++;
          }
          						
          return users;
          

          那么,這段代碼是不是就方便閱讀了呢?其實(shí),咱們還能更進(jìn)一步:

          let users=userHelper.findAll();
          userHelper.incrementScoreForAll(users);						
          return users;
          

          這樣你感覺(jué)如何?相比于最開(kāi)始的那段代碼,這段是不是就看得舒舒服服

          所以,可讀的代碼比可讀的注釋更重要。優(yōu)先考慮讓你的代碼說(shuō)話,實(shí)在不行,再附上簡(jiǎn)短、清晰的注釋。

          注釋未更新

          // Find all users
          let users=userHelper.findBanned();
          
          // Give each user 100 extra score
          users.forEach((user)=> {
          	user.score=0;
          }
          
          return users;
          

          我們有時(shí)候會(huì)發(fā)現(xiàn)注釋和代碼并不匹配,比如這里為用戶設(shè)置分?jǐn)?shù)的操作。代碼中是 0 分,注釋卻是 100 分。

          導(dǎo)致出現(xiàn)這種情況有多種可能:

          1. 我們總是在從其它地方復(fù)制代碼,有時(shí)也會(huì)一并復(fù)制注釋,然后在為己所用的過(guò)程中,修改了代碼卻沒(méi)有修改對(duì)應(yīng)的注釋。
          2. 我們同時(shí)也在不斷的根據(jù)產(chǎn)品需求調(diào)整代碼(比如此處設(shè)置分值),修改代碼也可能會(huì)忘記修改之前寫的注釋。

          怎么辦?讓我們來(lái)看看優(yōu)解:

          // userHelper.js
          function updateScoreForUsers(score, users) {
            users.forEach((user)=> {
          	  user.score +=score;
            }
          }
          
          // Code 1: punish banned users
          let users=userHelper.findBanned();
          userHelper.updateScoreForUsers(users, -100);
          return users;
          
          // Code 2: give everybody 1 extra score
          let users=userHelper.findAll();
          userHelper.updateScoreForUsers(users, 1);
          return users;
          

          這樣寫將設(shè)置分?jǐn)?shù)的邏輯封裝成函數(shù)進(jìn)行了抽離,功能更強(qiáng)了,也更易于閱讀了。

          現(xiàn)在,我們可以在多種情況下重復(fù)調(diào)用它,且不必?fù)?dān)心注釋未及時(shí)更新的問(wèn)題了。

          注釋太長(zhǎng)

          請(qǐng)問(wèn)如果是這樣的注釋,你還有信心整個(gè)完整讀下來(lái)嗎?即使你是一個(gè)勇敢堅(jiān)強(qiáng)的技術(shù)人,讀下來(lái)也會(huì)消耗很多時(shí)間吧?這樣低效率的事肯定不是我們想要的。

          // userHelper.js
          /**
           * Mass updates the user score for the given a list of user
           * The score will be updated by the amount given in the parameter score
           * For example, if the parameter score is 5, the users will all receive 5 extra score
           * But if the score is negative, it can also be used. In that case, the score will be decreased by 5.
           * If you set score as 0, then this method will be useless as nothing will be updated.
           * If you set the score as a non number value, the function will not do anything and return false
           * just to ensure the score is not messed up after updating it with a non-number value
           * Try to avoid using non-number values in the score parameter as this should not be used like that
           * If you do however choose to use Infinity in the score argument, it will work, because Infinity is considered as a number in JavaScript
           * If you set the score to Infinity, all the users score will become Inifinity, because n + Infinity where n is a number, will always result in Infinity
           * Regarding the users, make sure this is an array! If it is not an array, we will not process the users score,
           * then our method will simply return false instead and stop processing
           * Also make sure the users array is a list of actual user objects, we do not check this, but make sure the object has all the required fields as expected
           * especially the score object is important in this case.
           * @returns {boolean} Returns true if successful, false if not processed.
           */
          function updateScoreForUsers(score, users) {
            if (isNaN(score) || typeof users !=='array') { return false; }
            
            users.forEach((user)=> {
          	  user.score +=score;
            }
                          
            return true;
          }
          

          所以,請(qǐng)確保你的注釋不要太長(zhǎng)。有那么多想說(shuō)的,可以寫文檔、可以寫文章,不要寫注釋~

          簡(jiǎn)單直接是最迷人的!

          注釋太短

          這是另一個(gè)極端的例子,但是它確實(shí)源自于現(xiàn)實(shí)的開(kāi)發(fā)項(xiàng)目中。

          // userHelper.js
          /**
           * Update score
           * @returns {boolean} result
           */
          function updateScoreForUsers(score, users) {
            if (isNaN(score) || typeof users !=='array') { return false; }
            
            users.forEach((user)=> {
          	  user.score +=score;
            }
                          
            return true;
          }
          

          此段代碼注釋只是說(shuō)明了返回值,但是更為關(guān)鍵的傳參并未作出釋義。顯得有些尷尬~

          如果你決定注釋,那就不要只寫一半。請(qǐng)盡量準(zhǔn)確、完整、干凈的將其寫出。從長(zhǎng)期來(lái)看,你一定會(huì)從中受益。

          好的注釋

          好的注釋就是告訴大家你為什么要進(jìn)行注釋!

          比如:

          // userHelper.js
          function updateScoreForUsers(score, users) {
            users.forEach((user)=> {
              user.score +=score;
              
              // VIPs are promised 500 extra score on top
              if (user.type=='VIP') {
                user.score +=500;
              }
            }
                          
            return true;
          }
          

          此例中我們可以明白 VIP 用戶是被產(chǎn)品要求多加 500 分值的。這樣其它開(kāi)發(fā)就不會(huì)對(duì)此產(chǎn)生疑惑。

          如果代碼由多個(gè)團(tuán)隊(duì)維護(hù),簡(jiǎn)單直接的小標(biāo)注就更為必要了!

          小結(jié)

          注釋在代碼中扮演很重要的角色。本瓜還記得大學(xué)老師說(shuō):注釋應(yīng)該占代碼的三分之一。

          我們都有不同的注釋習(xí)慣,但是也應(yīng)該有一個(gè)基本的指導(dǎo):

          1. 注釋應(yīng)當(dāng)簡(jiǎn)短、清晰,長(zhǎng)篇大論稍邊邊。
          2. 告訴大家你 “為什么” 寫這個(gè)注釋,而不是告訴大家這段代碼 “是什么”“是什么” 應(yīng)該交給代碼本身去解釋。這個(gè)最為關(guān)鍵!
          3. 保持你的注釋持久維護(hù),也就是記得及時(shí)更新和與代碼匹配。

          代碼可讀就是最好的注釋。

          我是掘金安東尼: 一名人氣前端技術(shù)博主(文章 100w+ 閱讀量)

          終身寫作者(INFP 寫作人格)

          堅(jiān)持與熱愛(ài)(簡(jiǎn)書打卡 1000 日)

          我能陪你一起度過(guò)漫長(zhǎng)技術(shù)歲月嗎(以夢(mèng)為馬)

          覺(jué)得不錯(cuò),給個(gè)三連吧(這是我最大的動(dòng)力 )


          主站蜘蛛池模板: 日本精品3d动漫一区二区| 精品国产免费一区二区三区香蕉| 精品国产一区二区三区四区| 无码人妻一区二区三区精品视频| 岛国无码av不卡一区二区| 国产日韩精品视频一区二区三区| 日韩精品无码一区二区视频 | 日本精品一区二区久久久| 亚洲AV乱码一区二区三区林ゆな| 日本精品一区二区三区四区| 亚洲AV一区二区三区四区| 骚片AV蜜桃精品一区| 国产亚洲综合一区柠檬导航| 精品视频一区二区三区四区五区| 国产乱人伦精品一区二区在线观看| 任你躁国语自产一区在| 亚洲国产老鸭窝一区二区三区| 日本一区视频在线播放| 国产伦精品一区二区三区免.费| 国产精品一区二区久久精品涩爱| 精品一区二区三区在线成人 | 中文字幕在线精品视频入口一区| 亚洲AⅤ无码一区二区三区在线 | 亚洲一区二区在线免费观看| 精品aⅴ一区二区三区| 最美女人体内射精一区二区| 免费萌白酱国产一区二区三区| 大屁股熟女一区二区三区| 国产综合精品一区二区三区| 无码精品一区二区三区在线| 日韩精品中文字幕无码一区| 国产91久久精品一区二区| 亚洲国产韩国一区二区| 亚洲综合激情五月色一区| 国产麻豆剧果冻传媒一区| 国产免费私拍一区二区三区| 亚洲免费一区二区| 日韩视频一区二区三区| 无码精品一区二区三区免费视频| 成人日韩熟女高清视频一区| 国精品无码一区二区三区左线|