今日已更新 160 条资讯 | 累计 24117 条内容
关于我们

标签:#tutorial

找到 440 篇相关文章

AI 资讯

为什么使用代理总弹出“安全验证”?深度解析 Cloudflare 拦截机制与避坑指南

为什么使用代理总弹出“安全验证”?深度解析 Cloudflare 拦截机制与避坑指南 在互联网开发、跨国办公或日常浏览中,使用代理(如 VPN、机场、Socks5、OpenVPN/WireGuard 协议等)已经是不可或缺的技能。 然而,许多人在开启代理后,访问国外网站(如 Dev.to、GitHub、Medium 等)时,频繁遭遇如下提示: Performing security verification This website uses a security service to protect against malicious bots. This page is displayed while the website verifies you are not a bot. 甚至更让人崩溃的是,有时候点击了验证码,它依然不断刷新,陷入 无限验证死循环 。这并不是你的系统或浏览器损坏了,而是代理网络的特性触发了现代 Web 安全防御机制。本文将从技术原理深入拆解这一现象,并提供切实可行的优化方案。 一、 核心原理:网站安全服务是如何盯上你的? 现代网站大多会部署 Cloudflare(如 Turnstile 验证) 、Akamai、Imperva 等网络安全与防 DDoS 攻击服务。这些服务通过以下几个维度来评估访问者是“真实人类”还是“恶意机器人(Bot)”: 1. IP 信誉度(IP Reputation)与“连坐”机制 这是最核心的技术原因。代理服务商(特别是商业 VPN 或公共机场)所使用的 IP 地址,绝大多数属于 数据中心(Data Center)机房 IP ,而非普通家庭的 住宅(Residential)IP 。 高密度共用: 同一个代理 IP 节点上,可能同时有成百上千个用户在发起请求。 黑名单牵连: 如果该 IP 下的其他匿名用户正在使用自动化脚本抓取数据、进行端口扫描,或者发起恶意网络攻击,安全系统的风控引擎(如 Cloudflare IP Threat Score)就会瞬间拉高该 IP 的风险等级。当你恰好切换到这个“脏 IP”时,就会被系统无差别“连坐”,要求强制验证。 2. 被动指纹识别(Passive Fingerprinting)与几何特征 安全防御系统不仅看你的 IP 归属地,还会通过深层网络和浏览器几何特征来判断你的真实身份: TLS/SSL 握手特征(JA3 指纹): 当你通过一些特定协议或混淆模式(如带有特定加密的 TCP 隧道)连接网站时,浏览器发出的 TLS 握手特征可能会发生形变。 TCP/IP 栈特征: 经过代理服务器的转发,数据包的 TTL(生存时间)、Window Size(TCP 窗口大小)等底层参数可能会与你浏览器宣称的操作系统(如 Windows 11 或 Ubuntu 24.04)的标准特征不匹配。 浏览器画布与几何指纹(Canvas/Geometry): 浏览器的窗口大小、屏幕分辨率以及它们的比例,也是风控系统评估的重要指标。 自动化爬虫脚本(如 Selenium、Puppeteer)在启动时,常常使用死板的默认分辨率(如完美的 1024x768 或 800x600 )。如果你的代理 IP 本身信誉度低,窗口又处于这些“机器人专属分辨率”下,或者网页窗口大小与物理显示器分辨率比例极其诡异(例如伪造环境时穿帮),就会直接触发拦截。 3. 环境与地缘标签冲突(以 Yandex 浏览器为例) 风控系统对你使用的浏览器品牌同样有一套风险权重评估。 如果你使用的是 Yandex 浏览器 或某些小众、经过重度隐私魔改的浏览器,在配合代理时会变得 极其难通过验证 。Yandex 浏览器虽然基于 Chromium 内核,但其内部由俄罗斯团队集成了大量独特的隐私保护技术与 Canvas 渲染机制,计算出的浏览器指纹非常非主流。 更致命的是 地缘标签冲突 :欧美的主流网络安全公司(如 Cloudflare)对特定区域标签的客户端流量天然设置了更低的信任阈值。当你 用着 Yandex 浏览器 ,IP 却 挂着美国或日本的代理 时,这种“指纹与地理位置的剧烈冲突”在风控模型眼里极度反常,系统会判定该请求大概率来自自动化黑客工具,从而直接卡死验证。 4. 地理位置与行为“瞬移” 如果你的代理客户端开启了“负载均衡”或“定时自动切换节点”,可能会导致前一分钟请求来自日本,后一分钟请求来自美国。这种超越物理极限的“空间瞬移”属于高风险异常行为。此外,如果通过代码 瞬间改变 窗口尺寸,而非人类拖拽时产生的连续 resize 事件,也会被风控脚本捕捉到异常。 二、 实战优化:如何彻底摆脱“无限验证”死循环? 要彻底解决或缓解这个问题,可以根据实际的使用场景,从 节点筛选 、 路由分流 以及 浏

