什么鬼?把简单的事情弄复杂,连多年的生信老司机都给整不会了。还社区驱动?无力吐槽。没入门,已放弃,白白浪费几十分钟。
既然其官网说了, Linux 是数据科学的通用语言 。为何 Nextflow 搭建的流程没有多少 Linux 的影子?
把简单的生信流程,弄成一个堪比 IT 的大工程?
槽点一:过度包装,徒增复杂性
我们就以其官网提供的核心流程 RNA-seq 为例,来看看这东西到底有多复杂。下面是流程目录。
代码语言:javascript复制rnaseq/
├── assets
├── bin
├── CHANGELOG.md
├── CITATIONS.md
├── CODE_OF_CONDUCT.md
├── conf
├── docs
├── lib
├── LICENSE
├── main.nf
├── modules
├── modules.json
├── nextflow.config
├── nextflow_schema.json
├── pyproject.toml
├── README.md
├── subworkflows
├── tower.yml
└── workflows
内容很多,其中:
代码语言:javascript复制workflows/
└── rnaseq.nf
是主流程。在其中,引入子流程 subworflows 和模块 modules ,如下图:
在这一套体系中,模块是最小的单位,每一个软件的具体操作,被包装为模块。然后在模块之上,再封装成子流程。最后,由主流程将各子流程串起来,成为完整流程。
这样看似很有道理,模块化,增加代码的可重用性。实则是过度包装,一行 Shell 代码能完成的功能,硬是包装出了几百行代码(可查看 hisat2 比对软件的包装逻辑)。功能没增强多少,复杂性呈指数级上升,有害无益。
如果你曾经学习过 Nextflow 却没有学懂,那不是你的错。这套东西没几个人能看懂,更何况用它搭建流程了。
槽点二:语法怪异,晦涩难懂
语法中有大量生造的符号,仅举一例便可窥其全貌,如将多个 FASTQ 文件 cat
在一起的命令:
CAT_FASTQ (
ch_fastq.multiple
)
.reads
.mix(ch_fastq.single)
.set { ch_cat_fastq }
ch_versions = ch_versions.mix(CAT_FASTQ.out.versions.first().ifEmpty(null))
其中.reads
/ .mix
/ .set
等,啥意思,就一个简单的cat
命令,需要弄这么复杂吗?
结论是,用这套符号系统搭流程,还不如直接用 C ,Java 呢,起码是正规的编程语言,参考资料众多。更不用说像 Python 或 Perl 这种通用的脚本语言,天然适合流程搭建。
我将流程搭建分为这样几个境界:
- Shell 脚本
- Makefile
- Python / Perl
- Python / Perl Makefile
这足以应付绝大多数的生信数据分析场景,没必要把事情搞得那么复杂。
那些年,我们踩过的坑
好的生信团队都是用自己的生信框架。不会用社区的,如WDL,snakemake,nextflow等,我们好多年前就放弃了。不为别的,因为吃过亏。
还记得曾经大火的 WDL,许多知名生信机构都在推,我们也热情拥抱社区。原因很简单:社区驱动,资源共享,一套流程开发出来,所有团队都能使用,这将会极大地避免重复劳动,提高资源利用率。
于是当时部门的生信流程尽量都用 WDL 搭建。没想到这货非常不稳定,总是莫名其炒地报错,非常难以排查原因。
痛定思痛之后,我们放弃了 WDL,回到了做生信最开始的地方:老老实实写 Shell,然后用 Python 串起来。
到后来,随着搭建的流程越来越多,我们经验也越来越丰富。最后将所有流程通用的部分,抽离出来,形成了一个通用的组学数据分析框架。于量,我们也定义了一门域语言(DSL)。
不过,我们并没有“屠龙少年终变成恶龙”,我们的框架依然保持简单而高效。它没那么华丽,但刚好够用。
一个好的生信流程框架应该是怎样的?
我认为,好的生信流程框架,应该有这样几个特点:
- 批量任务,能同时分析任意数量样本的任务。
- 既支持单样本,也支持配对样本的数据分析。
- 能轻松定义任务之间的依赖关系,最终纳入有向无环图(DAG)管理。
- 每一步任务可以定义 CPU 和内存资源需求。
- 能适应各种计算环境,如单机,以及各种集群。这可以分两步实现,第一步生成 Shell 脚本,第二步再将 Shell 脚本组织成符合集群任务投递的文件。
- 任务命令调用,尽量用 Linux Shell 脚本描述,这样方便提前测试命令的正确性,因为 Linux 是数据科学的通用语言,Shell 命令是软件调用最自然的方式。
- 简约而不简单。在保证能够满足绝大多数应用场景的情况下,新手也能简单上手。
那有人可能要问了,这样一套流程,实现应该很复杂吧?其实不然,只需要 500 行 Python 代码即可。
欲知究竟如何通过 500 行 Python 代码就能实现这样一套堪称完美的框架模型,且听下回分解。