让AI替代50%的工作 ——利用 AI 进行代码改写与依赖迁移

让AI替代50%的工作 ——利用 AI 进行代码改写与依赖迁移


chinese AI

本文以及本专栏正在参加豆包 Marscode 专栏征文活动,如何喜欢欢迎投票支持,这将对我们意义非凡
投票链接
以下实战案例均使用豆包 MarsCode AI 工具,欢迎大家尝试!

想要提升编程效率,释放创造力?快来体验 豆包 MarsCode 编程助手!作为一款由豆包打造的智能编程工具,MarsCode 提供智能代码补全、单测生成、代码解释等强大功能,全面覆盖编程的各个环节,让你从写代码到调试的每一步都更加高效。

无论是快速生成代码片段、优化注释、发现并修复代码问题,还是通过 AI 问答解决开发中的疑惑,MarsCode 都能帮你轻松搞定!支持 Python、JavaScript、TypeScript 等超过 100 种语言,兼容主流 IDE,如 VSCode 和 JetBrains,让开发无缝衔接。

数据安全更是无忧:Marscode 采用加密传输,严格保护用户隐私,确保数据不被用于二次训练。

立即安装 MarsCode,登录即可享受 AI 助力编程的全新体验! 开启效率新篇章,从 MarsCode 开始!
https://www.marscode.cn/


在我们讨论使用 AI 进行代码改写和依赖迁移之前,先思考一个问题:从信息的角度来看,代码的描述力处于什么水平?

例如,当我有一个业务需求,不考虑书写描述的难度,仅考虑不同描述方式的“描述力”,是用文字描述这个业务描述力强,还是用代码描述力强?

这个问题没有统一的答案。如果是哲学问题,我相信文字的能力大于代码;但如果是逻辑问题,我认为代码的描述能力更强。许多追求“Code is Law”的朋友相信,一个详尽描述所有情况的代码就是法律,是比法律条文更可靠、更能避免二义性的描述方式。当然,这就有点扯远了。

我们回到描述力。在利用 AI 辅助编程时,我们的核心任务是使用各种方式让 AI 理解我们想做的事提供足够的上下文。我认为这是 AI 辅助编程中人类的核心任务。如果从 AI 辅助编程扩展到设计 AI 应用,人类的任务就多了一个 给 AI 提供足以完成任务的外部能力。当然,我们这里仅限于 AI 编程,AI 应用的故事我们之后有机会聊。

所以,对于 AI 了解你的需求,没有什么比你的代码更具有信息量。在理解了这件事后,让我们开始这一章的学习。

依赖迁移

我们从我个人常用的技巧开始。就像前几章我们举过的 JS 生态中 moment.js 和 day.js 的例子,前者是一个几乎在现代开发中没有使用价值的老旧库,但依旧在许多遗留代码库中占据主流。因此,在公司内部安全要求和供应链安全的要求下,我们经常会做类似的迁移。

这里我们以 moment.js 迁移到 luxon.js 为例,因为 luxon.js 提供了完整的与 moment.js 对比的文档。
对不熟悉 JS 或相关背景的朋友,不需要理解代码(其实熟悉的朋友也不需要理解代码,这些并非真实代码),重点在于交互的过程。

首先,我们有一部分基于 moment.js 进行日期计算的 Node.js 代码:

const moment = require("moment");

// 获取当前日期和时间
const now = moment();

// 格式化日期
console.log(now.format("YYYY-MM-DD HH:mm:ss"));

// 解析日期字符串
const date = moment("2023-04-15", "YYYY-MM-DD");

// 日期加减
const nextWeek = date.add(7, "days");

// 获取星期几
console.log(nextWeek.format("dddd"));

然后,我们进行提示,要求 AI 进行迁移:

我有一段使用 moment.js 的 JavaScript 代码,需要将其迁移到使用 luxon.js。请帮助我改写以下代码,并确保功能保持不变:

<your-code>

请在改写后,解释每一处改动的原因和 luxon.js 中对应的方法。

image.png

这里有一个注意点。
因为 moment.js 和 luxon.js 都是非常流行的库,且 API 相对稳定,在 AI 训练数据库中有一定的比重,所以改写质量还可以。
但依赖库的 API 变化太快了,我们不应该依赖于此,而是应该手动提供有价值的信息。同样地,提供信息的原则是:给我同样的信息我可以顺利完成这个任务。熟练背诵最新的 API 显然不是我们具备的能力,也不应该是我们要求 AI 具备的能力。
所以,这就是我们应该提供的信息:luxon.js 文档:给 Moment 用户

