一起来做类型体操吧!😊

一起来做类型体操吧!😊

类型重要吗?

长话短说,类型很重要。

类型的重要性

静态检查

在编程中,类型往往是我们的第一道防线,它可以帮助我们在编译阶段就发现一些潜在的问题,避免一些不必要的错误。在过去,由于 JavaScript 是弱类型、解释型语言,所以在编译阶段无法发现一些类型相关的问题,这就需要我们在运行时进行一些类型检查,这样就会增加一些不必要的开销。而 TypeScript 则是由微软推出的、基于 JavaScript 的强类型语言,它可以在编译阶段就发现一些类型相关的问题,这样就可以避免一些不必要的错误。

当然也不是说用 JavaScript 就一定会出问题,但这要求编程者有更高的责任心和编程能力,能够在编码阶段就提前规避问题,但对于大型项目来说,这是不现实的。不要完全相信任何人的代码,即使是自己的代码。因为人是会犯错的,需要加以约束。在 Web 应用开发过程中,JavaScript 代码如果访问了一个空对象的字段则会导致异常,如果程序有限定错误边界,那么这个错误可能会被忽略,但是如果没有限定错误边界,那么这个错误可能会导致程序崩溃,也就是页面白屏。而使用 TypeScript 配合 IDE 的类型检查、其他静态检查工具,可以在编码、编译和代码合并时就发现并修复这些问题。

类型即文档

另外,用弱类型语言编写的项目一旦涉及到多人协作(甚至是对于现在的自己和过去的自己来说也是如此),就会变得难以维护和协作,因为弱类型语言无法提供足够的信息,所以在多人协作时,很容易出现一些问题。而强类型语言则可以提供足够的信息,帮助我们更好地理解代码,提高代码的可维护性。所以我也认为“类型即文档”。

现在很多语言都有相关工具可以通过类型信息来生成文档,例如 openapi-generator、TypeDoc、JSDoc 等等,通过代码自动生成文档可以帮助开发者省去很多写文档的时间,同时也可以极大程度地提高交流效率。

阅读更多
rFTP - 用 Rust 实现简单的 FTP Server (2)

rFTP - 用 Rust 实现简单的 FTP Server (2)

前情提要

上一篇文章中,我讲述了我为什么选择 Rust 作为学习计算机底层知识的工具,一些 Rust 的基础知识和我当时所遇到的困难。在这篇又是属于目标回收的文章中,我将介绍最近的进展、Rust 开发的体验和下一步的计划。总的来说,用 Rust 写项目体验尚可,通过与编译器博弈而最终通过“考试”后,自己对 Rust 的理解也有了些许提升。

异步编程

在 Rust 中,异步编程是通过 Future 特征和 async/await 语法糖来实现的。Future 是 Rust 中的异步编程的基础,它代表了一个异步计算的结果或者异步任务的“承诺”,可以通过 poll 方法来获取计算的结果。async/await 语法糖则是为了让异步编程更加友好,通过 async 关键字来定义异步函数,通过 await 关键字来等待异步计算的结果。

越来越多的语言采纳异步编程机制,比如 Python 的 asyncio、JavaScript 的 Promise(或者是同样的 async/await)、Golang 的 goroutine 等等。异步编程的优势在于可以提高程序的并发性能,因为异步编程可以让程序在等待 I/O 操作的时候不阻塞,可以继续执行其他任务。Rust 的 Tokio 是一个基于 Future 的异步编程框架,它提供了很多异步编程的工具,比如 tokio::spawntokio::net::TcpStream 等等。

阅读更多
在 Kubernetes 中安全地运行应用

在 Kubernetes 中安全地运行应用

背景

在近期的工作当中我大量接触 Kubernetes 集群以及容器化应用,在完成 Operator 拓展的开发和发布后,有海外用户反映在 OpenShift 平台上运行我们的容器化应用会遇到安全性问题,具体而言是我们的容器化应用默认需要 root 用户运行,而 OpenShift 平台如果不进行专门的设置是不允许容器使用 root 用户的。为了解决该用户的问题我们花费了一些功夫,正好我也想以此为契机进一步了解如何在 Kubernetes 中安全地运行应用。本文将记录我在调研和学习过程中的一些心得体会。

容器安全

Docker Init CLI

Docker Init 命令是用来创建遵循最佳实践的 Docker 配置文件的命令行工具。在使用时通过选择需要运行的应用类型(例如 Go、Python、Node、Rust 等),Docker 会自动帮助用户创建出符合最佳实践的 Dockerfile 和 compose.yaml 文件。

我的操作系统是 macOS, Docker 版本为 25.0.5,后续的版本中支持的应用类型可能会更多。

