我们如何在圣彼得堡HSE教授软件工程

在以前的帖子中,我们谈到了学生在实习方面的工作:科学(例如, 在JetBrains Research中 )和工业 。 在这篇文章中,我们想分享我们如何教授工业编程。



简而言之:在四门课程中,一名前学生尝试一十二种技术和语言,不断编写和删除大量代码,通过经验丰富的朋友的代码审查(并非总是第一次尝试),深入研究主题并最终捍卫有意义的文凭。 所有这些都是在大学进行的,并提供国家文凭。 夏季,您可以在JetBrains,Yandex和JetBrains Research(如果您想了解更多科学知识)在俄罗斯放松或实习,也可以出国旅行(Google,Facebook等)。 现在更详细。


关于我自己


我叫Yegor Suvorov,我在高等经济学院学习,在Google实习(两次),Asana和GSA Capital实习,成功参加了国际编程( 学生学校 )奥林匹克竞赛。 去年,我从学术大学的本科学位毕业,所以我几乎完成了帖子中描述的所有内容。 我还参与了软件工程培训计划的开发,并在多个主题(范例和编程语言,C ++)中进行了实践练习。


主要组成


在本文中,我们将仅考虑“工业编程”子方向。 尽管我们仍然有“机器学习”,“编程语言”和其他一些语言,但方向上的程序重叠,尤其是在前两门课程中。


培训包括三个主要部分。 首先,我将进行概述,然后再详细介绍每个部分。


  1. 基本项目 。 从第一学期开始,孩子们就学会用双手工作。 每六个月,所有“工业程序员”必须通过2-4个基本主题(其他子方向需要某些主题)。 目的:让学生或多或少地参与所有编程领域的学习,以便您可以逐步了解抽象层次。 从用少量的汇编器(对于最持久的)和命令行在C中用用户空间编写玩具OS开始,然后到C ++的移动语义,再到monad转换器。 这对于形成不同编程的视野和经验是必要的。 我们不仅教授语言:并行编程,网络,数据库。 而且,当然,很少有主题与代码无关,但是在这种情况下都是一样的:例如,软件工程(概述课程:为什么我们需要团队/经理/项目和风险管理)和界面设计(否则,他们会认为“模具被铆钉了” -很简单。”) 也有数学和算法,但这是单独发布的主题。
  2. 学期练习 。 从第二学期开始,必须完成这些课程。 目的:让学生尝试做比家庭作业更大的事情,并了解更像是什么。 在学期开始时,将举行一个项目展览会,潜在的研究领导者将讨论您可以如何使用他们。 顺便说一句,领导者的学位是可选的-更重要的是特定的人和实践可以给学生带来什么。 在一个学期中,您可以在Qt上制作一个桌面+移动应用程序,并了解在整个学期中通常如何在一个项目上工作而无需明确的技术要求(有困难)。 接下来的事情就是尝试使用Android,感觉就像“为社交网络打造可靠的客户端”一样,即使功能受到严重限制,也很难做到。 在另一种方法中,尝试使用Python制作某种机器学习工具,并意识到您根本不想处理这个主题。 第四步-完成Haskell编译器,感到恐惧,然后回到甜心C ++文凭。 反之亦然。 取决于学生-这就是练习的含义。 结果,学生要么形成了喜欢的方向(您可以在其中工作并获得文凭),要么经历了一系列不同的方向。 反正双赢。 顺便说一句,如果您不喜欢任何一个项目,可以提出自己的想法。 但是在这种情况下,您首先需要引起科学顾问的兴趣或从外部找人,然后说服我们,有意义的和受保护的东西可以从项目中产生。
  3. 可选项目 。 出现在第三年。 原因:并非每个人都想钻研Linux内核,就像不是每个人都想钻研带有大量隐式的Scala集合的设计一样。 因此,您可以选择要研究的主题。 例如,如果一个学生不喜欢在膝盖上屈膝的多种方法,那么他可以上Linux上的容器虚拟化课程,用纯C语言编写并感到高兴。 反之亦然:如果“英特尔64和IA-32架构软件开发人员手册第3卷”仍然有些噩梦,那么您可以通过抽象的独角兽进入美丽的Scala世界。 在每个模块(半学期)中,大约提供4门课程,其中应选择两门。

此外,我们希望学生喜欢学习。 您可以随时与计划经理聊天,并在任何领域提出改进建议。 我们一年收集四次反馈,并且-注意-考虑到这一点并不断改进该程序。 我们没有专门招募很多学生,因此我们有机会与每个人亲自交谈。 第二年级和第三年级有30名学生,第四年级有15名学生。


