直接构建

我们如何设计 Streamlit,让您倾向于向前发展。

发布于 产品,
Just build it

如果您正在阅读此文,您可能已经熟悉 Streamlit 了。如果还不熟悉,这里有个概要:Streamlit 是一个用于构建数据应用的 Python 框架。它有自己的观点,内置了常用功能,并且与特定的设计系统紧密相连。

  • 它专注于数据应用。我们所做的一切都源于此。我们不针对手机或您喜欢的 SaaS 等通用应用,而是针对数据科学家和机器学习工程师需要在组织中使他们的工作产生影响的那类应用。
  • 它有自己的观点,因为我们希望推广快速、迭代的工作流程,并坚持我们认为的工程最佳实践。
  • 它内置了常用功能,因此您入门所需的大部分东西都在库本身中。
  • 最后,它与特定的设计系统紧密相连,因此您无需花费时间构建组件库、视觉语言或标识。您只需立即开始——而且非常快

此时,我可以告诉您 Streamlit 是如何开始的。它可以追溯到一个基于我们在工业界和学术界经验的好预感。我们可以深入探讨我们如何深入不同公司,观察他们的数据科学家和机器学习工程师的工作,以塑造 Streamlit。但是 Adrien 五年前已经写得非常好了,我觉得我无法超越!

所以,我将改为谈谈我们对数据应用的深入关注如何转化为我们每天做出的产品决策。为此,我将从一个故事开始…

10倍效率的新员工

曾几何时,一个数据科学团队构建了一个强大的预测模型,预测公司最重要的指标。财务团队看到后非常喜欢,于是要求一个实时版本供他们在每周会议中使用。于是数据团队向工具团队提交了构建数据应用的请求,工具团队将其加入了他们的待办事项列表。

三个月后,经过多次会议,这个应用终于交付了,而且它非常漂亮。 

但问题来了:财务团队试用后,发现它并不是他们真正需要的。于是他们又向数据团队提交了另一个请求,数据团队将其转交给工具团队,工具团队又将其加入了他们的待办事项列表。又过了好几个月。

这时,一个毫不知情的新员工加入了数据团队,并被分配了一个入门项目:快速搭建一个数据应用,以便在等待工具团队的那个真正的应用的同时,解除财务团队的阻塞。

经过一番谷歌搜索,这位新员工发现了 Streamlit,并在一天之内能够与同事分享一个极简应用。它并不完美,但她处理了一些反馈并更新了应用。第二天,她将其展示给财务团队的联系人,获得了更多反馈,并相应地改进了应用。

三天之内,财务团队开始在他们的会议中定期使用这个应用。他们有了更多反馈,新员工很快在更新版本中解决了这些问题。

一周之内,CEO 开始使用这个应用,这位新员工被誉为英雄 💪

为什么会这样

我们已经无数次看到这个故事发生。 新员工的应用最终获胜的原因是:今天一个简单的应用胜过三个月后一个过度设计的应用。

事实上,这正是最优秀的初创公司构建产品的方式!他们发布最小可行产品(MVP),尽快将其交到客户手中,并不断迭代。

在这个过程中,他们逐步加固底层基础设施。因为新员工的故事有一个必然结果:随着团队继续使用这个应用,他们会逐步将其投入生产环境。

那些慢得要命的定制 Pandas 转换?他们会将其提取到单独的数据管道和一些物化表中。

其他应用想使用的复杂计算?他们会将其移到 RESTful 服务中。随着应用的发展,他们会将其重构成多个页面。他们会编写测试,搭建 CI。然后应用变得固若金刚。

这种流程的好处显而易见

  1. 您可以构建更好的应用,因为您通常在尝试之前并不知道自己需要什么。因此,通过构建和用户测试,再构建和用户测试,您最终会得到一个比您提前计划好一切却后来才意识到这不是您想象中的解决方案要好得多的应用。
  2. 您从第一天就获得价值。在您构建和用户测试的同时,您已经拥有一个有用的应用。而且它只会随着时间的推移变得越来越有用。
  3. 您不会过度构建。与其在构建应用的同时构建管道,不如先将应用推出,然后随着它证明自己的有用性再对其进行加固。然而,并非所有应用都有用,也并非所有有用的应用都能存活足够长的时间来需要加固。因此,您只需将宝贵的精力花费在那些既有用又长期存在的应用上。

您开始的方式很简单:您直接构建它。

刻意设计

我们喜欢认为新员工的故事在如此多不同的公司发生并非偶然。我们喜欢认为这个故事发生是因为我们刻意设计 Streamlit 来促进向前发展

当您第一次开始编写应用时,向前发展意味着在5分钟内获得一个已经在某种程度上有用的草稿。而使应用更有用的一件事无疑是交互性。因此,从一开始,我们就强烈认为应该使交互性尽可能简单。 

