<返回更多

微任务编程

2020-07-31    
加入收藏
微任务编程

 

引用:Latoza T D , Di Lecce A , Ricci F , et al. Microtask Programming[J]. IEEE Transactions on Software Engineering, 2018:1-1.

摘要:

诸如开源软件开发之类的传统众包形式利用人群贡献来使软件创建民主化。但是,潜在的贡献者必须首先克服加入障碍,迫使那些随心所欲的贡献者花上几天或几周的时间参加培训,从而减少该类人员的参与。为了更有效地利用人群的潜在贡献,我们提出了一种编程方法,其中的工作完全通过微任务来完成,为贡献者提供简短,独立的任务,例如实现功能的一部分或更新调用了某一函数的功能点来匹配对该函数所做的更改。在微任务编程中,微任务涉及对单个功能点的更改,由系统根据需要自动生成,并通过迭代来提高质量。一项研究了微任务编程在创建小程序上的可行性的研究发现,开发人员能够在不到 15 分钟的时间内完成 1008 个微任务,在机上提交第一个微任务,平均在不到 5 分钟的时间内完成所有类型的微任务并创建 490 行代码和 149 个单元测试。结果证明了微任务编程的潜在可行性,并揭示了要成功地将微任务编程扩展到更大,更复杂的程序仍然需要解决许多重要的挑战。

关键词:编程环境,管理

1.介绍

众包软件工程为缩短软件投入市场时间,生成替代解决方案,聘请专家,通过工作学习以及使参与软件工程更加民主化提供了许多机会。如今,最古老,最流行的软件众包形式之一就是开源软件开发(OSS)。在 OSS 中,从人群中征求意见,向爱好者,专业人员甚至公司开放功能开发和错误修复。 OSS 是一种基于平民的对等生产形式,可以实现以下三个关键的结构化特性:(1)可以将输出分解为单独的贡献单位(例如,解决问题跟踪器中的问题),(2)贡献的粒度足够细,可以吸引那些仅会付出很小努力的人的贡献,并且(3)低成本的机制可以抵御不称职和恶意的贡献,并将其整合为一个整体(例如拉取请求)。但是,当今的开源项目尚未完全意识到该模型的潜力,因为它们对潜在的贡献者施加了巨大的加入障碍。其中包括:(1)识别适当的联系方式并定时收到反馈,(2)识别适当的任务和相应的功能点,(3)了解项目结构,复杂的代码并设置工作区,(4)过时,不清楚的文档和信息过载,以及(5)学习项目实践,领域知识和技术专长。综上所述,这些障碍强阻止了忙碌或随便投入的人做出贡献,并将数以百万计的潜在贡献者池限制为仅最有贡献的人。

通常在其他领域中使用的一种解决方案是微任务。 微任务是一个简短,独立的工作单元,目标明确。 在微任务中组织工作可以使工作人员完成的任务脱上下文,从而可以在不进行其他工作的情况下做出贡献,而无需先验知识。 将工作去上下文化为微任务已应用于许多领域中的问题。 例如,在 Soylent 的工作中可以将编辑文档去上下文化,并分解为“查找”,“修复”和“验证”微任务,在这些微任务中,独立的工作人员可以识别修改的机会,生成潜在的修改并对修改进行投票。 FoldIt 游戏的玩家解决难题任务,然后将其结果用于生成有挑战性的蛋白质折叠任务的解决方案。

微任务众包已发现在软件工程领域可行的去上下文化的任务分解的应用方法。 如今,开发人员通常在 StackOverflow 上完成微任务,其中问题的提问者通过以问题的形式识别简短,清晰的目标(通常构造为要生成或修改的简短代码片段)完成任务的去上下文化[10]。 uTest1 等网站将自由测试人员与项目匹配,从而帮助项目从 300,000 多名注册测试人员中快速招募。

但是编程可以应用微任务吗?对于开发人员来说,今天是否有可能花 10 分钟来回答关于 StackOverflow 的问题,而花同样的 10 分钟来为开源项目编写代码呢?为了实现这一目标,需要新的方法来减少上下文需求,并减少加入传统上由开源项目施加的障碍以扩大参与度。但是,扩大参与范围与提高团队生产力相比是一个截然不同的目标,甚至可能与之相反。与一个开发人员相比,五个人组成的团队会产生单个开发人员不必要的协调开销。同样,将一个开源项目的贡献者数量从 20 个增加到 2000,很可能意味着每个贡献者的小时数都会增加,这是因为每个贡献者在项目上花费的时间更少,专业知识更少,工作更慢。正如 Shirky 所认为的,我们的目标不是利用团队的生产力,而是要利用 1980 名短时贡献者的贡献,否则他们的贡献潜力就无法发挥作用。

为了解决微任务编程的挑战,我们提出了一套针对新编程环境的设计原则,并根据这些原则描述了系统设计。 为了实现细粒度的贡献,将工作组织成对单个功能点(例如功能或测试)的本地更改。 然后,系统本身负责创建,管理和分配微任务,跟踪功能点的状态以确定需要执行的操作,并在必要时传播功能点之间的接口更改。 为了确保所创建的最终程序的质量,将通过草绘,重复编辑,报告问题,检查过程和测试来迭代评估和修改功能点。 为了做出贡献,工作人员只需登录,完成一个简短的教程并开始处理分配的微任务。

