Open edX是我一直关心的开源项目。

近期参与构建了一个开源项目blocks4edx。在这个项目中,我们试着将积木引入Open edX中,帮助课程团队创作复杂的题目。blocks4edx可用于替代Open edX的Custom Python-Evaluated Input题目编辑器。允许课程团队在不写代码的情况下,通过拖拽积木自动生成代码与题目(XML)。

Elite Education邀请我与@MT(曾老师)和他们一同参加2019.3.26在UCSD(加州大学圣地亚哥分校)举办的Open edX年会,在年会上,我们可能会就blocks4edx做一个主题演讲。

体验

你可以通过这个链接体验blocks4edx

我在项目主页里写了使用说明.

缘起

与@李懿的一次交流中,我们聊到 积木如此强大,它可以将领域概念封装在图形之下,暴露出合适粒度的积木块,而将其他细节屏蔽掉,用户通过组合积木来操控领域概念和表达逻辑。如此一来,就可以为不同细分领域的人,针对他们的问题,构建出问题域内合适粒度的积木供他们使用。

@李懿 想到课程团队在使用Open edX时遇到的困难: 课程团队根据教授的课程和课件,经常需要制作随机题目,所谓的随机题目是指,题干的内容是随机的,但考察的知识点是确定的。举个例子,如果我们想考察两位数的加法,我们希望题干出现的数字是随机的,答案却会根据题目出现的数字做相应调整。于是我们就能做到了,既考察知识,又做到了题目随机化。

Open edX默认支持这种题型:Write-Your-Own-Grader Problem,这是Open edX令人震惊的地方,它对教育的思考非常深入。

目前官方给出考察两位数的加法的随机题目模版是:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<problem>
  <p>Some problems in the course will utilize randomized parameters.
     For such problems, after you check your answer you will have the option
     of resetting the question, which reconstructs the problem with a new
     set of parameters.</p>
<script type="loncapa/python">
x1 = random.randint(0, 100)
x2 = random.randint(0, 100)
y = x1+x2
</script>
<p>Let (x_1 = $x1) and (x_2 = $x2). What is the value of (x_1+x_2)?</p>
<numericalresponse answer="$y">
  <responseparam type="tolerance" default="0.01%" name="tol"
    description="Numerical Tolerance"/>
  <textline size="10"/>
</numericalresponse>
<solution>
  <p><b>Explanation:</b></p>
</solution>
</problem>

既有Python代码,又有XML代码。

@李懿指出美中不足的是,Open edX提供的随机题目编辑器需要编程才能实现(使用Python)。如此一来,每道题都需要课程团队与技术团队的配合。课程团队确定了考察的知识点后(往往是计算公式),由技术人员用代码实现它。这不仅支出了技术人员的时间,也影响课程团队的进度,而且还增加考虑沟通成本。

能否让用积木来创建随机题目?

我们拉来课程团队的@李婷同学帮我们梳理了一遍创建随机题目的流程,并就着一道具体的题目,走完了整个流程。

接下来我们就用积木来优化这个流程,让课程团队可以通过拖拽积木,独立地实现题目的构建,而无需技术人员参与。blocks4edx将自动生成题目所需的所有代码: Python+XML。

技术方案

我们选择blockly作为基础工具。

第一步工作是将问题域中的概念积木化, 问题域中的所有概念都在官方文档中: Write-Your-Own-Grader Problem。由此可见这是一道定义清晰地好问题,解决它的过程充满乐趣。

我们一直坚持积木是一项很有潜力的技术,codelab.club将在这个问题上持续深挖,我们会探索积木的各种可能性。我们并不满足于copy一个国外项目,照着实现一遍,接着号称自主研发,就此了事。我们希望探索一些有趣的范式和最佳实践。

目前积木一般以两种方式被使用:

  • 其一是blockly官方例子中的方式,直接generate出代码。
  • 其二是code.org/scratch3.0使用它的方式,将积木映射为js函数。

我最初想用第一种方式,直接generate出Python代码。在这个想法里,积木编辑器被视为Python代码生成器,课程团队使用它来构建题目中Python代码相关的部分。积木编辑器不关心题目的其他部分(XML)。

后来我觉得,应该整体解决这个问题,课程团队不只是对Python代码不熟悉,他们构成题干的XML也不熟悉,仅生成Python代码是不够的。即便熟悉XML,手写XML也不是什么令人愉快的体验。于是我想一次生成所有的东西。

接着带着这个想法开始构建blocks4edx

由于我想要的比较多,遇到的困难也就多些。既要生成Python代码,又要生成XML代码,blockly本身并不支持这种操作。于是我想到模版的思路,将XML视为文本,虽然它也以Python的方式generate出来,但本质上被看作文本,于是生成它地javascript有了预处理它的能力。如此一来,问题域里的XML结构肯定可以被积木化。

在这个思路下,只剩下一个困难需要解决: Python的import相关部分会被默认前置(如import random),但它本不应该跑到所处的xml结构之外。由于xml以Python代码的方式generate,所以前置不可避免,但我们不能接受这点,怎么办呢?hack blockly的成本太高,不可接受。剩下的方案只有打破xml,依然是预处理地思路,这块的最终方案见源码细节:var code = <problem>\n<script type="loncapa/python">\n${origin_code};

这个策略本质依然是把代码看作文本。如果你将代码视为字符串,你就拥有无限的力量,这是LISP教会我们的,但这种力量也很危险。这是一把力大无比却容易砸伤脚的锤子。

todo

blocks4edx不只适用于Custom Python-Evaluated Input题目,也适用于edx的其他题目,因为edx中地大多题目都是XML,这意味着他们是文本!

积木可以生成文本,理论上我们就可以做任何事。

关于积木化其他题目,我们将在之后继续探索。

blocks4edx的目标是为课程团队提供更好的题目编辑器。

参考