2026-05-30 原文 →
AI 资讯

SQL Pattern Series #1: The Presence Pattern

Thinking in terms of existence instead of lists SQL Pattern Series #1 of 21 A collection of practical SQL patterns that help developers recognize common solutions to recurring database problems. What You'll Learn In this article you'll learn: When EXISTS and IN solve the same problem The difference between set membership and existence Why the underlying mental model matters When I typically reach for EXISTS Most SQL developers write a query like this at some point: SELECT c . CustomerID , c . CustomerName FROM Customers c WHERE c . CustomerID IN ( SELECT o . CustomerID FROM Orders o ); And it works. But sometimes it isn't the best way to think about the problem. The Question Behind the Query Many SQL problems can be framed in two different ways. Set Membership Is this value in a set? WHERE CustomerID IN (...) Existence Does at least one matching row exist? WHERE EXISTS (...) Both approaches often return the same result. But they represent different mental models. The Presence Pattern The Presence Pattern is useful when you do not actually care about the values being returned from a related table. You only care whether a matching row exists. For example: Customers who have placed an order Users who have logged in Employees assigned to a project Products that have sales In these cases, the question is often: Does a related row exist? rather than: What values are contained in this list? Example Using EXISTS SELECT c . CustomerID , c . CustomerName FROM Customers c WHERE EXISTS ( SELECT 1 FROM Orders o WHERE o . CustomerID = c . CustomerID ); The subquery is correlated to the outer query. Conceptually, SQL asks: For this customer, does at least one matching order exist? As soon as the answer becomes true, the condition is satisfied. Why This Pattern Matters Many SQL developers initially learn syntax. Over time, they discover that query writing is really about choosing the right mental model. The Presence Pattern encourages you to think in terms of: existence relationshi

2026-05-30 原文 →
AI 资讯

Environment Variables in Node.js: The Complete Guide (2026)

Environment Variables in Node.js: The Complete Guide (2026) Environment variables are the standard way to configure apps across environments. Here's how to use them correctly. What and Why What: Key-value pairs set outside your application code Where: OS environment, .env files, CI/CD config, container orchestration Why: → Separate config from code (12-Factor App methodology) → Same code runs everywhere (dev, staging, production) → Secrets never committed to git → Easy to change behavior without redeploying Reading Env Vars in Node.js // Method 1: process.env (built-in, always available) const port = process . env . PORT || 3000 ; const dbUrl = process . env . DATABASE_URL ; const apiKey = process . env . API_KEY ; // ⚠️ process.env values are ALWAYS strings! const timeout = parseInt ( process . env . TIMEOUT , 10 ) || 5000 ; const debug = process . env . DEBUG === ' true ' ; const maxRetries = Number ( process . env . MAX_RETRIES || ' 3 ' ); // Method 2: dotenv (most popular approach) // npm install dotenv import ' dotenv/config ' ; // Loads .env into process.env automatically // Now process.env has all your .env variables! // Or explicit load: import dotenv from ' dotenv ' ; dotenv . config ({ path : ' .env.local ' }); // Custom file path // Method 3: env-cmd (for package.json scripts) // "dev": "env-cmd -f .env.dev node server.js" // "prod": "env-cmd -f .env.prod node server.js" // Method 4: tenv / enve (type-safe alternatives) import { env } from ' tenv ' ; const port = env . number ( ' PORT ' , 3000 ); // Type-safe with default const dbUrl = env . string ( ' DATABASE_URL ' ); // Required, throws if missing const debug = env . bool ( ' DEBUG ' , false ); // Boolean parsing The .env File Ecosystem # .env (committed to git with defaults) NODE_ENV = development PORT = 3000 LOG_LEVEL = debug # .env.local (NOT committed! Gitignored) # Contains local overrides and secrets DATABASE_URL = postgresql://localhost/myapp_dev API_KEY = sk_test_local_key JWT_SECRET = local-de

2026-05-30 原文 →
AI 资讯

Dynamic Workflows in Opus 4.8: Build a Self-Verifying PR Reviewer