例如,您不必创建一个带有滑动条的“视图(View)”,然后创建一个带有修改滑动条使用的“模型(Model)”的回调函数的“控制器(Controller)”(换句话说,就是 MVC 范式)。

value = st.slider("Pick a number", 0, 100)

您输入这段代码,就得到一个已经能做事的应用。向前发展!

然后,两年后在构建会话状态(Session State)时,我们很快了解到提议的 API 很容易导致差一错误(off-by-one errors),唯一有效的解决方案是回调。受到我们过去使用 MVC 和类似范式的经历的创伤,我们在这个问题上花费了相当长时间,才提出了一个明确的“Streamlit 式”回调版本,避免了所有这些复杂性。更重要的是,这个解决方案不会强制您从一开始就使用回调,而是允许您在需要时再将其分层添加。向前发展!

另一个对我们——当然也对社区——来说非常重要且贴近的例子是样式。一方面,对我们来说最简单的事情就是直接在 Streamlit 中添加对 CSS 的支持,例如使用 st.css(...)st.write(..., style="css goes here")。但当我们进行实验时,注意到不受限制的样式访问很快就成为向前发展的阻碍。人们不是将第一个版本提交给利益相关者,而是卡在仔细查阅 MDN、与层叠作斗争、调整选择器以及纠结于单个像素上。最糟糕的是,最终结果往往不稳定且令人分心。

所以我们通过问自己这些问题来处理这些请求: 

  • “人们试图解决的根本问题是什么?”
  • “这个问题有多普遍?”
  • “我们能否自己解决它并帮助解放开发者?” 

根据这些问题的答案,我们采取以下两种方法之一

  1. 为问题提供一行式、有观点的解决方案

    这发生在几个月前。我们注意到大量开发者使用 CSS hack 将 Logo 放置在应用左上角,因此我们决定通过 st.logo() 为他们提供一行式解决方案。这个新命令会绘制他们的自定义 Logo,使其响应侧边栏的状态,确保它不与任何内容重叠,并且默认情况下看起来很美观。

    这也是我们添加文本颜色标题下划线容器边框垂直对齐Material 图标等功能的方式。在视觉效果和行为方面,它们无疑是有观点的解决方案,但好处是您只需说出您想要什么,Streamlit 就会做到,然后您可以继续做下一件事。向前发展!
     
  2. 提供一套精选的控制旋钮……并观察

    当一行式的有观点解决方案不够用时,我们会引入一套最少的“控制旋钮”,观察结果并进行迭代。由于我们不想破坏兼容性,我们的大多数功能都是单向门(one-way doors),这意味着我们必须谨慎行事。

    一个例子是主题设置(theming)。每个人都希望他们的应用与其公司的颜色相匹配,当然,确切的颜色因公司而异。但 Streamlit 的界面由几十种颜色组成,选择一个视觉上令人愉悦的组合可能需要几个小时。因此,我们解决这个问题的第一个尝试是让您只选择 4 种颜色,Streamlit 会为您计算出所有其他颜色。向前发展!

    我们现在正忙于幕后思考解决这个问题的第二次尝试——一个扩展的解决方案,它能为您提供更多控制旋钮(甚至不仅仅是颜色!),同时不牺牲迭代速度。类似地,我们也在考虑除了列之外的新的、更灵活的布局选项。

    我们目前还没有什么要宣布的,但请务必留意😉

总而言之,我们不希望任何事物分散您向前发展的注意力。我们每迈出一步,都尽力提供一个框架,抽象掉 HTML、JS、CSS、HTTP、路由、序列化、回调以及各种工程细节。这样,您就能专注于将数据的力量置于您的利益相关者指尖,以便他们也能实现向前发展

A stylized image of a rocket ship taking off.

迭代成就完美

在 Streamlit,我们自己也是 Streamlit 的忠实用户,这意味着我们有自己的烦恼和功能需求。我们感同身受您的痛点,并且我们一直在迭代改进这个库。我们绝不想停止迭代!我们对这一承诺的体现就是我们每月都会发布一个新的版本。

Streamlit 社区及其独创性也给了我们启发。我们不断看到将 Streamlit 推向我们从未想过的高度应用自定义组件,这为我们提供了将新功能引入核心库的新思路。社区无疑是这份工作中最好的部分!

正因为如此,我们还有很多新东西要带给您。我们公开开发,因此您可以随时在 roadmap.streamlit.app 上查看我们的路线图,或者参加下一场季度展示会,我们的产品经理会在会上讨论 Streamlit 的最新进展,例如垂直对齐和高级主题设置。

迭代的妙处在于,最好的日子总在前方。很荣幸能与您同行。

Streamlit 愉快!🎈

分享此文章

评论

在我们的论坛中继续讨论 →

产品中的其他文章...

查看更多 →