我们的工作是对微任务在软件工程中使用的长期探索的一部分。 在本文中,我们考虑在较小的范围内进行编程,在这种情况下,可以通过编码,测试和调试来实现对由客户端构成的组件的明确定义的请求。 我们的方法建立在早期探索和原型检查机制的基础上,这些机制用于为编程和小型先导实验推导微任务。 其他工作研究了微任务众包与其他众包模型的关系,并考虑了协调开发人员对微任务进行编程的机制。 在这项工作中,我们不考虑微任务创建软件需求,体系结构,设计或用户界面。 在其他工作中,我们已开始探索如何将软件设计任务众包。

在本文中,我们为微任务编程提供了一组新的设计原理,以反映从我们先前的方法中吸取的教训。 尤其是,我们贡献了新技术来确保质量,向贡献者提供反馈,模块化调试,使贡献者更轻松地重用代码并更快地启用新贡献者。 我们还提供了一项新的实证研究,探讨了微任务编程在可行性,入门速度,贡献速度和质量控制机制等方面的潜力和挑战。

我们首先通过一个例子来说明微任务编程。 然后,我们介绍我们的方法并描述新的微任务编程环境的设计。 为了评估微任务编程的可行性,我们描述了一项用户研究的结果,其中两群用户使用微任务编程来构建小程序。 最后,我们讨论了将微任务应用到编程中的前景和挑战。

2.激励例子

Doug 刚刚启动了一个开源项目,以构建更好的绘图应用程序。 在初步了解其应具有的功能之后,他决定下一步是开始构建原型实现。 他决定使用 CrowdCod 应用微任务来创建该原型。 他首先将绘图程序的核心逻辑指定为一个组件,该组件由四个功能和描述这些功能将使用和产生的数据的抽象数据类型(ADT)组成。 Doug 在 CrowdCode 管理界面中输入此信息,为项目声明,在其网站上发布该项目的链接,并在在线编程论坛上宣布其新的绘图应用程序。

爱丽丝找到项目,单击并登录到 CrowdCode。她首先看到一个简短的教程,描述了 CrowdCode 界面的主要元素,包括任务描述,微任务窗格,聊天,活动提要和页首横幅。然后,她被分配到了”编辑功能”的微任务。她阅读了第二篇教程,其中描述了该微任务,确定了微任务的目标,可能采取的行动,并强调只写几行代码或伪代码,而不必完成该功能的实现。然后,她开始处理“编辑功能”微任务,并读取其中包含的函数 moveElement。她发现其中已经包含伪代码,因此将其替换为部分实现。她认为实现功能来检查先决条件是在其他地方表现最好的实现方式,因此她在底部编写了一个用于新功能 validElementType 的函数声明用于检查先决条件,并在 moveElement 中添加了一个调用(图 1,底部)。她努力完成工作,发现 10 分钟的倒数计时器几乎快到期了。写下一个最后的想法,她添加了自己的伪代码,该伪代码描述了仍需要完成的一部分功能并单击提交。

在 Alice 工作期间,其他人同时从事七个独立的微任务,为绘图程序的 API 其余部分构建代码和测试。 Bob 被分配了一个微任务来测试 moveElement。 微任务提供函数的描述和声明,描述移动矩形的测试用例的文本以及将测试用例实现为单元测试的请求。 使用测试构建器界面,Bob 首先浏览一个列出可用数据类型的面板,以了解 Element 数据类型的字段。 然后,他意识到自己不知道正在使用什么坐标系。 鲍勃没有立即看到答案,而是在聊天中问了一个问题,爱丽丝回答了这个问题。 鲍勃完成测试,然后单击提交。

微任务编程

 

查尔斯(Charles)坐公车回家,真的想编程。 他登录到 CrowdCode,并被分配了 Write Test 微任务。 毫不激动,他单击“跳过”,并被分配了一个新的“编辑功能”微任务,继续执行 Alice 在 moveElement 上离开的位置。 更热心的是,他迅速实现了爱丽丝(Alice)描述的算法,并编辑了其他几行以使代码更简洁。 然后,他单击提交。

Dave 评论了查尔斯的工作。 他注意到算法中的一个细微问题。 在他的评论中,他描述了该问题并将该作品评为 3 星。 Ellen 被分配了 Edit a Function 微任务来解决该问题,她已解决了该问题。 爱丽丝(Alice)受委派审查艾伦(Ellen)的贡献,很高兴地发现,自从她先前的贡献以来,对 moveElement 的工作已经取得了较大的进展,并给埃伦(Ellen)的作品给予了 5 星的评价。

当 CrowdCode 跟踪 moveElement 的状态时,它确定没有剩余的伪代码要完成,也没有要完成的测试。 使用分布式测试运行程序执行每个测试后,它会收到测试失败的报告,并创建一个“调试任务失败”微任务。 Charles 被分配了该微任务以调试 moveElement,选择失败的测试,并将鼠标悬停在表达式上以查看其在执行中的值。 将鼠标悬停在从 moveElement 到 validElementType 的调用上,他发现 validElementType 返回 false,这与它在描述中所承诺的行为相矛盾。 他使用编辑器编辑 validElementType 的返回值,并将其替换为 true。 重新运行测试后,他发现现在可以通过测试,然后单击提交。 这会自动为 validElementType 生成一个新测试,该测试将自动执行并失败。