You stopped being the loop Most people use Opus 4.8 the way they used every model before it: open a chat, type a request, watch the cursor, correct it, repeat. That's a conversation. A dynamic workflow is something else entirely. The shift is this: you stop being the loop. Instead, an orchestrator — plain code you control — spawns subagents you design, fanning out work in parallel, running steps in sequence, judging and merging results, and reporting back when the whole thing is done. Opus 4.8 can drive hundreds of parallel subagents inside a single workflow, with effort control per node so cheap steps stay cheap and hard steps think harder. In this tutorial you'll learn the core patterns by building one concrete thing: a pull-request reviewer that fans out across correctness, security, and performance, then adversarially verifies every finding before it reaches you. // You design the shape. The orchestrator runs it. const found = await parallel ( DIMENSIONS . map ( d => () => agent ( d . prompt , { schema : FINDINGS }))) const deduped = dedupeByFileLine ( found . flatMap ( r => r . findings )) const verified = await parallel ( deduped . map ( f => () => agent ( refutePrompt ( f ), { schema : VERDICT }))) const real = verified . filter ( v => v . refuted === false ) By the end you'll know when to reach for parallel() versus pipeline() , how structured output schemas keep subagents composable, and where to set effort per node. The mental model: it's a graph, not a prompt Stop thinking "I send a prompt, I get a completion." Start thinking: an orchestrator runs a workflow graph, and each node is an agent call. The orchestrator is plain code. It decides what runs, in what order, and what to do with each result. Subagents are the leaf workers — each gets a focused prompt, a structured-output schema, and its own effort setting. The unit of work is no longer the prompt; it's the graph. Two primitives compose every graph, and the difference between them is entirely about ba

2026-05-30 原文 →
AI 资讯

Advanced Hooks & State Management Patterns in React

Read Time: ~14 minutes | Building on React fundamentals to master state management at scale Prerequisites : Familiarity with React basics, useState, useEffect (Part 1) 🔗 Series Navigation ← Part 1: Complete Guide from Zero to Production Part 2: Advanced Hooks & State Management ← YOU ARE HERE → Part 3: Performance Optimization (coming next) 📌 What You'll Learn By the end of this guide, you'll understand: ✅ Creating powerful custom hooks ✅ When and how to use useReducer ✅ Managing state globally with Context API ✅ Redux fundamentals and when to use it ✅ Modern alternatives: Zustand and Jotai ✅ Choosing the right pattern for your project ✅ Real-world shopping cart implementation 🎣 Custom Hooks: Reusing Logic Across Components Custom hooks are regular JavaScript functions that let you extract component logic into reusable functions. They're one of the most powerful React patterns. Rule #1: Custom Hooks Must Start with "use" // ✅ Correct - starts with "use" function useFormInput ( initialValue ) { const [ value , setValue ] = useState ( initialValue ); return { value , bind : { value , onChange : e => setValue ( e . target . value ) }, reset : () => setValue ( initialValue ) }; } // ❌ Wrong - doesn't start with "use" function formInput ( initialValue ) { ... } Example #1: useFormInput Hook import { useState } from ' react ' ; function useFormInput ( initialValue = '' ) { const [ value , setValue ] = useState ( initialValue ); return { value , setValue , bind : { value , onChange : e => setValue ( e . target . value ) }, reset : () => setValue ( initialValue ) }; } // Using the custom hook function LoginForm () { const email = useFormInput ( '' ); const password = useFormInput ( '' ); const handleSubmit = ( e ) => { e . preventDefault (); console . log ( email . value , password . value ); email . reset (); password . reset (); }; return ( < form onSubmit = { handleSubmit } > < input {... email . bind } placeholder = " Email " type = " email " /> < input {... password .

2026-05-29 原文 →
AI 资讯

Rest Template - API for developers- Spring Boot