我们还不断地根据学生的要求创建或寻找新的课程,寻找能够理解该学科并且能够教书的优秀老师。 因此,在本模块中,仅用了几个星期, 成功出现了SPbCTF的实验性逆向工程课程。 并且,如果您找不到合适的课程,则可以通过协议,与Computer Science CenterShAD或Coursera一起进行有意义的尝试


基本项目


主要编程主题:C ++,类Unix系统,范例和编程语言,计算机体系结构,Java,操作系统,功能性编程,数据库,软件设计,软件工程,并行编程,计算机网络技术,接口设计,移动开发。


这些主题共同涵盖了工作中可能发生的几乎所有任务。 它们还可以防止各种“经典”错误,例如,将浮点数与==进行比较,对未定义行为,竞争条件的适当性期望以及谈论产品开发中设计模式和非程序员任务的存在。


当然,在学习过程中,学生会不断“动手练习实验室和功课”。 以经典的东西为例,例如,基于Huffman算法的存档器的实现。 使它“以某种方式工作”并不是那么困难。 但是,要使项目具有良好的体系结构(至少将输入输出,位压缩和算法本身分开),请正确使用C ++的功能(三年或五年的规则,具体取决于半年),并通常对代码进行设计,以使其阅读愉快且不会完全尴尬置于开放源代码中-教师在C ++课程中教授的另一门艺术,它不断与学生交流并详细分析所有代码行。 在其余的科目上是相似的。 任何课程都不仅限于理论测试。 在所有编写代码的学科上,都会有经验丰富的程序员对代码进行复习。


C ++ 。 学习的第一年。 以C开头,以C ++ 14结尾。 我们展示了RAII,Valgrind和自动测试,我们学会了编写库(保证例外的my_vector)和应用程序(同一个存档器)。 原因:因为C ++仍在业界中积极使用,并且它与系统编程产生了积极的共鸣(缺少垃圾回收,所以您可以显示内存中数据的布局...)。


类Unix系统 。 第一学期。 年轻的战斗机课程介绍如何在不使用C:\D:\情况下使用命令行和文件系统。 测试工作示例:在该对上,听到安装了Ubuntu的轻微损坏的映像,有必要对其进行修复。 一个家庭作业的示例:遍历Bash上一个文件夹中的文件,并使用正则表达式呼叫有用的人。


范例和编程语言 。 第一学期。 一打主题(至少是OOP,函数编程,SQL,多线程),每个主题的学生都可以尝试一两个作业。 当然,从表面上看,但它仍然使人们了解编程的通用性以及使用不同方法可以组装哪些很棒的东西。 然后将详细描述OOP,FP和SQL,但是在第一年,学生已经知道它们的存在,并且可以说,如果需要,可以在代码中安排断言或编写几个简单的单元测试。


计算机体系结构 。 第一年。 寄存器,由逻辑门,高速缓存,处理器管线,数字表示和其他理论组成的类似计算机的组件。 原因:将有关各种低级事物的信息捆绑在一起。


爪哇 第二年的学习。 它以流和Android的课程项目结尾(例如,使用漫游器和网络模式播放递归井字游戏)。 我们展示了Maven,IDEA,JUnit,与网络的异步工作。 原因:JVM上现在有很多事情,有很多库,很高兴知道。


操作系统 。 第二年 铁杆 引导加载程序无须大惊小怪-在预制中为学生提供了多重引导,切换到保护模式,然后您可以在C中编写内存分配器,线程,进程,文件系统,保护环分区甚至ELF加载。 也许不如Tannenbaum的“现代操作系统”那么广泛,但是您可以清楚地看到深入研究它还是想留在孤立的用户空间中是否很有趣。 如果有兴趣,欢迎参加特殊的Linux内核编程课程。 顺便说一句, Stepik提供了一个非常轻便的版本-那里没有OS编写,但是有必要的理论和验证任务。 为了不因性能不佳而飞走,请通过它。


功能程序设计 。 在lambda演算上上了两节课,然后去了Haskell。 我们以单子变压器结束。 当然,所有内容都是详细的:monad不是盒子,而只是这样的用于编写代码的模板的有用抽象。 但是,中级项目比实际更具理论性-在Lambda演算中编写自动类型推断。 但是现在正在准备继续学习本课程(作为硕士课程的附加主题),其中计划了多线程和Web服务器。 另请在计算机科学中心阅读。