Frank 登录到 CrowdCode,并被分配了 对于 validElementType 的“调试测试失败”任务。 查看失败的测试,他发现对于有效的形状,它返回的是 false。 编辑代码后,他发现该函数缺少检查形状有效性所需的参数。 在编辑声明以添加参数后,他添加了一些功能,重新运行测试,查看其通过并提交。 然后自动生成微任务以更新每个调用站点并测试 validElementType。

3. 设计原则

在本节中,我们提供了一组表示微任务编程方法的设计原理。 我们通过检查现有系统以及我们根据自己的经验来设计和评估一系列系统的早期原型,从而为我们的原则提供佐证。

3.1 贡献去上下文化

传统的软件开发任务要求开发人员首先学习上下文,例如代码中功能的位置,构建和运行代码的步骤以及向谁询问信息。 学习上下文会创建一个冗长的入门过程,从而延迟了开发人员首次可以做出有价值的代码贡献的时间。尽管不可能完全消除对上下文的需求,但是减少上下文可以降低入门成本,并使开发人员能够更快地做出贡献。

3.1.1 定位编辑到单一功能点

为开发人员提供单个任务以在单个小的功能点上执行(例如,功能或测试)具有多个优点。开发人员需要修改的功能点应该已经被定义好了,而不是还要在代码库中寻找可以进行更改的适当功能点。 减少此类上下文可能会大大减少在代码库中高效工作所需的知识。

使开发人员一次只能与单个功能点进行交互会带来一些挑战。 与其依赖开发人员访问调用点或功能定义来了解相关功能的作用,不如将此类信息嵌入其他功能点的接口中。 不应依赖开发人员通过阅读相关代码来推断参数的运行时类型,而应为参数显式指定静态类型。 开发人员需要进行仔细考虑才能更改其他的上下文信息。

3.1.2 提供预配置的环境

安装适当的工具,从服务器下载代码,识别和下载适当的依赖项以及配置工作区以构建项目,这些都构成了重大的贡献障碍。 提供一个预先配置的环境可以大大减少这些障碍,从而减少启动时间。 可以通过包含配置的开发环境的预设虚拟机,安装的库,脚本或通过 Web 应用程序来提供预配置环境

3.2 自动生成微任务

微任务描述了要取得进展的下一步。准确,完整地捕获所有必要步骤非常重要,这样就不会丢失所需完成的工作,也不会拖延进度。在任何给定的时间点,可能有许多并发的微任务正在进行中。一种方法是让经理明确创建每个微任务并评估每个结果贡献。但是,对于由短暂贡献者进行的微任务简短编程,这种方法对微任务的管理者要比他们自己简单地完成工作要花费更多的时间,从而抵消了微任务的好处。此外,它还假定一个或多个经理在任何时候进行的工作始终可用。编程之外的领域中的传统微任务众包系统已通过使用完全自动化的微任务生成来解决了该问题,在这种情况下,客户描述了初始请求,系统负责自动并立即生成全套微任务以完成,以及诸如冗余的机制投票确保质量。这样,不再需要由请求者手动创作,管理和评估每个微任务的成本,而是由系统在众包的帮助下组织工作。

但是,自动微任务生成带来了新的挑战。 在传统的众包方法中,微任务是通过固定的步骤序列生成的,例如 MapReduce 工作流程,其中描述了将每个输入转换为输出的步骤。 相反,软件任务是动态的,并且可能无法预先枚举可能需要的功能和测试以及可能出现的问题和错误。 需要一种不同的方法,以便在程序出现时动态生成微任务。

3.2.1 跟踪功能点状态

为了跟踪程序的当前状态及其在满足其要求方面的进展,可以分别跟踪程序中每个功能点的状态。考虑函数创建时的状态。在任何时间点,一个功能可能都需要编写声明,完成实现或对其代码进行调试。通过跟踪描述完成或未完成的属性,可以使用状态机来描述功能点可以通过其进行过渡的状态,并规定要完成的工作(例如,在开始其功能之前强加一个功能必须具有声明的约束)。无论何时提交微任务,功能点都可以改变其属性(例如,记录已添加声明),并转换到反映这些属性改变的新状态。然后,每个转换可以生成适当的微任务。功能点的演变甚至不必是单向的。例如,在开发人员在修复缺陷时添加伪代码之后,功能点可能会转换回以前的状态。

3.2.2 跨依赖指示接口更改

当工作人员编辑功能点时,对功能点界面的编辑可能需要更改系统中其他位置的功能点。 例如,添加功能可能需要通过新参数传递其他信息,这随后需要所有函数调用点和调用该函数的测试进行更新以提供此信息。 由于微任务仅跨越单个工件,因此需要一种机制来向其他功能点发出信号,说明发生了接口更改。

