道与术:程序员的内功心法
November 29, 2024 by walter
在软件开发的江湖中,C/C++ 和 Java 就像少林与武当,一个偏向“硬功夫”,刀枪棍棒样样能打;另一个更讲究“以柔克刚”,推崇灵活多变的内功。而 Python、Go 和 Rust 则是近年崛起的少年高手,一个擅长速成、一个拥抱云原生,还有一个以内存安全闻名,都在争夺编程江湖的“武林盟主”之位。 尤其是在企业开发的武林中,Java 堪称“中原武林盟主”,它的招式(术)浩如烟海,从简单的“打狗棒法”(工具类库)到深奥的“九阴真经”(分布式架构)。门下弟子修炼轮子(第三方库)无数。然而,纵然 Java 的术法浩如烟海,如果只沉迷于术,终究如蜻蜓点水,难入武道真谛。只练招式不修内功,就像拿着绝世神兵却没有力气挥动,最终难逃江湖纷争的淘汰法则。 正如古人所言:“术乃器,道为心。器可换,道难变。” 术是什么?术是刀枪剑戟的武器。 术是工具、框架、库、配置文件。你可以把术看成是你手中的菜刀,某个问题来了,直接拿出来用,快速解决,效率拉满。 比如: • Spring:一个开箱即用的武林秘籍,简直是厨师的多功能锅,煎炒烹炸样样行。 • MyBatis:数据库操作的助力,能让你用 SQL 潇洒如风,甚至可以用 XML 来写代码。 • Spring Security:防盗、防抢、防 SQL 注入三件套。 • WebFlux:响应式编程的“闪电五连鞭”,性能杠杠的。 术学起来很爽,用起来很炫,解决问题很快,但如果你只会用术,可能就像一个拿着高级武器但内功薄弱的武者,风吹草动就可能翻车。 道是什么?道是你的内功心法。 道是一种理念、一种本质,超脱于术之上。它是程序员的大局观,是问题背后的普适法则。懂得了道,你就能从根本上理解术为什么存在、怎么优化甚至怎么重写它。 比如: • 依赖注入和控制反转(IoC) 是道,理解了它,你就能明白 Spring 为何如此设计。 • ORM 的本质 是道,懂了它,你就知道 JPA 和 MyBatis 的优劣。 • CAP 理论 是道,掌握了它,分布式系统中的“妥协艺术”尽在掌握。 • 响应式编程的多路复用原理 是道,搞懂了它,WebFlux […] →Read more
pydantic 对象的陷阱
November 29, 2024 by walter
陷阱 在 Python 中,类成员在所有实例之间是共享的,例如以下代码,friends 是一个类成员(而不是实例成员),所有 User 实例都会共享同一个 friends 列表。也就是说,对一个实例的 friends 列表进行修改,会影响到其他实例的 friends 列表。 这是因为 friends 是在类定义时定义的,是一个类级别的属性。 示例代码 from datetime import datetime from pydantic import BaseModel class User(BaseModel): id: int name: str = "Walter Fan" signup_ts: datetime | None = None friends: list[int] = [] user1 = User(id=1) user2 = User(id=2) user1.friends.append(2) print(user1.friends) # [2] print(user2.friends) […] →Read more
奇异模板模式(Curiously Recurring Template Pattern)
November 27, 2024 by walter
在 C++ 中,“奇异模板”(Curiously Recurring Template Pattern, 简称 CRTP)是一种常用的模板编程技巧,主要用于实现静态多态(static polymorphism)或为派生类提供通用的功能。它的名字来源于其递归的结构:一个类使用自己作为模板参数传递给基类。 CRTP 的基本结构 CRTP 的核心是定义一个基类模板,并让派生类作为模板参数传递给这个基类。 基本代码示例 #include <iostream> // 基类模板 template <typename Derived> class Base { public: void interface() { // 调用派生类的方法 static_cast<Derived*>(this)->implementation(); } // 默认实现(可选) void implementation() { std::cout << "Base implementation\n"; } }; // 派生类 class Derived : public Base<Derived> { public: void implementation() { […] →Read more
革命人永远是年轻
November 25, 2024 by walter
你有信仰就年轻,疑惑就年老。 有自信就年轻,畏惧就年老。 有希望就年轻,绝望就年老。 岁月刻蚀的不过是你的皮肤, 但如果失去了热忱, 你的灵魂就不再年轻。 →Read more
如何组织你的 jupyter notebook
November 24, 2024 by walter
在一个 Jupyter Notebook 中引用另一个 Notebook 的 Python 函数或类有以下几种常见方法。选择合适的方法取决于你的需求和项目结构: 方法 1: 使用 import_ipynb 模块 这是专门为导入 Jupyter Notebook 中的代码而设计的方法。 1. 安装 import_ipynb pip install import-ipynb 2. 导入另一个 Notebook 假设有一个 helper_functions.ipynb,你想在当前 Notebook 中使用它的内容。 import import_ipynb import helper_functions # 使用 helper_functions 中定义的函数或类 result = helper_functions.some_function() my_class = helper_functions.SomeClass() 方法 2: 将 Notebook 转换为 Python 文件 将另一个 Notebook 转换为 .py […] →Read more
编程语言的边界
November 23, 2024 by walter
最近重新复习了 Java 这门我曾经非常熟悉的语言 , 翻阅到 Bruce Ekecl 的 ON JAVA 一书, 他在卷首就引用了维根斯坦(Ludwig Wittgenstein)的名言: ‘The limits of my language means the limits of my world.’ 我的语言的局限即我的世界的局限. 作为程序员, 一种语言会悄然无息的引导你进入某种思维模式, 同时远离其他思维模式. 看到这里, 我深有同感, 我现在用的最多的编程语言是 Python , 而 C++ , Java 和 JavaScript 也是我熟知的语言, 我用它们来谋生, 写过许多正式项目和 side project. 在语言之间我也曾经有过好恶, 对 JavaScript 我还写过一篇吐槽的文章 C++程序员眼中丑陋的 JS 可是随着年岁的增长, 我也渐渐领悟到不应局限于语言的边界, 很多编程语言为了解决机器语言的复杂性, 引入了更多的自身的复杂性, 当看到 […] →Read more
如何解决大模型的“幻象问题”
November 21, 2024 by walter
大模型的“幻象问题”是指它们生成的回答可能看起来合理但实际上错误或虚构的现象,也被称为“AI 幻觉” (AI hallucination)。这种问题的根源在于大模型是概率生成模型,缺乏对事实的真正理解或对内容的验证能力。以下是一些可能的解决策略: 1. 提供高质量的上下文 大模型的输出质量高度依赖输入内容。如果输入信息模糊或不完整,模型容易生成虚构的回答。 解决方法 明确提示 (Prompt Engineering): 设计更具体、更详细的问题,减少模型的推测空间。 示例: 错误:解释一下宇宙的起源。 改进:根据当前主流科学理论解释宇宙的起源,例如大爆炸理论。 提供上下文:将相关的事实或背景信息直接提供给模型。 示例:在提示中明确说明所用的数据来源,例如 “基于 2021 年的全球人口统计数据”。 2. 结合外部知识库 大模型本身没有实时更新的知识,但可以通过结合外部知识库或 API 来增强准确性。 解决方法 知识增强 (Retrieval-Augmented Generation, RAG): 使用像 Pinecone、Weaviate 或 Elasticsearch 的向量数据库存储知识,然后根据输入从数据库中检索相关内容,再将其提供给模型生成回答。 示例工具: LangChain: 支持从外部知识库检索信息并增强生成内容。 Haystack: 支持文档检索和基于上下文的生成。 检索工具集成: 通过搜索引擎或领域专用的 API 来验证模型的生成内容。 3. 设置事实验证机制 在生成结果后,通过额外的步骤验证其准确性。 解决方法 事实检查模块: 在生成答案后,添加一个独立的模块验证模型输出是否与真实信息一致。 示例: 使用规则库、专家系统或查询外部数据库对模型生成内容逐项核实。 链式推理验证: 模型可以逐步输出推理过程,每一步都进行自检或外部验证。 示例:通过 […] →Read more
Deep path traversal algorithms
November 21, 2024 by walter
Overview Graph algorithms are a set of instructions that traverse (visits nodes of) a graph and find specific nodes, paths, or a path between two nodes. Some of these algorithms are built into Memgraph and don’t require any additional libraries: Depth-first search (DFS) Breadth-first search (BFS) Weighted shortest path (WSP) All shortest paths (ASP) Reference […] →Read more
OIDC Review
November 19, 2024 by walter
What’s OIDC OpenID Connect(OIDC)是基于 OAuth 2.0 规范框架(IETF RFC 6749 和 6750)的可互操作身份验证协议。允许客户端(如 Web 应用、移动应用等)通过验证用户身份并获取基本的用户信息,来进行安全的用户认证和授权。 对于开发人员来说,它为“当前使用连接的浏览器或移动应用程序的人的身份是什么”这个问题提供了一个安全且可验证的答案。最重要的是,它消除了设置、存储和管理密码的责任,这通常与基于凭据的数据泄露有关 OAuth 2.0 是关于资源访问和共享的,而 OIDC 是关于用户身份验证的。它的目的是为你提供多个站点的一次登录名。 OpenID Connect 的角色有下面三个: 身份提供者 (Identity Provider, IdP):身份提供者,负责用户身份认证,发布授权码和令牌,验证令牌有效性。常见的 IdP 有 Google、Facebook 等。 客户端 (Client):需要获取用户身份信息的应用程序,例如 Web 应用、移动应用等。 终端用户 (End User):使用客户端应用并希望通过身份提供者进行身份认证的用户。 它的流程步骤如下实体关系图所示 EndUser:请求访问客户端应用。 Client:重定向用户到身份提供者(IdP)进行身份认证。 IdP:认证用户身份。 EndUser:提供认证凭证。 IdP:返回授权码给客户端应用。 Client:使用授权码向身份提供者请求访问令牌和 ID 令牌。 IdP:发布访问令牌和 ID 令牌给客户端应用。 Client:使用令牌为用户提供访问资源的权限。 Client:可以选择性地向身份提供者验证令牌的有效性。 通过这些流程,OpenID Connect 协议实现了安全的用户身份认证和授权,确保用户能够安全地访问客户端应用所提供的资源。 Reference […] →Read more
OAuth 详解
November 18, 2024 by walter
Problem 核心问题: "我怎样才能允许应用程序访问我的数据而又不必向其提供密码?" OAuth 是 REST/API 的委托授权框架。它允许应用获得对用户数据的有限访问权限(范围),而无需泄露用户的密码。它将身份验证与授权分离开来,并支持针对不同设备功能的多种用例。它支持服务器到服务器的应用、基于浏览器的应用、移动/本机应用以及控制台/电视。 您可以将其视为酒店钥匙卡,但适用于应用程序。如果您有酒店钥匙卡,则可以进入您的房间。如何获取酒店钥匙卡?您必须在前台进行身份验证才能获得它。通过身份验证并获取钥匙卡后,您可以访问整个酒店的资源。 简单来说,OAuth 是 (以照片打印程序 PhotoApp 为例) 应用程序向用户请求授权: PhotoApp 向 Alice 请求要访问 Alice 的照片 用户授权App并提供证明: PhotoApp 向 Alice 申请我授权访问她的 QQ 相册, 而 Alice 授权 PhotoApp 这一请求 应用程序向服务器提供授权证明以获取令牌: PhotoApp 向 QQ 相册提供 Alice 的授权证明 Token 仅限于访问用户为特定应用授权的内容 QQ 相册发给 PhotoApp 访问 Alice 相册图片的访问令牌 access token OAuth 流程中的参与者如下: 资源所有者 Resource Owner(RO):拥有资源服务器中的数据。例如,Alice 是她的 […] →Read more