资料库 我们熟悉关系DBMS(以PostgreSQL为例),SQL。 我们设计一个特定学科领域的数据库,然后根据老师的指导安排彼此的代码复习。 然后老师进行一次代码复习复习。 形式为“为此数据库写这样的请求”的竞赛。 简单分析查询(EXPLAIN)作业。 再次,与计算机科学中心课程相呼应。


软件工程 。 他谈到了如何安排程序员的工作,公司中其他所有人的工作,为什么好的经理仍然有用以及为什么管理项目也很困难。 规划的重点是什么,为什么它并不总是有效,为什么不是所有的bug都需要修复?目标是要了解除人以外的项目需要什么。 当然,在一学期内详细披露所有内容是不现实的,但是,例如,知道在项目开发之后仍然存在同样重要的支持是很有用的。


软件设计 。 各种建模现实和(UML图)的方法,分解方法,设计模式。 作为示例,在课程结束时,我们将了解GFS,BigTable,CMake ...在实践中,我们不仅学习编写代码,而且还学习描述体系结构并在适当的地方应用模板。


并发编程 我们从简单的线程和互斥锁开始,最后解析并编写无锁/无等待算法,渗透MESI,研究诸如fork-join框架,OpenMP,OpenCL,Intel TBB之类的高级技术。


计算机网络技术 。 讲座:TCP / IP协议栈的主要协议的详细概述:ICMP中的消息,RIP的历史考察,DNS中的各种记录,FTP / HTTP / SMTP / DHCP的工作方式,NAT是什么,以及有关IPv6的一些知识。 做法:我们在跨平台的TCP客户端和服务器上编写附加信息,首先是玩具Messenger,然后是DNS的UDP客户端。


界面设计 学生不会编写任何代码,而是要经历设计良好用户体验的所有阶段:他提出了一个项目,进行了研究(包括对真实人的调查),开发并验证了使用场景,最后您可以在Sketch或Figma中绘制一个界面。 。 目的是要了解,对于一个好的产品,您不仅需要代码,而且还需要大量其他准备工作。 这里没有代码审查,但与老师积极地讨论了所有中间产物。 在我看来,第一次尝试通过作业是不现实的(但是,这不是必需的)。


移动开发 。 进阶Android开发课程。 我们已经在Kotlin上编写了比Java上更多的文章,我们在Android上使用了各种Kotlin特定的东西。 与第二年的Java项目相比,这里的应用程序更加复杂,我们在外部依赖项和库上的工作更多,我们对界面和用户的考虑更多(这里的课程与界面设计有一些共同点)。


软件测试 。 基本上,有很多理论为学生可能在其他学科中发明的所有标准实践取名:测试控制流或数据流,成对测试(所有成对测试)……还有一些特定的实践-为此等制定测试计划这种技术,可以在此类应用程序中查找极端情况,并使用Selenium在Web应用程序中运行多个方案,以使仅编写案例就不会感到无聊。


大数据软件工程,又名大数据软件工程。 与计算机科学中心一起阅读。 我们连接数据库,并行编程,分布式系统和其他流行语-这些都在讲座中。 在去年的实践中,学生从零开始编写了他们的分布式电话簿。 在接下来的发布中,将重点从低级转移到行业中实际使用的工具,如Zookeeper,Cassandra和其他可怕的动物,似乎是正确的。 到目前为止,主要的困难是如何模拟学生的“大数据”条件并评估他们的解决方案:如果没有明确的证据表明没有它,一切都会非常糟糕,则无需举起Zookeeper。


练习


训练的第二个重要部分是练习。 从第一年开始,学生将在经验丰富的同事的指导下完成一些实用的任务。 例如,另一个用于管理日历或便笺的应用程序。 或现有应用程序中的新功能。 或者,如果将其引入计算机科学领域,则可以研究一系列公式的可计算复杂性。


在最初的课程中,我们不需要新颖性或实用性(毕竟,目标是发挥作用),但是对项目质量和保护的文凭要求不断提高。 在最后几门课程中,除了“做了什么?”这个问题之外 重要的是让学生说出完成的原因和原因。 同时,“我真的想要这家由我的研究主管工作的特殊公司”本身并不是答案。 但是,“那里的硬盘每秒钟就会死掉,所以这个开源不起作用,这篇文章纯粹是理论上的,但是Google有解决方案,但是已经关闭了”-就是这样。 从第二年开始,它就不能用作保护不必要的锻炼的文凭-拥有笔记本电脑和Google的好奇的开发人员已准备好进行辩护(以及一些防御措施)。 “还没有人这样做”-实际上可以说是最危险的事情。 顺便说一句,从第一年起,我们不仅捍卫文凭,而且还捍卫实践。