为了响应界面更改通知,功能点必须生成适当的微任务。一个关键的决定是依赖功能点应响应哪个接口更改。例如,一个函数可能会在其实现中发生行为更改,对其行为描述进行更改或对其声明进行更改。但是,通常很难确定实现的更改或对函数描述的更改是否表示或不表示该功能接口的更改,这可能会影响该函数的调用者。根据我们对早期原型的经验,我们发现工作人员经常更改函数描述只是为了澄清文本并修复格式和拼写错误。在这种情况下,向这些函数的调用者发出信号更改会产生许多不必要的微任务,从而大大降低了生产率。更好的替代方法是仅针对明显需要进行更改(例如声明更改)的更改发出信号,并在不太频繁的情况下依靠测试来捕获其他行为界面更改。

在开发人员工作时,他们利用任务上下文描述其他相关功能点的接口。 开发人员可能会发现此任务上下文与他们的功能点不一致。 例如,我们发现编写测试的工作人员有时意识到无法按照测试用例描述中所述测试函数的行为。 结果众包工人不可能完成他们被要求执行的微任务。 因此,允许工作人员报告任务上下文相关的问题,中止微任务的工作,并为其他功能点创建微任务以解决问题是很重要的。

3.3 通过迭代实现质量

所有众包方法的关键考虑因素是设计机制以防止不良贡献并确保高质量的工作。 然而,使用众包来征集许多贡献者进行开发,也可以提高软件质量,因为众人贡献的多样化为实现更高质量的设计提供了基础。 众包本身不是由单个经理或架构师负责来监督项目,而是随着工作的进行,通过个人的贡献来确定项目的方向。 因此,重要的是要详细考虑分解工作流组织和协调机制对产生的输出质量的影响。

3.3.1 通过草图鼓励修改

长时间的贡献会阻止众包在完成工作时提供反馈,从而使贡献在没有众包投入的情况下偏离正常。 出于多种原因可能会导致质量下降。 工人可能会因为困惑、不了解足够的知识而无法提供高质量的解决方案、付出了很少的努力或是恶意而偏离了正常轨道。 无论出于何种原因,即使是单个低质量的贡献,也可能通过引入使后续实施工作更具挑战性的决策或引入缺陷来显着降低总体质量。

防止低质量贡献的一种机制是减少任何个人贡献可能造成的损害。 通过减小贡献的粒度,许多工人就有机会贡献于相同的功能点,并且任何有问题的贡献都可以修改。 这样,犯错误的工人可能会迅速对其进行修正。 但是,我们在初步研究中发现,尽管另有明确指示,开发人员有时仍希望在单个功能点上继续工作直至完成,这反映了开发人员对编程任务的期望。 例如,在一项关于早期原型的非正式研究中,一名工人在一个“编辑功能”微任务中工作了 66 分钟。 由此,我们了解到创建限制贡献规模的机制(例如限制单次贡献的最大时间或规模)非常重要。

编程任务通常需要多行代码。 在这些情况下,开发人员可能首先开始进行一项功能,然后将工作移交给其他人继续。 在这种情况下,对于开发人员而言,重要的是要有办法通过草图实现设计的机制来传达其方法的意图。 草图可以采用伪代码的形式,其中开发人员为算法编写高级计划,而不必担心仔细考虑所有细节。 如果算法中的步骤可能包含功能的整个单元,则开发人员可以编写功能桩,描述该功能预期提供的功能。 通过这种方式,开发人员可以在更高的抽象水平上做出贡献,随后的开发人员可以随后进行填写。

3.3.2 支持审核和测试

防范低质量贡献的第二种机制是明确检查贡献的质量。 创造机会来审查贡献将创造一个贡献必须经过的质量把关,并为贡献提供可能有价值的反馈。 审查可以快速确定朝着无效的方向发展的新贡献者的工作,并教导困惑的工人正确的工作方式。

评审提供了一种冗余形式,其中两个贡献者必须共同签署工作才能继续进行。 当然,与任何冗余一样,评审本身可能是错误的。如果审稿人能够决定放弃某些贡献,这在导致有价值的贡献被丢弃方面会成问题。 一种解决方案是仅允许使用评审修改工作。 这样,引入了更多的冗余,因为随后的贡献者必须再次对先前的贡献做出反应。例如,响应于评审修改贡献的贡献者可以确定所请求的修改本身是错误的并且忽略它。这样,随后的工作人员便可以看到以前的贡献并采取他们认为合适的任何行为。

与传统软件开发一样,测试提供了重要的质量关卡。 此外,通过将编写测试和实现功能划分为单独的微任务,测试为另一个开发人员提供了一个机会,使他们可以在测试中了解该功能的改变,从而可以揭示实现者可能未曾考虑过的问题。 但是,在某些情况下,测试本身可能不正确,而不是功能不正确。 因此,重要的是提供必要的功能以同时修改功能和测试。

4. 系统

根据我们的设计原则,我们开发了用于微任务编程的 CrowdCode 环境。 在以下各节中,我们将描述用户工作流,系统架构及其实现。

4.1 工作流