RestTemplate is a synchronous Spring Framework client used to consume RESTful web services by simplifying HTTP communication. Synchronous Communication: It blocks the execution thread until a response is received.HTTP Methods: It provides built-in methods for standard operations like GET, POST, PUT, and DELETE.Automatic Mapping: It can automatically convert JSON or XML responses into Java domain objects using message converters.Status: While widely used, it is in maintenance mode. For new projects, Spring recommends using the modern RestClient or the reactive. Its an automate work. getForObject() Performs a GET request and returns the response body directly as an object. getForEntity() Performs a GET request and returns a ResponseEntity (includes status and headers). postForObject() Sends data via POST and returns the mapped response body. exchange() A general-purpose method for all HTTP verbs, offering full control over headers and request entities. getForObject- Controller Snippet Response is received in Object format. @RestController @RequestMapping("/api") public class ApiController { @Autowired private ApiService apiService; @GetMapping("/getUsers") public String users() { return apiService.getUsers(); } Service snippet: @Service public class ApiService { @Autowired private RestTemplate restTemplate; @Autowired UserApiRepo userApiRepo; public String getUsers() { String url = "https://jsonplaceholder.typicode.com/users"; String response = restTemplate.getForObject(url, String.class); return response; } Response: "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "Sincere@april.biz", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" } getForEntity() Respo

2026-05-29 原文 →
AI 资讯

How to Route Real-Time Gold and Silver Prices from a Unified WebSocket Stream

When I first connected to a precious metals WebSocket API, I expected to get a clean stream of prices. What I actually got was a firehose of mixed ticks—gold, silver, platinum—all arriving through the same callback. If you’ve ever tried to build a trading bot or a custom chart, you know this is a recipe for disaster. In this post, I’ll share how I solved the problem with a few lines of Python and a clear mapping strategy. The scenario: You have one WebSocket URL that pushes quotes for multiple metals. You need to separate them so you can update different UI components, run independent strategies, or store them in distinct database tables. The data pain point: every message uses the same JSON structure, and the only differentiator is a field like symbol . If you don’t act on it immediately, everything gets mixed up. Identify Assets via the Symbol Field Start by checking the API docs for the field that carries the instrument code. Usually it’s symbol , but instrumentId or type are also used. Here’s a typical reference table: Field Description Example symbol Asset code XAUUSD, XAGUSD instrumentId Internal platform ID 1001, 1002 type Asset class gold, silver I turn this into a dictionary mapping each symbol to a human-readable category: asset_map = { " XAUUSD " : " gold " , " XAGUSD " : " silver " , " XPTUSD " : " platinum " } Buffer Messages by Type Because these streams are high-frequency, I avoid processing every tick individually. Instead, the WebSocket callback just updates an in-memory store that is already grouped by asset type: # Keep the hot path extremely light def on_message ( msg ): symbol = msg [ ' symbol ' ] price = msg [ ' price ' ] asset_type = asset_map . get ( symbol , " unknown " ) cache [ asset_type ][ symbol ] = price Then, a background timer fetches the latest prices from cache["gold"] and cache["silver"] separately and does the actual work—like computing indicators or rendering charts. The key benefit is complete isolation: your gold logic never t

2026-05-29 原文 →
AI 资讯

Building a Custom API Using PL/SQL with ORDS

In modern application development, exposing database logic as REST APIs is a powerful way to integrate systems. Oracle REST Data Services (ORDS) makes it easy to turn PL/SQL into RESTful APIs without needing a separate backend service. In this blog, we’ll walk through how to create a simple POST API using ORDS and PL/SQL to insert data into a table. Pre-requisites A cloud-based ATP wallet (I prefer) Let's start how we create the APIs on the top of any custom table which relies on databases Create a table in the oracle SQL Developer and followed by create an ORDS Module 1.Create an ORDS Module A module is a logical container for related REST endpoints. What this Module does ?? Creates a module named nj_api Defines base URL: http://server_name/ords/table_Schema/nj_api/ 2: Define a Template (Endpoint Path) A template represents the API endpoint path. It defines how Endpoint URL:/ords/table_schema/nj_api/insert_data 3: Define the Handler (Business Logic) The handler contains the logic executed when the API is called. Key Concepts: p_method => 'POST': Defines HTTP method p_source_type => ORDS.source_type_plsql: Uses PL/SQL block Bind variables (:name, :num, etc.) map directly to JSON request body parameters 4: Testing the API Using Tools like Postman,cURL,ORDS REST Workshop I tested with Postman FYR Let's call same in Oracle VBCS in new blog. .. Try other methods like Delete, PATCH & GET

2026-05-29 原文 →
AI 资讯

Python Day Three – Lists, Indices, and Packing Your Virtual Backpack 🎒

Welcome back to Day 3, Python dynamic duo! 🚀 If you survived Day 2 , you now know how to create variables and throw strings, integers, floats, and booleans into their own little cardboard boxes. 📦 But what happens when you’re building a game and your character needs an inventory? Or you're making a shopping list app? Creating 50 different variables like item1, item2, item3 will make you want to throw your router out the window. 🪟💻 Today, we are leveling up our storage game. We are moving out of single cardboard boxes and packing a Virtual Backpack: Enter Lists! 🎒🎉 🎒 What is a List? In Python, a List is a data structure used to store a collection of items in one single variable. Think of it like a backpack where you can stuff multiple things inside, keep them in a specific order, and pull them out whenever you need them. Creating a list is simple. You use square brackets [] and separate your items with commas: # Packing our survival backpack 🗺️ backpack = [ " map " , " flashlight " , " water bottle " , " protein bar " ] print ( backpack ) # Prints: ['map', 'flashlight', 'water bottle', 'protein bar'] The coolest part? Python lists don’t care what you put inside. You can mix strings, integers, and booleans all in one single backpack (though usually, it makes the most sense to keep similar things together). 🤯 The First Rule of Coding Club: We Start Counting at Zero! Here is where programming turns your brain upside down. 🧠🙃 If I asked you what the first item in our backpack list is, you’d logically say "map". And you'd be right in human language. But in Python-speak, computer memory starts counting at 0. This is called Indexing. To pull a specific item out of your backpack, you write the name of the list followed by the item's position (index) inside square brackets: backpack = [ " map " , " flashlight " , " water bottle " , " protein bar " ] # Pulling out the items using their index 🔍 print ( backpack [ 0 ]) # Prints: map (The absolute first item!) print ( backpack [

2026-05-29 原文 →
AI 资讯

Gas Optimization Part 4: Solidity Tips for Cheaper Contracts

Every line of your smart contract costs something. Some lines cost more than others. In this part of our gas saving series, we’ll explore how to write smarter Solidity code that keeps your contract lean and efficient. Here are six simple and practical ways to reduce gas costs while writing Solidity smart contracts. 1. Use payable Only When Needed, But Know It Saves Gas In Solidity, a function marked payable can actually use slightly less gas than a non-payable one. Even if you're not sending ETH, the EVM skips some internal checks when the function is marked payable. See this example: function hello() external payable {} // 21,137 gas function hello2() external {} // 21,161 gas That tiny difference may not seem like much, but across thousands of calls, it adds up. Only use payable when your function is actually meant to accept ETH 2. Use unchecked for Safe Arithmetic When You’re Sure Since Solidity 0.8.0, all arithmetic operations automatically check for overflows and underflows. While this makes contracts safer, it also uses extra gas. When you're certain that overflow won't occur, you can use the unchecked keyword to skip these safety checks. uint256 public myNumber = 0; function increment() external { unchecked { myNumber++; } } Gas used: 24,347 (much cheaper than using safe math) Warning: Use unchecked carefully. Only when you're confident there's no risk of overflow. 3. Turn On the Solidity Optimizer The Solidity Optimizer is like a smart helper that cleans up and tightens your compiled bytecode. It does not change how your contract works, but it removes waste and makes it cheaper to run. If you’re using tools like Hardhat or Remix, always enable the Optimizer before deploying to mainnet. 4. Use uint256 Instead of Smaller Integers (Most of the Time) Smaller types like uint8 or uint16 might look more efficient, but they can cost more gas during execution. That’s because the EVM automatically converts them to uint256 behind the scenes. So, if you're not tightly p

2026-05-29 原文 →
AI 资讯

Building a Resume Download Gate: Email Collection, Signed Tokens, and an S3 Lesson

I wanted a soft gate on my resume download. Not a paywall. Just an email field — enough friction to filter bots, enough signal to know who's interested. What started as a straightforward feature turned into a three-part lesson: stateless token signing, S3 public access, and email delivery mechanics. Here's the full story. The Feature The flow I wanted: Visitor clicks "Download Resume" on the About page or Hero A modal asks for their email Backend validates the email (format + disposable domain check) A signed, time-limited link is emailed to them They click the link, the PDF opens No database tokens. No cron jobs. No permanent S3 URLs floating around. Part 1 — The Model and the Gate The Resume Model Resume follows the singleton pattern I already use for page headers — force pk=1 on every save, restrict add/delete in admin. One row, forever. class Resume ( models . Model ): pdf = models . FileField ( upload_to = " resume/ " , storage = private_resume_storage ) last_updated = models . DateField ( default = date . today ) def save ( self , * args , ** kwargs ): self . pk = 1 super (). save ( * args , ** kwargs ) ResumeDownloadRequest logs every email that requests a link — no tokens, no expiry columns, just a record of who asked and when. class ResumeDownloadRequest ( models . Model ): email = models . EmailField () created_at = models . DateTimeField ( auto_now_add = True ) unsubscribed = models . BooleanField ( default = False ) class Meta : ordering = [ " -created_at " ] The unsubscribed flag is there for a future newsletter broadcast — when a new blog post goes out, skip anyone who opted out. Blocking Disposable Emails Before signing anything, the email is checked against a frozenset of ~70 known throwaway domains: # core/validators.py DISPOSABLE_EMAIL_DOMAINS : frozenset [ str ] = frozenset ({ " mailinator.com " , " guerrillamail.com " , " yopmail.com " , " 10minutemail.com " , " trashmail.com " , # ... ~70 total }) def is_disposable_email ( email : str ) -> bool

2026-05-29 原文 →
AI 资讯

Git for GitHub: How to use simple Git commands to manage a GitHub repository

Recently, I was working on creating a website on a cloud-based IDE (CodeHS). One night, I was editing, and then when I was done, I simply turned off my monitor and disabled my mouse and keyboard. Then, the next day at school, I continued to work on the website, and made significant changes. When I got home, I made more significant changes, but then realized something very important. What I realized is that when I continued to work on the project at home, the cloud-based IDE hadn't refreshed to the new code, and overwrote the work I did at school when I saved my new work. So, what is the purpose of me telling you this? Is it to say that you should always close your code editor when you're done working, or some other trick to prevent this from happening? No, it definitely is not. After the initial panic, I realized that the cloud-based IDE had a history section, which has a detailed log of every change that happened to every file. I then looked back at my old copy, copied the changes, and put them back into my new code. Now, imagine you aren't using a cloud-based IDE, and your just editing a file on your computer, in an IDE, or simply your terminal. To clarify, Git is not cloud-based, it is local, (sitting on your computer), that connects to the cloud (GitHub). What happens when something breaks? For some environments, this could be catastrophic, and make you loose a lot of work. When you make an update to a file, the last state and all the states before it are gone. But, this isn't the only thing that can happen. When you use a version control system (VCS), like Git, you can always go back to your previous commits, (snapshots of your code). The work I almost lost wasn't very important; that work didn't effect anyone, except myself. Imagine what would happen if I was working on something more important, or even just working on something for a job. Before learning how to manage your project, it helps to understand what Git actually is. Git is overwhelmingly the most po

2026-05-29 原文 →
AI 资讯

First 90 days as a junior engineer on an AI-heavy team: what to learn first

You took the offer. The team uses Cursor or Copilot for almost every PR, runs an internal RAG bot over the docs, and at least one senior engineer is building agent workflows on the side. Your onboarding doc is half-written because the person who owned it left, and the codebase has roughly 40% more surface area than the org chart suggests, because LLMs have made it cheap to ship adapters, scripts, and one-off services nobody fully owns. This is the environment most junior engineers walk into in 2026. The traditional advice — read the codebase, ask questions, find a mentor — still applies, but it doesn't tell you what to prioritize when the senior engineers around you are visibly faster than you because they've internalized tools you've never touched. Below is a 90-day plan that assumes you have decent fundamentals (you can write a function, you understand HTTP, you've used git) but you're new to working in a codebase where AI is a first-class collaborator. Days 1-30: read more than you write, and read what the AI reads The biggest mistake juniors make in AI-heavy teams is opening Cursor on day three and trying to ship a feature. You will produce code that compiles, passes the obvious tests, and quietly violates three conventions nobody wrote down. Your PR will get approved by a tired senior because rejecting AI-generated junior code costs political capital. You will learn nothing. Instead, spend the first month doing three things in roughly equal proportion: 1. Read the codebase the way the AI reads it. Look at how the repo is structured for retrieval. Most AI-heavy teams have a CLAUDE.md , .cursorrules , AGENTS.md , or an internal RAG index. These files encode the conventions, the patterns the team wants reinforced, and — critically — the things the team has had to tell the AI not to do . Forbidden patterns are usually the result of an incident. Read them. Ask which incident produced each one. 2. Read closed PRs, not open ones. Open PRs are noisy. Closed PRs from th