我有一段使用 moment.js 的 JavaScript 代码,需要将其迁移到使用 luxon.js。请帮助我改写以下代码,并确保功能保持不变:
<your-code>

这是相关的文档供你参考:<doc>

请在改写后,解释每一处改动的原因和 luxon.js 中对应的方法。

CleanShot 2024-10-04 at 01.38.16@2x.png

由于我们的改写任务不是一个特别复杂的程序,且 moment.js 和 luxon.js 比较流行,所以两次输出的结果是一致的。但对于内部库、小众库或者是最新的库,这种方法的效果会更好。

这个技巧也很适合对代码库进行依赖的升级,例如使用升级 Redux 5.0 到 RTK 2.0 的迁移文档作为上下文,来帮助升级 Redux 相关的依赖。

语言迁移

就像前文说的,代码是描述力更强的方式,能够让 AI 更深入理解我们的需求。在日常工作中,我们的很多工作并不是开创性的,甚至极少有开创性的工作,所以参照现有的代码是很常见的。

不同语言擅长和常见的工作领域不一样。例如,我之前在做关于 GIS(Geographic Information System,地理信息系统)的业务时,大量的相关代码是用 C++ 写的,而使用 TS(TypeScript)的参考代码就很少。之前在这种情况下,需要自己先理解 C++ 语法和这个程序,然后想到对应的 TS 写法,最后改写成 TS 版本。现在,这个任务用 AI 显然是非常方便的。

例如,我们现在有一段使用 C++ 编写的计算经纬度的代码:

#include<iostream>
#include "math.h"
using namespace std;
#define pi 3.1415926535897932384626433832795
#define EARTH_RADIUS 6378.137 //地球半径 KM
double rad(double d)
{
    return d * pi /180.0;
}
double RealDistance(double lat1,double lng1,double lat2,double lng2)//lat1第一个点纬度,lng1第一个点经度,lat2第二个点纬度,lng2第二个点经度
{

    double a;
    double b;
    double radLat1 = rad(lat1);
    double radLat2 = rad(lat2);
    a = radLat1 - radLat2;
    b = rad(lng1) - rad(lng2);
    double s = 2 * asin(sqrt(pow(sin(a/2),2) + cos(radLat1)*cos(radLat2)*pow(sin(b/2),2)));
    s = s * EARTH_RADIUS;
    s = s * 1000;
    return s;
}

int main()
{
    cout<<RealDistance(34.04640,-118.434,34.042,-118.429);
    return 0;
}

我们使用 AI 将其转换成使用 JS 实现的代码:

这里是一段使用 C++ 编写的计算两个经纬度坐标点之间的距离的代码,帮我改写成 TS 版本,注意计算的准确度。
注意,代码风格符合 TS 的习惯。
<c++_code>

CleanShot 2024-10-08 at 21.33.25@2x.png

这里 AI 写的代码在一些细节上还有优化空间,就像我们前面章节提到的,AI 并不能解决所有问题。所以,这里是给我们提供了一个基础的实现,我们可以在此基础上进行修改,要比我们从零开始实现方便得多。
对大多数人来说,比起完整地写代码,更擅长在一定基础上修改代码。

在 prompt 中,我们强调了注意计算的准确度,这是因为 TS 不擅长做科学计算。这里可以根据自己的需求进行额外的强调,例如:

  • 注意代码的简洁
  • 使用 xxx 库去实现
  • 注意复用现有的工具函数 <your-code>
  • 使用 ES6 编码风格,不要使用 var

应用这些额外的要求,来提高 AI 代码输出的质量。

代码风格改写

代码风格改写是指一些旧的写法、旧的风格,需要我们统一改成新的实现方式,但这过程中是繁琐的重复劳动,并不需要投入太多精力。例如在 JS 中,经典的把回调地狱改成 async/await 的方式,修改起来并不涉及复杂的逻辑,但又不是简单的字符替换,需要稍微花一些心思,就很适合 AI 来做。

原代码:

function getUserData(userId, callback) {
  database.getUser(userId, function (err, user) {
    if (err) return callback(err);
    api.fetchProfile(user.profileId, function (err, profile) {
      if (err) return callback(err);
      cache.save(userId, profile, function (err) {
        if (err) return callback(err);
        callback(null, profile);
      });
    });
  });
}

然后使用 AI 进行修改:

请将以下使用回调函数的代码改写为使用 `async/await` 的现代写法:
<your-code>

21.53.14.png

然后我们只需要做审核工作,验证 AI 的修改逻辑。