这是一些具有典型保护的照片。 摄影师:Dima Drozdov。




通过实践,您可以学习大型项目的“长期”工作,有时是由其他开发人员编写的。 并非总是可以用项目的主题来猜测:例如,尝试过低级开发后,学生可能会决定将来参与其中。 这就是练习的意思:了解自己喜欢什么,不喜欢什么,不是在工作中,而是在较低的条件下。 尽管后者的做法应发展为实质性的学士学位。 根据文凭,“实质性”是指您至少可以在Habr上写一篇文章,而不要减负。 或者,如果工作非常好,则发表在科学期刊上,在会议上发表讲话,或者至少收集优点。


选修项目


第三,也是重要的部分是附加项目。 主题是特定的,可能不是每个人都需要,但有兴趣的学生可以品尝。 在高年级课程中,大多数学科都是这样:有一个基础,它仍然有朝着学生一个有趣的方向扩展我们的视野。 不幸的是,没有足够的时间来拿走所有物品。 有时课程设置会发生变化,以下是提供给我的课程:


JVM的替代语言 。 一个包含两个模块的课程:一个模块涉及Kotlin,另一个模块涉及Scala。 对于Kotlin,我们既解析Java互操作,又编写自己的DSL和协程。 最后一个可选的作业是使用corutin将调试器添加到玩具语言解释器中(在先前的作业中编写)。 至于Scala ...语言虽然很大,但是我们有时间了解各种隐式的'y :)


在Linux内核中编程 。 逐步开发了一个内核模块,该模块可模拟虚拟存储设备:mmap,缓冲区,并发访问,非阻塞I / O。 顺便说一句,您可以从操作系统中回顾中断并挤出多任务,并研究Linux的内部结构(例如,等待队列)。


编译器 我们正在OCaml中编写我们的微语言编译器。 中间堆栈计算机,在x86中进行编译,没有任何LLVM,与libc集成。 学生惊讶的惊叹“为什么它只落在一百个长度的表达上?” (可能是因为该错误在于寄存器分配中)。 顺便说一下, 计算机科学中心也提供类似的课程。


计算机图形学 。 相对较低的课程:我们研究OpenGL,编写阴影和延迟渲染的着色器,比较使用和不使用伽马校正的颜色混合。


建立DBMS 。 内部设备数据库。 各种连接算法,形式模型,列DBMS。 在实践中,您可以在带有加号的玩具DBMS中实现几种逐块处理算法(例如,双管道哈希连接)。


容器虚拟化 。 Linux中容器的详细研究。 举例来说,命名空间和cgroup以及API及其工作方式。 网络的各种辅助工具。 在此过程中,我们像Docker一样编写容器,但并不是那么简单-您需要正确限制所有内容,配置网络,将必要的文件转发到容器中。但是,还考虑了使用Kubernetes作为示例的高级编排。


我们要改善的地方


我们和我们的学生都更可能对由此产生的计划感到满意(根据民意测验)。 但是,您不仅可以改进现有项目,还可以添加新项目,甚至可以做得更好。


例如,目前尚不清楚如何将“工作经验”的某些方面转移到大学。 与旧版代码相同的工作-有用吗? 然后 甚至还有书籍和特定技术。 但是,为了从中得出一个好的过程,必须结合几个因素:


  1. 不要长时间分散教师的主要工作注意力,以使他们不断帮助学生理解大型项目。 而且,如果有好的文档-那就不再是旧版。
  2. 学生应该感兴趣。 不包括“向您不需要的项目添加一千行代码”。
  3. 结果应该是可预测的。 “看来这是一项艰巨的任务,对不起,他们没有想到。”-根据检查作业的结果,这是一个坏消息。

不幸的是,我们还没有弄清楚如何做到这一点。 最接近机器学习的方向是机器学习,每周举行一次研讨会,让学生就一些最新文章进行演讲。 也许可以将这种经验转移到工业编程中。


可能当前未涵盖的唯一领域是Web开发(包括前端),复杂的自动化系统(例如1C或SAP)和计算机安全性(实验课程于2019年2月上旬开始)。 我们可能忘记了其他事情,或者您知道如何教更好的编程-我们很乐意在评论中进行讨论。


但是,我们认为,准备工作的毕业生,如果需要的话,必须接受专门的培训,然后可能是公司的内部系统,已经离开了文凭。 顺便说一句,经过如此严格的课程设置之后,我们现在正在思考和尝试实现的一个单独主题是在硕士课程中学习的内容,但这是单独发布的主题。

Source: https://habr.com/ru/post/zh-CN439362/


All Articles