阅读更多
VSCode 插件 - YAI

VSCode 插件 - YAI

介绍

这又是一次目标回收计划,早在 2021 年我还在广泛地写 TypeScript 代码时就想完成这样一个插件来满足我“不打断心流地引入模块”的需求,但“新建文件夹”之后我一直没有实际的迭代动作。直到最近高频写 Go 代码时,才真正意识到这个需求的重要性。于是我又重新打开了这个项目的代码仓库。

这是一个 VSCode 插件,叫做 YAI,全称 Yet Another Importer,英文项目命名的 Yet Another 数不胜数,我也随波逐流一次。这个插件是用来帮助开发者方便地引入模块的,它可以自动识别当前项目中的依赖,并且扫描项目本地的文件,统计当前项目中引入模块的规律和频次,在需要引入模块时给出相应提示,并且以编程语言“原生”的方式将模块引入到代码中。何为“原生”,也就是适应当前项目编程语言的引入方式,比如在 JavaScript 项目中,它会使用 importrequire 语句引入模块,而在 Python 项目中,它会使用 import 语句引入模块,在 Go 项目中,它会使用别名来引入模块等。

目前这个插件还处于开发阶段,但是已经可以在 Go 语言中使用了。目前规划的编程语言还有 ECMAScript、Python、C/C++ 这几种。该插件的代码仓库在 Github 代码仓库中,如果你也对这个插件感兴趣,欢迎使用或者参与开发。

插件已发布,可以在 yai - VSCode Marketplace 查看安装。

这篇文章可以算作插件的设计文档,我会在这里记录一些关于这个插件的设计思路和实现细节。

阅读更多
Controller-runtime 源码阅读

Controller-runtime 源码阅读

Operator 是 Kubernetes 用来拓展其 API 的一种开发范式(Pattern),其核心是定义若干的自定义资源及其对应的资源控制器,当这些资源发生变化时其对应的控制器对变化进行调解(Reconcile),最终使得实际状态与预期状态达成一致。K8s-sigs 推出的 kubebuilder 是一个用于构建 Operator 应用的框架,和 Operator-SDK 一样都依赖了 controller-runtime,提供了高级 API 和抽象,让开发者更直观地编写操作逻辑,并提供用于快速启动新项目的脚手架和代码生成工具。

截至目前我已经参与了两个 Operator 项目的搭建和维护,均采用了 kubebuilder 做基础脚手架。我目前对 CRD 的设计生成、Webhook 的校验机制和、Controller 的控制循环机制有了一定认识,接触时间稍长后在日常开发 Operator 项目时难免出现缺乏新意的情况,Operator 模式看久了和 CURD 之于后端有些许相似。但我乐观地估计通过观察下层实现可以收获一些启发。既然 kubebuilder 和 Operator-SDK 都依赖了 controller-runtime,那么就先从它出发吧。

阅读更多
当我执行 kubectl create 时发生了什么[译]

当我执行 kubectl create 时发生了什么[译]

翻译自 What happens when … Kubernetes edition!。我认为这篇文章写得生动有趣,且在关键位置都给出了有价值的链接,引导进一步的阅读学习,让我有了重读并翻译的冲动。

如果我希望往 Kubernetes 集群当中部署 nginx,我大概率会在命令行输入下面这样的命令并敲下回车键:

1
kubectl create deployment nginx --image=nginx --replicas=3

几秒之后,我应该能看到三个 nginx 的 pod 散布在集群的工作节点上。这很神奇!但这个过程背后究竟发生了什么?

关于 Kubernetes 的惊人的特点是,它通过用户友好的 API 处理工作负载的部署。其中的复杂性被简单的抽象隐藏起来。但为了充分理解它所提供的价值,了解其内部工作原理也是很有用的。本指南将引导您了解从客户端 kubectl 到 kubelet 的请求的完整生命周期,并在必要时链接到源代码(或者相关文档和博客)来进一步说明正在发生的事情。

这是一份不断修订的文档。如果您发现可以改进或重写的地方,欢迎贡献!

阅读更多
rFTP - 用 Rust 实现简单的 FTP Server (1)

rFTP - 用 Rust 实现简单的 FTP Server (1)

开发动机

核心动力是我有学会一门系统级编程语言的梦想。所以计划用 Rust 为开发语言(手段)完成本科三年级计算机网络专业课上的 FTP 大作业(目标),学习 Rust 的同时巩固计网的基础知识。

虽然大一刚入学就开始接触 C/C++,但是对于当时没有任计算机知识何积累的我来说用这样的方式开始我的编程入门实在是颇为残忍。或许我当时连内存大小和磁盘容量都分不清,不知堆栈为何物,也搞不懂什么编译链接,让我去理解指针实在是有点为难。现在回过头来看,当时的教学顺序对零基础的学生来说是不太友好的:老师在讲指针结构的内存优化时我甚至还写不出像样的符合语法的程序,课程内容就自然也就无法很好地消化了。