2026-05-28 原文 →
AI 资讯

JSON Schema Validator Advanced Techniques for Power Users

Advanced JSON Schema Validator Techniques for Power Users Once you're comfortable with basic validation, these advanced techniques will help you handle complex validation scenarios and integrate validation deeply into your systems. 1. Conditional Validation with if/then/else The most powerful feature in modern JSON Schema is conditional validation. Use it to enforce different rules based on the data itself: { "type" : "object" , "properties" : { "type" : { "type" : "string" , "enum" : [ "individual" , "business" ] }, "taxId" : { "type" : "string" }, "businessName" : { "type" : "string" } }, "allOf" : [ { "if" : { "properties" : { "type" : { "const" : "business" } } }, "then" : { "required" : [ "taxId" , "businessName" ] }, "else" : { "properties" : { "taxId" : { "not" : {} }, "businessName" : { "not" : {} } } } } ] } This schema makes taxId and businessName required only when type is "business". For individual accounts, those fields must not be present. 2. Custom Error Messages with Error Message Extension Enhance validation with user-friendly error messages that guide users toward correct input: { "type" : "object" , "properties" : { "password" : { "type" : "string" , "minLength" : 8 , "pattern" : "^(?=.*[A-Z])(?=.*[0-9])" , "errorMessage" : { "minLength" : "Password must be at least 8 characters" , "pattern" : "Password must contain at least one uppercase letter and one number" } } } } While not part of the core JSON Schema spec, many validators (including AJV) support the errorMessage keyword for better user-facing error reporting. 3. Schema Composition with allOf, anyOf, and oneOf Combine multiple schemas to create sophisticated validation rules: { "allOf" : [ { "$ref" : "#/$defs/baseUser" }, { "$ref" : "#/$defs/withTimestamp" }, { "if" : { "properties" : { "role" : { "const" : "admin" } } }, "then" : { "$ref" : "#/$defs/adminPrivileges" } } ] } allOf: Data must match ALL sub-schemas (intersection) anyOf: Data must match AT LEAST ONE sub-schema (union) oneOf: Da

