软件工程发展史:从软件危机到AI共创
AI大模型让需求澄清、代码生成、测试生成都出现了新的路径,很多团队感到传统开发流程被重写了。要看清这一轮变化的本质,先把软件工程的历史脉络梳理出来会更有帮助。 本文按阶段回顾软件工程的发展路径,最后落到AI时代的变量与判断方法,方便你把当下的问题放回更长的时间尺度里看清楚。 ...
AI大模型让需求澄清、代码生成、测试生成都出现了新的路径,很多团队感到传统开发流程被重写了。要看清这一轮变化的本质,先把软件工程的历史脉络梳理出来会更有帮助。 本文按阶段回顾软件工程的发展路径,最后落到AI时代的变量与判断方法,方便你把当下的问题放回更长的时间尺度里看清楚。 ...
Chrome DevTools MCP 可以让 MCP 客户端直接连接到 Chrome 的远程调试接口。WSL2 和 Windows 的网络是隔离的,所以需要做端口转发与防火墙放行。下面把关键命令拆开说明,按步骤执行即可。 ...
对于喜欢 Linux 工具的强大功能但在 Windows 上工作的开发人员来说,Windows Subsystem for Linux (WSL) 是一个改变游戏规则的工具。Cursor,这款 AI 优先的代码编辑器,可以通过与模型控制程序 (MCP) 服务器集成来进一步增强此设置。直接在你的 WSL 环境中运行这些 MCP 服务器可以使你的开发工作流程保持整洁和统一。本指南将引导你完成配置 Cursor 以使用在 WSL 中运行的 MCP 服务器的步骤。 ...
前言 Hexo和Hugo都是优秀的静态网站生成器,但由于性能考虑或个人喜好,你可能想从Hexo迁移到Hugo。本文将详细记录完整迁移过程,包括配置、文章转换、多语言支持等方面。 准备工作 在开始迁移前,你需要先安装Hugo并了解基本的站点创建流程。以下是官方文档链接,建议按照官方文档进行操作: 1. 安装Hugo Hugo提供了多种安装方式,包括预编译二进制文件和包管理器。请根据你的操作系统,参考官方安装文档: Hugo官方安装指南 2. 创建Hugo站点 安装完Hugo后,你可以使用以下命令创建一个新的Hugo站点: hugo new site your-site-name cd your-site-name 更多关于创建站点的详细信息,请参考: Hugo快速入门指南 3. 安装主题 Hugo有丰富的主题可供选择,你可以在Hugo主题页面浏览并选择适合的主题。 安装主题的基本步骤如下: git init git submodule add https://github.com/theme-author/theme-name.git themes/theme-name 然后在配置文件中设置主题: echo "theme = 'theme-name'" >> hugo.toml 站点配置 创建hugo.toml配置文件: baseURL = 'https://www.mfun.ink/' defaultContentLanguage = 'zh-cn' title = "Mengboy's Blog" theme = 'PaperMod' hasCJKLanguage = true # Google Analytics配置 GoogleAnalytics = "G-xxxxxxx" # 请替换为您的Google Analytics ID # 添加permalink配置,使得链接格式与Hexo兼容 [permalinks] post = '/:year/:month/:day/:contentbasename/' # PaperMod主题参数 [params] # 设置环境为生产环境,这对于Google Analytics和AdSense加载非常重要 env = "production" # 作者信息 author = "mengboy" # 主要部分 mainSections = ['post'] defaultTheme = "auto" ShowReadingTime = true ShowShareButtons = true ShowPostNavLinks = true ShowBreadCrumbs = true ShowCodeCopyButtons = true ShowRssButtonInSectionTermList = true disableSpecial1stPost = false disableScrollToTop = false hideMeta = false hideFooter = false # 网站favicon设置 [params.assets] favicon = "/images/site/favicon.png" favicon16x16 = "/images/site/favicon.png" favicon32x32 = "/images/site/favicon.png" apple_touch_icon = "/images/site/favicon.png" # Google AdSense配置 需要自定义扩展,或者主题支持 googleAdsense = "ca-pub-xxxxxxxxxx" # 请替换为您的Google AdSense发布商ID googleAdsenseSlot = "xxxxxxxx" # 请替换为您的Google AdSense广告单元ID # 侧边栏配置 [params.profileMode] enabled = false title = "mengboy" subtitle = "记录学习与生活点滴" imageUrl = "images/site/favicon.png" imageWidth = 120 imageHeight = 120 # 社交图标 [[params.socialIcons]] name = "github" url = "https://github.com/mengboy" # 搜索设置 [params.fuseOpts] isCaseSensitive = false shouldSort = true location = 0 distance = 1000 threshold = 0.4 minMatchCharLength = 0 keys = ["title", "permalink", "summary", "content"] # 允许HTML [markup.goldmark.renderer] unsafe = true # 忽略HTML警告 ignoreWarnings = ['raw-html'] ignoreLogs = ['warning-goldmark-raw-html'] [languages] [languages.zh-cn] contentDir = 'content' languageName = '简体中文' weight = 10 title = "Mengboy's Blog" # 中文主页信息 [languages.zh-cn.params] [languages.zh-cn.params.homeInfoParams] Title = "记录学习与生活点滴" # 中文菜单 [languages.zh-cn.menu] [[languages.zh-cn.menu.main]] identifier = "home" name = "首页" url = "/" weight = 10 [[languages.zh-cn.menu.main]] identifier = "categories" name = "分类" url = "/categories/" weight = 20 [[languages.zh-cn.menu.main]] identifier = "tags" name = "标签" url = "/tags/" weight = 30 [[languages.zh-cn.menu.main]] identifier = "archives" name = "归档" url = "/archives/" weight = 40 [[languages.zh-cn.menu.main]] identifier = "about" name = "关于我" url = "/about/" weight = 50 [languages.en] contentDir = 'content/english' languageName = 'English' weight = 20 title = "Mengboy's Blog" # 英文主页信息 [languages.en.params] [languages.en.params.homeInfoParams] Title = "Recording Learning and Life" # 英文菜单 [languages.en.menu] [[languages.en.menu.main]] identifier = "home" name = "Home" url = "/" weight = 10 [[languages.en.menu.main]] identifier = "categories" name = "Categories" url = "/en/categories/" weight = 20 [[languages.en.menu.main]] identifier = "tags" name = "Tags" url = "/en/tags/" weight = 30 [[languages.en.menu.main]] identifier = "archives" name = "Archives" url = "/en/archives/" weight = 40 [[languages.en.menu.main]] identifier = "about" name = "About Me" url = "/en/about/" weight = 50 创建内容目录 mkdir -p content/post mkdir -p content/post/english # 英文文章目录 创建基础页面 关于页面 mkdir -p content/about 创建中文关于页面 content/about/index.md: --- title: "关于我" date: 2023-06-01T12:00:00+08:00 --- 这是关于我的页面内容... 创建英文关于页面 content/english/about/index.md: --- title: "About Me" date: 2023-06-01T12:00:00+08:00 --- This is about me page... 其他基础页面参考about页面。 编写转换脚本 创建一个Python脚本来转换Hexo文章到Hugo格式: #!/usr/bin/env python3 # 将Hexo的Markdown文件转换为Hugo格式 import os import re import datetime import shutil from pathlib import Path # 设置路径 hexo_posts_dir = "hexo/source/_posts" hugo_posts_dir = "hugo/content/post" hexo_img_dir = "hexo/source/images" hugo_static_dir = "hugo/static/images" # 确保目标目录存在 os.makedirs(hugo_posts_dir, exist_ok=True) os.makedirs(hugo_static_dir, exist_ok=True) # 复制图片文件夹 def copy_images(): if os.path.exists(hexo_img_dir): print(f"正在复制图片文件从 {hexo_img_dir} 到 {hugo_static_dir}") # 复制文件夹内容 for item in os.listdir(hexo_img_dir): s = os.path.join(hexo_img_dir, item) d = os.path.join(hugo_static_dir, item) if os.path.isdir(s): shutil.copytree(s, d, dirs_exist_ok=True) else: shutil.copy2(s, d) # 处理YAML front-matter def convert_front_matter(content): # 提取front-matter match = re.match(r'^---\s+(.*?)\s+---\s*', content, re.DOTALL) if not match: return content front_matter = match.group(1) rest_content = content[match.end():] # 转换标签和分类 new_front_matter = [] categories = [] tags = [] date = None for line in front_matter.strip().split('\n'): line = line.strip() # 处理日期 if line.startswith('date:'): date_str = line[5:].strip() try: date = datetime.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') new_front_matter.append(f'date: {date.strftime("%Y-%m-%dT%H:%M:%S+08:00")}') # 添加lastmod new_front_matter.append(f'lastmod: {date.strftime("%Y-%m-%dT%H:%M:%S+08:00")}') except ValueError: new_front_matter.append(line) # 处理标签 elif line.startswith('tags:'): tags_str = line[5:].strip() if tags_str.startswith('[') and tags_str.endswith(']'): # 格式为 tags: [tag1, tag2] tags = [tag.strip(' "\'') for tag in tags_str[1:-1].split(',')] else: # 可能是多行格式 continue # 处理分类 elif line.startswith('categories:'): cats_str = line[11:].strip() if cats_str.startswith('[') and cats_str.endswith(']'): # 格式为 categories: [cat1, cat2] categories = [cat.strip(' "\'') for cat in cats_str[1:-1].split(',')] else: # 可能是多行格式 continue # 复制其他行 elif not (line.startswith('- ') and ('tags:' in front_matter or 'categories:' in front_matter)): new_front_matter.append(line) # 添加分类和标签 if categories: new_front_matter.append(f'categories: {categories}') if tags: new_front_matter.append(f'tags: {tags}') # 添加slug if 'slug:' not in front_matter: filename = os.path.splitext(os.path.basename(content))[0] new_front_matter.append(f'slug: "{filename}"') # 组合新的front-matter new_content = '---\n' + '\n'.join(new_front_matter) + '\n---\n\n' + rest_content return new_content # 转换Markdown内容 def convert_markdown_content(content): # 替换图片链接 content = re.sub(r'!\[(.*?)\]\((.*?)/images/(.*?)\)', r'', content) # 处理更多标记 content = re.sub(r'<!--\s*more\s*-->', ' ', content) return content # 主转换函数 def convert_posts(): print(f"开始转换文章从 {hexo_posts_dir} 到 {hugo_posts_dir}") files = os.listdir(hexo_posts_dir) for file in files: if not file.endswith('.md'): continue source_file = os.path.join(hexo_posts_dir, file) target_file = os.path.join(hugo_posts_dir, file) print(f"转换: {source_file} -> {target_file}") # 读取源文件 with open(source_file, 'r', encoding='utf-8') as f: content = f.read() # 转换内容 content = convert_front_matter(content) content = convert_markdown_content(content) # 写入目标文件 with open(target_file, 'w', encoding='utf-8') as f: f.write(content) # 检测语言并创建多语言文件 def handle_multilingual(): print("处理多语言文章...") for file in os.listdir(hugo_posts_dir): if not file.endswith('.md'): continue filepath = os.path.join(hugo_posts_dir, file) # 读取文件内容 with open(filepath, 'r', encoding='utf-8') as f: content = f.read() # 检查是否有language标记 lang_match = re.search(r'language:\s*[\'"]?([a-z\-]+)[\'"]?', content) if lang_match: lang = lang_match.group(1) if lang.startswith('en'): # 创建英文版本 en_file = os.path.splitext(file)[0] + '.en.md' en_filepath = os.path.join(hugo_posts_dir, en_file) # 移除语言标记并写入新文件 content = re.sub(r'language:\s*[\'"]?[a-z\-]+[\'"]?\n', '', content) with open(en_filepath, 'w', encoding='utf-8') as f: f.write(content) # 删除原文件 os.remove(filepath) print(f" 创建英文文章: {en_filepath}") if __name__ == "__main__": copy_images() convert_posts() handle_multilingual() print("转换完成!") 运行转换脚本 cd ~/dev/book python3 convert_hexo_to_hugo.py 创建启动脚本 创建start.sh: ...
deepseek出现后,AI的势头更加一路不可阻挡, cursor最近又更新了Claude 3.7,编程体验进一步提高,身为码农对未来还有几年职业生涯充满了焦虑。熟话说打不过就加入,AI的浪潮已经阻挡不了,最好的方式就是学习接受,细节算法实现暂且不提门槛太高,还是先从使用上入手,下面整理常见的prompt框架。 ...
继续压榨主机生产力,在wsl Ubuntu中部署ai绘图,安装过程中需要代理,系统版本如下: ...
最近组了台台式机,日常主力机从Mac OS切到了Windows,Windows下的终端之前一直是被吐槽的对象,不过自从有了WSL后,Windows下的开发体验有了极大的提升,终端体验已经完全能赶得上Mac、Linux。贴两张调整后的终端截图: ...
seo 是什么 SEO,即搜索引擎优化(Search Engine Optimization),是一种通过优化网站结构、内容和外部链接来提高网站在搜索引擎中的排名的技术和策略。SEO的目的是增加网站的可见性,从而吸引更多的自然流量(即非付费流量)。 ...
单文件组件 什么是单文件组件? 简称SFC,将模版(template)、逻辑(script)、样式(style)整合在一个文件中,通常以`.vue`的形式存在。 简化组件开发和管理,使得代码更加清晰、模块化、便于维护 ...
核心概念 在 Vue.js 中,“应用”(Application)是指整个 Vue 项目的一个实例。它是 Vue 应用的基础结构和运行的起点,负责管理和协调所有的组件、状态、路由、和其他功能模块。 一个 Vue 应用通常是由一个 Vue 实例或多个 Vue 实例组成,通过实例化 Vue 对象创建应用。应用实例负责初始化应用的根组件,并提供应用范围内的配置和资源,例如插件、全局状态管理等。 ...