所有工作都从客户请求开始,客户请求描述了要通过一组功能描述和声明,一组 ADT 描述以及一组验收测试待实现的 API。所有工人的贡献都是通过微任务完成的。当工作人员首次访问 CrowdCode 时,将向他们显示一个欢迎屏幕,解释 CrowdCode 的基本概念,并提供简短的交互式教程,解释主要的界面元素。当工人第一次开始他们以前没有做过的微任务时,会为他们提供一个额外的教程,其中使用一系列示例(例如,图 2)详细说明了如何执行微任务。 然后为工作人员提供系统自动分配的微任务,他们可以选择完成或提交或跳过。

微任务编程

 

表 1 列出了 CrowdCode 环境中的微任务。 图 3 描绘了为实现功能而生成的微任务的简单示例。 根据客户请求创建新项目后,将为每个 API 函数生成“编写功能”(图 3. 1)和“编写测试用例”(图 3.2)。 每当提交包含伪代码的函数时,都会生成一个新的“编辑函数”微任务以继续进行该函数的工作。

微任务编程

 

编写测试分为两个步骤。 在“编写测试用例”微任务中,工作人员首先通过枚举用于标识应测试行为的测试用例描述列表来指定功能的测试计划。 在第二步中,每个测试用例为要作为单元测试实现的测试用例生成一个单独的“编写测试用例”微任务,从而使工作人员可以并行地完成每个测试(图 3.4)。

提交包含一个或多个新功能桩时,将生成“重用搜索”微任务,使工作人员有机会找到提供与所请求桩相似的功能的现有功能,或表明不存在此类现有功能(图 3.5)。 在这种情况下,将创建一个新功能并生成一个“写功能描述”微任务,以根据提供的功能请求和请求功能的实现编写新功能的声明和文本描述(图 3.6)。 然后递归地继续工作,继续生成微任务以编辑功能和编写测试用例。 同时,一个事件被发送到调用函数,并且一个“编写调用”微任务被生成并排队(图 3.7)。

当一个函数不包含剩余的伪代码时,它将被编写并准备进行测试。 随着每个测试的实现,将针对该功能执行该测试。 如果某个功能未能通过一个或多个测试,则会为每个失败的测试生成一个唯一的“调试测试失败”微任务,以提供所有通过的测试以及恰好一个失败的测试(图 3.8)。 然后,工作人员可以编辑该功能,使其通过先前通过的测试和其他失败的测试,插入新的伪代码和桩,或报告一个或多个功能测试的问题。

微任务编程

 

当然,测试失败可能不是功能中的缺陷。这就提出了一个挑战:当故障定位似乎首先需要知道包含缺陷的功能时,如何才能将故障定位取消关联,以使开发人员能够使用单个功能模块化地工作。为了应对这一挑战,CrowdCode 使用了使用桩的模块化调试过程。在调试函数时,工人可以随时将鼠标悬停在函数调用上以查看实际参数和返回值。如果工作人员发现某个函数的返回值似乎与该函数的描述不匹配,则该工作人员然后可以编辑该函数的输出,从而自动创建桩。然后重新运行测试,使工作人员可以检查对功能行为的建议更改是否可以修复缺陷并导致测试通过。如果微任务是通过桩提交的,则请求的行为更改随后将传播到调用的函数,从而创建一个相应的测试,然后该测试将运行并且将失败(除非功能已同时更改)。这样,故障定位过程将在函数调用中递归地继续,从而为每个相关函数创建一个新的“调试测试失败”微任务。

在提交每个微任务之后,在微任务被标记为完成之前,首先会生成一个相应的“评审”微任务(“调试测试失败”和“重用搜索”微任务除外)。 复查微任务向员工展示了贡献和原始任务背景,并要求员工提供五点量级的质量评级。 得分为 1-3 的微任务被标记为“重发”,并且必须包含说明原因的评论; 否则,微任务将标记为“已接受”,并且评审文本是可选的。 然后,评审的结果将通过反馈通知工人。 一旦评审接受了,微任务就完成了,微任务的内容被用来更新相应的功能点。 如果标记为“重新发布”,则会生成一个新的微任务,该任务将复制原始微任务,并包括原始贡献和评审。 然后将此微任务分配给新工作人员,以解决所报告的问题。

微任务编程

 

在查看微任务的任务上下文时,工作人员可能会发现任务上下文存在问题,从而阻止他们完成微任务(例如,无法测试的测试用例)。 在这种情况下,工作人员可以通过描述问题而不是微任务并提交来报告任务上下文中引用的特定功能点的问题。 然后为功能点生成一个新的微任务以解决该问题。

为了确保贡献不会偏离轨道并获得频繁的反馈,微任务的时间和贡献大小受到限制。 微任务的持续时间限制为 10 分钟,通过显示剩余时间的条形图向工作人员显示(图 1-4)。 6 分钟后,显示警告消息。 如果 10 分钟后仍未提交微任务,则会自动跳过该微任务并将其丢弃。 此外,除任何伪代码外,“编辑功能”和“调试测试失败”微任务中的贡献仅限于净增加十个语句(图 1-3)。

CrowdCode 为工作人员提供了项目进度的总体展示,列出了所有功能的总代码行以及功能和测试的数量(图 1-8)。 工作人员可以通过全局聊天与其他当前登录的工作人员进行交互。 最后,CrowdCode 提供了一个鼓励贡献的基本游戏化系统。 提交微任务的工人将获得与评分相应的分数。 为了鼓励员工承担别人不希望做的微任务,跳过微任务会使其价值增加 20%。 每个工人的得分都显示在排行榜中(图 1-8)。