2026-05-28 原文 →
AI 资讯

Tipos de errores, Wrapping e Inspección en Go

Tabla de Contenidos Objetivo Restricciones de los Errores Basados en Texto Errores Personalizados en Go Conceptos Clave Implementar e Inspeccionar Errores Casos de Uso Comunes Para no morir en el intento y consejos que no pediste Conclusiones del Tema Objetivo Aprender a diseñar tipos de errores personalizados con metadatos de negocio en Go y a propagarlos correctamente a través del flujo de la aplicación sin perder su tipo ni su información de origen. Restricciones de los Errores Basados en Texto En programas sencillos, el uso de errors.New es perfecto. Sin embargo, en aplicaciones empresariales los errores necesitan transportar datos estructurados. Por ejemplo, si una validación de entrada falla, el frontend no solo quiere saber que "hubo un error", necesita saber qué campo exacto falló (ej. email ) y qué regla se violó (ej. formato inválido ). Si solo devolvemos una cadena de texto, la capa superior de nuestra aplicación tendría que parsear el texto del error con expresiones regulares para extraer los metadatos. Esto es extremadamente ineficiente, propenso a errores de formato y acopla la lógica interna a los mensajes de texto visibles al usuario. Tipos de Errores Comunes en Go Antes de analizar cómo propagar y envolver errores, es fundamental comprender los dos patrones principales que se utilizan en Go: Sentinel Errors : Son variables globales predefinidas que representan un estado de error estático y específico. Se definen a nivel de paquete y se comparan directamente por valor. Ejemplos estándar: io.EOF , sql.ErrNoRows . Creación: Generalmente declarados con errors.New (como var ErrNotFound = errors.New("not found") ). Custom Structs (Errores estructurados personalizados): Son estructuras que implementan la interfaz error y contienen campos adicionales para transportar metadatos dinámicos del fallo en tiempo de ejecución (como códigos de estado o parámetros de entrada). Creación: Un struct personalizado que implementa el método Error() (ej. type ValidationErr

2026-05-28 原文 →
AI 资讯

Understanding known_hosts and Host Key Verification: What It Protects Against and How TOFU Works

That "authenticity of host can't be established" message isn't just noise. Here's what's actually happening — and why blindly typing "yes" is a security mistake. Every developer has seen this: The authenticity of host 'example.com (203.0.113.1)' can't be established. ED25519 key fingerprint is SHA256:abc123xyz... Are you sure you want to continue connecting (yes/no/[fingerprint])? Almost everyone types yes without reading it. Then they move on. This message is SSH trying to protect you from one of the most dangerous attacks in network security: the man-in-the-middle attack. Understanding what's happening here — and what the ~/.ssh/known_hosts file actually does — will change how you think about every SSH connection you make. The Problem SSH Is Solving When you connect to ssh user@example.com , how do you know you're actually talking to example.com ? You can't rely on the IP address — IP addresses can be spoofed or rerouted. You can't rely on DNS — DNS can be poisoned. You can't rely on the network path — traffic can be intercepted at any point between you and the server. Without verification, an attacker positioned between you and the server could intercept the connection, pose as the server, decrypt everything you send, re-encrypt it, and forward it along. You'd type your password or authenticate with your key and never know the attacker saw every keystroke. This is a man-in-the-middle (MITM) attack . It's not theoretical. It happens on compromised networks, corporate proxies, malicious Wi-Fi hotspots, and misconfigured infrastructure. SSH's defense is host key verification . Every SSH server has a unique cryptographic identity — its host key. Before you exchange any sensitive data, the server proves it holds the private key corresponding to a public key you've previously verified. If the keys don't match, SSH warns you — loudly. What a Host Key Actually Is When OpenSSH is installed on a server, it automatically generates a set of host key pairs. These live in /etc

2026-05-28 原文 →
AI 资讯

v0 by Vercel Review: AI-Generated React Components That Actually Ship

I opened v0, typed "a settings page with profile editing, notification preferences, and a connected accounts section," and watched it generate a fully functional three-tab settings interface in under 40 seconds. The component used shadcn/ui primitives, Tailwind utility classes, and TypeScript types — the exact stack I would have chosen if I had written it from scratch. I copied the code, pasted it into my Next.js project, changed two import paths, and it rendered correctly on the first try. This is the v0 value proposition distilled: generate UI components that look like a senior frontend developer wrote them, then paste them into your real project without rewriting half the output. After generating 15 components across two weeks of real product work, I can confirm that v0 delivers on this promise more reliably than any general-purpose AI coding tool I have tested. But its scope is narrower than the marketing suggests, and understanding where v0 stops being useful is as important as knowing where it excels. The shadcn/ui Advantage v0 is built on top of shadcn/ui, and this is the single most important fact about how it works. shadcn/ui is not a component library in the traditional sense — it is a collection of copy-pasteable React components built on Radix UI primitives with Tailwind styling. When v0 generates a component, it uses these primitives directly, which means the output is consistent, accessible, and composable. The practical benefit is that v0-generated components integrate with your existing project without introducing a new design system. If you already use shadcn/ui — and a large and growing percentage of Next.js projects do — the generated components reuse your existing Button, Card, Dialog, and Input primitives. v0 just assumes you have them installed and generates code that expects them. If you do not have shadcn/ui in your project, v0 prompts you to run the initialization command before generating anything, which takes about 30 seconds. This archite

2026-05-28 原文 →
AI 资讯

GitHub Copilot Workspace Review: Task-Level AI Coding in the Browser

I tested GitHub Copilot Workspace on 12 real tasks across three repositories in May 2026 — a mix of bug fixes, feature additions, and documentation updates. My goal was to figure out whether the spec-first, browser-based workflow actually produces useful code, or whether it is a demo that falls apart when you ask it to do real work. The answer sits somewhere between impressive and frustrating, with the tool's success rate varying dramatically based on task size, repository maturity, and how well you write the initial specification. The Spec-First Workflow Forces Better Communication Copilot Workspace changes the AI coding interaction in one fundamental way that I have not seen elsewhere: you do not start with code, you start with a specification. When I opened Workspace on a Next.js project and typed "add rate limiting to the API routes using the existing rate-limit.ts utility," the system did not immediately generate code. It spent roughly 15 seconds reading my repository, then produced a three-step implementation plan: (1) import the rate-limit utility in each route, (2) wrap the route handler with the rate limiter, (3) add a test for the rate-limited behavior. I could approve the plan as-is, reject individual steps, or add revision notes before any code was written. On this particular task, the plan was correct and I approved it. Workspace then executed each step, modified five route files, and produced a draft pull request with a clear description and a summary of what changed. The entire process — from typing the specification to having a reviewable PR — took 4 minutes and 12 seconds. This planning phase is not window dressing. On a different task where I asked Workspace to "add WebSocket support to the chat feature," it read the repository and surfaced during planning that the project was deployed on Vercel's serverless functions, which do not support persistent WebSocket connections. It suggested using Vercel's Edge Functions with a third-party real-time serv

2026-05-28 原文 →
AI 资讯

Cursor IDE Review: What Makes It a Genuinely Different AI Code Editor

I switched my primary editor to Cursor in January of 2026 after spending three years on VS Code with GitHub Copilot. The reason was not the chatbot sidebar — every editor has one of those now — but the tab completion model that felt qualitatively different the first time I used it. After six months of daily use across TypeScript, Python, and Go projects, I have a clear picture of what Cursor actually changes about the coding experience and where the marketing outpaces the product. The Tab Completion Model Changed How I Write Code The first thing I noticed with Cursor was that I was pressing Tab instead of thinking about what to type next. That sounds minor, but after tracking my usage over a two-week comparison period, I found that Cursor's tab model correctly predicted my next edit 73 times out of 100 attempts in TypeScript files — measured by counting how often I accepted the ghost text suggestion versus how often I ignored it and typed manually. The mechanism behind this is Cursor's speculative continuation engine. It does not wait for you to stop typing before offering a suggestion. As you modify a function signature at the top of a file, the model silently recalculates the impact on every call site below. I tested this explicitly on a 340-line TypeScript service file where I renamed a parameter from userId to accountId . Before I could scroll to line 180 where the first call site appeared, Cursor had already ghost-written the updated argument. By the time I reached line 310, all six call sites had correct suggestions waiting. That multi-location awareness is what I have not seen any other editor replicate consistently. Not every language gets the same treatment. I ran the same completion acceptance test across three languages I work in regularly. TypeScript came in at the 73 percent acceptance rate I mentioned. Python was close behind at 68 percent. Go was noticeably worse at 51 percent, and the Go suggestions that I did accept frequently required minor correct

2026-05-28 原文 →