如果由我来制定教学计划,我一定将最开始的编程入门课定为使用 Python 教学而不是 C/C++,在知道如何写出鲁棒、高效、优雅的代码前,先要做到能写代码,就好似学会跑步之前需要先学会走路;等学生们了解了计算机组成原理、操作系统等计算机基础知识之后(或同时),再教授 C/C++ 等较低层的、系统的编程语言了。话扯太远了,就此打住。

阅读更多
为什么前端开发要选择 GraphQL

为什么前端开发要选择 GraphQL

这篇博客其实是以一次公司内的技术分享为基础做的调研和总结归纳,包含了我自己很多不成熟的观点看法。这次分享主要是想向新同事介绍为什么我们选择在项目中大规模使用 GraphQL 而不是更传统更简单的 RESTful API。

GraphQL 是什么

在上一篇有关 GraphQL 的博客里,我简单地说明了 GraphQL 的定义及其大致用途,贴了官网链接就开始介绍我使用 GraphQL 的“更优雅的”方式,对 GraphQL 本身描述得并不多。这里又贴一下英文的定义:A query language for your API

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

划重点,它是一种查询语言使数据可查询的运行时。作为一种语言,它有自己的语法,能够定义Type, Enum, Input, Fragment, Query, Mutation等元素,熟悉 Typescript 的朋友会对此感到亲切。而在前端开发中需要重点关注的是以下几个部分:

阅读更多
打包发布 React 组件库

打包发布 React 组件库

起因

「代码写了不测等于白写」我总是跟身边的朋友这样调侃。然而我们写前端项目时很难在代码层面进行测试,大部分函数都是基于事件响应,接收用户输入的参数,并对页面组件或数据产生一定副作用,Mock 起来很麻烦。所以前端项目的测试往往都是端到端测试,即模拟用户在页面上进行操作,测试路径越离奇越好,因为无法提前预知用户会如何使用,所以最好在测试时可劲儿造。

曾经还会想着用 Cypress 等自动化工具进行端到端测试,例如用代码定义【打开某页面–>拖拽滑动条至页面下方–>点击输入框使之获取焦点–>输入“Hello world”–>按下回车–>等待页面响应–>观察响应是否符合预期】这个过程,但只要遇到元素稍多的页面,编写测试用例的过程就会变得机械呆板。

如果组件足够小,内容够聚焦,那么测一下也不是不可以。因为想在不同的项目中复用同一套富文本编辑组件(体积比较大,且包含机器构建的 JS),我把它单独提出来作为 NPM 包发布以便各个项目安装使用。这当中编码和测试都遇到了一些问题。

阅读更多

Nginx 基础

背景

Nginx 读作 engine x,是一个高性能的 HTTP 和反向代理服务器,还能用作邮件代理服务器或是通用的 TCP/UDP 代理服务器。有过后端程序部署经历的同学应该会有所了解,用 Nginx 能够很方便地完成反向代理、服务静态文件、实现负载均衡、接入 HTTPS 协议等任务。

根据官方文档里面写到的,除了提供静态文件服务、反向代理和负载均衡等功能之外,还提供以下包括单不限于若干个方面的支持:

  1. FastCGI, uwsgi 之类服务器和反向代理服务器的缓存支持;
  2. 以域名/IP 为基础的虚拟服务器、Keep-alive 和流水线链接的支持;
  3. 访问日志、错误日志的输出和格式化,带缓存的日志写机制;
  4. 3xx-5xx 错误码重定向,根据正则表达式重写 URI (Rewrite);
  5. 基于客户端地址的访问控制和函数调用;
  6. HTTP referer 的验证、支持除了 GET 外的几种 HTTP 方法: PUT/DELETE/COPY/MOVE/MKCOL;
  7. FLV/MP4 的流播放、响应限流、限制单点的并发连接数和请求数;
  8. 等等…(上面只列了我读得懂的)

Nginx 的功能实在太多了,在这里全部列出来不太可能。一直以来我对 Nginx 都停留在“配置是什么,work 就行”的态度。因为这周程序部署时遇到的一点问题,上网搜了好多帖子、博客寻求解决方法那种捉襟见肘、有病乱投医的样子让我觉得很狼狈。借此为契机,决定周末看一下 Nginx 的官方文档。nginx 旧版的官网文档组织混乱,建议移步 Nginx Plus (Nginx 的商业版)官网。Nginx 和 Nginx Plus 的对比放在这里

阅读更多