没有剩余的未完成的微任务时,项目即已完成。 要使用众包工人实现的代码,客户端可以随时访问项目的管理页面,并下载所创建代码的当前或过去版本。

4.2 服务

微任务编程基本上是分布式的,需要每个贡献者分别做出贡献之间的协调和同步。 CrowdCode 通过中央服务协调工作,该中央服务负责处理新的贡献,更新功能点的状态并生成新的微任务。

微任务生成器。 在客户提交贡献并由评审者审核之后,贡献将用于更新功能点的当前版本。 基于这些更新,功能点的属性可能会更改。 三个属性确定每个功能的总体状态:是否具有功能描述(已描述),是否具有不包含伪代码的完整实现(已编写)以及当前是否具有任何失败的测试(错误)。 更新功能后,将检查这些属性以确定接下来应生成哪个微任务。 如果未描述功能,则会生成“写功能描述”微任务。 如果未编写函数,则会生成“编辑函数”微任务。 如果某个功能有错误,则会生成“调试测试失败”微任务。 图 3 描绘了工件过渡和生成的微任务生成的示例。

函数的工作已完成,并且进入描述,编写且没有错误的状态时,不会生成任何微任务。 但是,当调用它的函数添加新的桩并将测试传播到该函数时,该函数可能再次进入错误状态。 在这种状态下,工作人员可以自由地编辑函数并添加伪代码,并且它可能会再次转换为未编写状态。

每个功能都有一组相关功能,这些功能包含该功能的调用站点。 每当消息通过更改其名称或参数来更改其接口时,都会向该函数的每个依赖项发送一条消息。 然后,此消息为每个调用者生成“编辑功能”微任务。 某些微任务还可以报告功能的问题(表 1),这将会会为该功能生成“编辑功能”微任务。

分布式测试执行器。 为了减少服务器资源的使用并促进对众包的可伸缩性,所有测试都在客户端而不是服务器上执行。 每个客户端都维护一个测试执行服务,该服务执行测试并返回测试结果。每次对功能进行编辑后,所有测试的运行都计划由服务器执行。这项工作分发给客户,客户将报告每次测试执行的结果。 测试失败会生成“调试测试失败”微任务。 此外,在“调试测试失败”中,工作人员可以直接运行某个功能的所有测试。

版本控制系统。 要使测试能够在客户端上执行,客户端必须具有被测功能的相应实现。 由于功能可以任意调用其他功能,因此客户端必须具有系统中所有功能的代码。 因此,CrowdCode 维护了一个简单的版本控制系统,将当前代码和测试从服务器同步到所有客户端。 服务器确保每个功能点的活跃微任务不会超过一个,因此不会发生合并冲突。 每当接受贡献并更新功能点时,都会创建该功能点的新版本。 然后,此新版本将与所有当前活动的客户端同步。

活动。 各种后端操作跟踪用于填充客户端视图的状态。这包括每个工人的活动提要,排行榜和项目统计信息。活动服务管理此状态,并向客户端广播更新。

4.3 体系结构

CrowdCode 被设计为由 Web 客户端,后端和实时 NoSQL 数据存储组成的客户端-服务器系统(图 4)。 后端和 NoSQL 数据存储区均公开 RESTful 接口。客户端从后端检索并提交微任务,该后端处理微任务并更新实时 NoSQL 数据存储中的数据。后端和数据存储区经过分片以实现可伸缩性,其中后端被组织成由包括功能点,工作程序和项目的单个实体组成的单独组件,并由数据存储区的单独区域支持。当服务器接收到多个并发请求时,每个组件都能够将请求处理到自己的状态并与其他组件并行地更新其状态,而无需创建竞争条件或资源竞争。

微任务编程

 

在 Web 应用程序体系结构中,传统上认为客户端是不受信任的,因为 Web 应用程序的任何用户都可以编辑在客户端上运行的代码。相反,服务器被认为是受信任的,因为只有拥有服务器的应用程序开发人员才能更改在该服务器上运行的代码。例如,恶意的众包工人可能会编辑客户端实现,以删除项目的所有代码,或者为自己提供更有利的活动历史记录。 为了防止此类攻击,所有客户端都必须通过服务器将所有更改提交给应用程序状态,服务器会更新应用程序状态并将更新发布到 NoSQL 数据存储之前验证请求的更改。将更新发布到数据存储后,数据存储将直接向客户端广播更新应用程序状态,包括对版本控制系统和活动服务的更新。

5.评估

5.1 方法

我们招募了十四名参与者,他们在美国,阿根廷,巴西和葡萄牙进行远程工作。 参加者是通过个人联系招募的。 所有参与者都具有计算机科学相关学位,并且在 2 个月到 12 年的行业经验之间,平均为 4 年。 所有参与者都有使用 JAVAScript 编程的经验。 参与者获得的时间补偿为 100 欧元。

与实验者的所有互动都是通过电子邮件和 IM 进行的,参与者之间的所有互动都是通过 CrowdCode 进行的。 我们将参与者分为两组(A 组为 6 个,B 组为 8 个),以提供两个观察众包人员工作并减少组间差异对结果影响的机会。 两组都是从相同的参与者人群中招募的,包括不同专业水平的参与者。

在研究期间收集了几种形式的数据。该服务器用于记录对功能点的所有更改,生成,提交,跳过和重新发出的微任务,以及使用聊天功能的情况。为了记录更多参与者互动的细粒度数据,捕获了所有参与者的屏幕录像。此外,参与者还完成了两次有关其经历的调查。在会议进行中,参与者完成了关于他们在微任务编程方面的经验和挑战的调查。 在会议结束时,要求参与者完成对他们的经历的第二次调查。每次会话总共持续 5 个小时。

在每次会议开始时,通过电子邮件向参与者简要介绍本研究的目的,要求安装屏幕记录仪,提供登录 CrowdCode 的说明,并要求从登录开始。 然后,在 CrowdCode 环境中为参与者提供了一系列教程,解释了整个环境,并在他们处理新类型的微任务时介绍了每种微任务类型。 每个参与者都在自己的计算机上独立工作。

每个会话中的参与者共同努力,为简单的交互式绘图应用程序的核心行为实现一个组件。功能集中于创建,操纵和渲染绘图元素。特别地,功能集中于将指定为鼠标动作的用户输入转换为图形的基础模型的更新,并根据图形的模型生成渲染元素。该任务是通过客户请求指定的,该客户请求为四个函数(createElement,createAction,renderDrawing 和 moveElement)其中的每个函数都以注释形式提供声明和简短描述。这些描述由描述这些函数参数的 ADTs 进行补充(元素,位置,分段和动作),以及每种 ADT 的几个代表性示例。除了函数声明,客户端请求中未提供任何代码。然后,根据此客户请求,CrowdCode 会自动为四个功能中的每个功能生成两个微任务:4 个编辑一个功能微任务和 4 个编写测试用例微任务。参与者开始工作时,系统会自动为他们分配这些微任务之一。

5.2 结果

5.2.1 可行性

在两次实验过程中,参与者提交了 1,008 个微任务,并实现了总共 22 个功能,包括 8 个 API 函数(2 个会话中有 4 个函数)和 14 个从头创建的函数。参与者的最终输出包括 490 行代码和 149 个单元测试和 2920 行代码。参与者平均每个功能创建 7.8 个测试。创建的测试中有将近一半(47%)是针对 API 函数的 36%的功能,这可能是因为它们的复杂性更高或因为它们是第一位的。在这两次实验中,总共 70 个小时的参与者时间中,有 44 个小时花在了提交的微任务上(称为“贡献时间”)。参与者将最多的时间用于审阅微任务(37%),编写测试微任务(22%)和编辑功能微任务(17%)。表 2 列出了每种微任务类型花费的时间。剩余的非贡献时间用于阅读研究材料,完成两次调查,处理被跳过而不是提交的微任务,以及等待分配微任务。

微任务编程

 

提交的所有 1,008 个微任务由系统自动生成。 例如,图 5 描绘了在过程 A 中为函数 createAction 生成的微任务。编辑函数并编写测试用例反复生成,完成和检查微任务,直到工作完成为止,并生成其他微任务以响应对附加功能的请求。虚线之前提交的最后一个微任务(“评审”微任务)导致功能转换为已实现状态,触发了测试的执行,并为每个失败的测试生成了单独的“调试测试失败”微任务。 其他功能的行为类似。功能有时会在已实现状态和未实现状态之间转换多次。与会人员很少更改一旦定义的功能接口,在过程 A 中只有两个更改而在过程 B 中只有零更改。

微任务编程

 

5.2.2 学习速度

登录 CrowdCode 后,参与者首先阅读简短的教程,介绍微任务编程和平台的基本用户界面元素,然后分配他们的第一个微任务。 在这一点上,参与者经常花时间熟悉环境。 在某些情况下,参与者开始处理他们的第一个分配的微任务。 在其他情况下,参与者跳过了一些微任务,因为他们想在开始工作之前先研究几种类型的微任务。 总体而言,参与者平均在 14 分 32 秒后提交了他们第一次完成的微任务。

参与者完成的第一批微任务通常是最具挑战性的,因为他们了解了微任务编程的各个方面,例如伪代码,请求功能和评论。 一份报告说:“一旦您已经开始完成一些微任务,这将非常容易。 乍一看,这可能有点奇怪,因为您的时间很少,但是您已经习惯于对其进行管理。” 评审微任务有助于发现早期微任务提交中的问题。 平均而言,首次提交的微任务的评分为 2.8,满分为 5。78%的评分为 3 或更低,导致他们被重新发布给第二位参与者。

与其直接产生学习成本,不如将特定微任务的学习成本推迟到参与者首次遇到该微任务之前。 在这一点上,参与者再次需要学习新的微任务,从而浪费时间并降低质量。 在开始从事微任务之前,参与者首先阅读了第二本特定于微任务的教程。 完成一种新的微任务将完成时间从 1 分钟 31 秒的中值提高到 5 分钟 29 秒,并且将质量得分的中位数从 5 分降低到 3 分。一位参与者报告说:“直到它完成,我才能理解每个任务 绕了几次”和“刚开始时,一切都很混乱。 渐渐地我开始理解”。 另一个建议是,使他们能够完成示例微任务的交互式演示微任务可能有助于加快学习速度。

随着参与者通过会议获得 CrowdCode 的经验,平均评审分数趋于稳定之前趋于上升。 图 6 描绘了带有 10 分钟时间窗口的移动平均评审得分。

微任务编程

 

5.2.3 贡献速度

总体而言,工作人员能够在 5 分钟内的中位数时间内完成两次实验过程中的所有微任务类型(表 2)。 对于较大的微任务,例如“编辑函数”,“编写测试用例”和“调试测试失败”,完成时间更长,对于“写入功能和调试测试失败”,中值完成时间高达 4:57 或 4:00。 较短的微任务的平均完成时间低于 2 分钟,包括重用搜索,编写测试和评审。在所有情况下,中位完成时间都不超过十分钟截止时间的一半。

参与者跳过了他们开始的所有微任务中的 13%。跳过的原因多种多样。 在某些情况下,参与者跳过微任务,因为他们似乎无法完成它们。在其他情况下,参与者连续跳过几个微任务只是为了在选择开始时先探索可用的微任务类型。由于参与者在微任务上用完时间,系统自动跳过了微任务,占到了总跳过微任务的 17%。一些参与者感到有些仓促,特别是那些错误地认为微任务要求更多的参与者。“有时花十分钟的时间让我感到很急,尤其是当我不得不从头开始编写新功能并且必须阅读并理解规格时。”

为了衡量参与者在贡献代码的微任务上的贡献,我们计算了修改的代码行数,包括添加,编辑和删除的行。参与者平均添加了大约 3 行代码,并分别删除和编辑了大约 1 行代码,平均修改了 5 行。

5.2.4 质量控制机制的作用

在实验过程 A 和实验过程 B 中,参与者都没有时间在 5 小时的会议中完全实现这些组件。在每个实验结束时,仍然需要进行其他工作以完全实现客户端请求中指定的功能。为了评估参与者的总体进步和贡献的质量,我们构建了一个测试套件(未提供给参与者),然后在每个实验中编辑最终代码,直到测试套件中的所有测试通过为止。在实验 A 中,必须编辑贡献代码的 3%(7 行),并添加另外 3%(6 行)的代码。这包括修复较小的拼写错误(例如,添加数组索引,修复拼写错误的变量名称)以及实现参与者使用伪代码绘制的几行代码。在实验 B 中,必须编辑 12%(33 行)的代码,并增加 25%(69 行)的代码。增加的内容包括实现参与者创建但尚未实现的两个功能。

在整个实验期间,参与者反复实现和修改功能。个别功能经常反映出某些参与者的贡献。 图 7 描述了在实验 A 中所做的实现贡献。平均,大约 3 个工作人员为每个功能的代码做出了贡献,从而提高了工作人员对所生成代码质量的认识。一位参与者报告说:“至少有三个人(通常是更多人)对每一部分代码进行了检查。我觉得效果很不错。”代码实现的贡献通常代表了一个在之后仍然需要继续贡献的步骤。图 8 描述了在会话 A 期间对函数 createAction 的三个贡献。一个工作人员首先实现了该函数的一种情况,其余情况则保留了伪代码。 在随后的迭代中,一名工作人员重新处理了某些情况逻辑,另一名工作人员为其他情况实现了逻辑。

微任务编程

 

为了识别和纠正缺陷,参与者使用了测试和评审系统。工人平均每个功能执行 6.8 个测试。测试失败时,将生成“调试测试失败”微任务。测试失败通常是由瓶邪错误,JavaScript 语法使用不正确,函数调用不正确以及错误实现的功能引起的。参与者的贡献时间的 37%用于“评审”微任务。审查系统有助于识别缺陷,例如代码中的拼写错误,缺少测试用例,错误的测试以及对数据类型或功能的不正确使用。一位与会者指出,“您可以从别人指出的错误中学习,或者通过更好的方法来实现某一功能的相同目标”。

微任务编程

 

参与者使用问题报告系统来报告他们通过功能点的当前状态确定的问题,从而确定了 63 个问题。 许多与过于模糊或自相矛盾的文字有关。 问题的最常见来源是“编写测试”微任务,参与者报告了 43 个问题。 大多数是因为测试用例的描述不清或难以理解。 例如,实验 B 的一位参与者报告说,“定义元素格式正确时,测试功能是否返回 true”的测试用例尚不清楚。参与者还报告了调试测试失败微任务中的 13 个问题。 在发现代码正确但测试错误之后,参与者使用问题报告系统报告测试中的问题。在 A 实验中 11 次在 B 实验中 1 次,众包工人错误地解释了功能规格。例如,在实验 A 中,测试案例“创建了一个矩形元素,而前一个元素为矩形...”,因为“前一个元素仅用于 Freehand,而在其他情况下未定义”。通过问题报告系统,并没有捕获并标记对功能规范的所有不正确或不同的解释。其他人只有在执行测试时才被捕获,从而创建了调试测试失败微任务来解决差异

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>