注册

都什么年代了,还在用传统方式写代码?

前言


还在把 AI 当作搜索引擎的替代品,有问题才问 AI,没问题就在那边吭哧吭哧地撸代码?如果是这样,那你真的 OUT了!现在正经人谁还自己一行行地写代码啊,都是 AI 生成的代码——没有 AI 我不写(手动滑稽)。


本文将分享 AI 时代的编程新实践,教你如何从一个 "Ctrl + C"、 "Ctrl + V" 工程师,变成一个 "Tab + Enter" 工程师🤣。


开发流程


软件的一般研发流程为:

  1. 需求分析
  2. 程序设计
  3. 代码编写
  4. 软件测试
  5. 部署上线

我们在这里主要关心步骤2~4,因为与 AI 结合得比较紧密。虽然需求分析也可以借助 AI,但不是本文的重点,故不做讨论。


程序设计


经过需求分析、逻辑梳理后,在编写实际代码前,需要进行程序设计。


此环节的产物是设计文档,是什么类型的设计文档不重要,重要的是伪代码的输出。


虽然《Code Complete》早就推荐过伪代码的实践,但对此人们容易有一个误区:认为写伪代码花的时间,已经够把实际代码写好了。但 AIGC 时代,此问题可以轻松破解:AI 写代码的速度肯定比人快,因此,只要能找到方法能让 AI 生成符合需求的代码,就值得花时间去研究。而伪代码,就是让 AI 快速生成符合期望的实际代码的最好方式。


为什么这么说呢?因为想要让 AIGC 符合期望,恰当的 Prompt 必不可少。但如何写好这个 Prompt,需要提供多少上下文,才能让 AI 更好地理解我们的意图,这是需要技巧、需要调试的。而经过精心设计的伪代码,本身已经提供了足够的上下文,且意图足够聚焦,减轻了对 Prompt 的要求,又提高了 AIGC 的成功率。


我们来看一下伪代码示例:

plainText = JSON.stringify(data)
digest = hash(plainText) // 防篡改
secret = Symmetric.getKey()
cipherText = encryptText(data, secret) // 防内容泄密


pair = Asymmetric.getPair()
cipherSecret = encryptKey(secret, pair.getPrivateKey()) // 防密钥泄露

return {
digest,
cipherText,
cipherSecret,
pair.getPublicKey(),
}

上述代码主要表达的内容是:

  1. 对初始数据进行加密
  2. 返回加密后的相关内容
  3. 涉及到了一系列的算法

对于伪代码的编写,有如以建议:

  1. 不要纠结类型,不要局限于某一种编程语言的语法,不用试图写能编译通过的代码——这只会限制了你的表达
  2. 命名一定要准确,符合领域术语,这一点很关键。这一点可以通过查找资料、看书、问 AI 来实现。千万不要只是生硬地汉译英,不专业的表达会妨碍 AI 的理解

代码编写


代码编写分为以下几步:

  1. 把伪代码转换成目标语言可执行的代码
  2. 根据项目情况,对生成的代码进行改造
  3. 利用 AI 编码辅助工具编写剩余的代码

生成真实代码


让 AI 生成代码的 prompt 很简单,示例如下(根据目标语言进行修改):

please transform the following pseudo code into practical java code ```
your code```please transform the following pseudo code into practical java code ```
your code```

使用 chatGPT 结果截图:


7c7f5cb33b560ce1c9d74418d7a2ec04.png


完整代码如下:

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.*;

public class EncryptionExample {

public static void main(String[] args) throws Exception {
// Prepare the license data
LicenseData licenseData = new LicenseData();
licenseData.setLicenseId("123");
licenseData.setLicenseType("Standard");

// Convert the license data to JSON string
ObjectMapper objectMapper = new ObjectMapper();
String plainText = objectMapper.writeValueAsString(licenseData);

// Hash the plain text
String digest = hash(plainText);

// Generate a symmetric key
SecretKey secretKey = generateSymmetricKey();

// Encrypt the license data with the symmetric key
byte[] cipherText = encryptText(plainText, secretKey);

// Generate an asymmetric key pair
KeyPair keyPair = generateAsymmetricKeyPair();

// Encrypt the symmetric key with the private key
byte[] cipherSecret = encryptKey(secretKey.getEncoded(), keyPair.getPrivate());

// Print the results
System.out.println("Plain Text: " + plainText);
System.out.println("Digest: " + digest);
System.out.println("Cipher Text: " + new String(cipherText));
System.out.println("Cipher Secret: " + new String(cipherSecret));
}

public static String hash(String input) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes());
return bytesToHex(hash);
}

public static SecretKey generateSymmetricKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
return keyGenerator.generateKey();
}

public static byte[] encryptText(String data, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data.getBytes());
}

public static byte[] encryptKey(byte[] secret, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(secret);
}

public static KeyPair generateAsymmetricKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
}

public static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("x", b));
}
return result.toString();
}

public static class LicenseData {
private String licenseId;
private String licenseType;

public String getLicenseId() {
return licenseId;
}

public void setLicenseId(String licenseId) {
this.licenseId = licenseId;
}

public String getLicenseType() {
return licenseType;
}

public void setLicenseType(String licenseType) {
this.licenseType = licenseType;
}
}
}

把上述代码 copy 下来,放到工程中,根据需要改造即可。


这里特别要说下,强烈推荐使用原版 AI,而不是寻找平替,同样的 prompt,下图是某一平替输出的结果:


只生成了函数声明,没有生成函数实现。二者对比,未免相形见绌。

e2029a28574b2a528b3c00f74f45177d.png


辅助编程工具


改造的过程中,少不了 AI pair programming tools。对此,我推荐使用 Amazon 的 CodeWhisperer,原因很简单,跟 GitHub Copilot 相比,它是免费的😃。


CodeWhisperer 的安装可以看文末的安装教程,我们先来看一下它是怎么辅助我们编码的。


第一种方式是最简单的,那就是什么都不管,等待智能提示即可,就好像 IDEA 原来的提示一样,只不过更智能。


下图示例中,要把原来的中文异常提示,修改成英文,而我只输入了两个字符 IM, 就得到了智能提示,补全了完整的英文字符串!


29c564a37d290195443915afdc2abfe1.png


可以注意到,上图的智能建议一共有 5 条,相应的快捷键为:

  1. 方向键 ->,查看下一条提示
  2. 方向键 <-,查看上一条提示
  3. Tab,采用该提示
  4. Esc,拒绝提示

我们再来看第二种 CodeWhisperer 的使用方式,编写注释,获得编码建议。


0727fabe19284d56f76877241d2a08f1.gif


最后一种就是编写一个空函数,让 CodeWhisperer 根据函数名去猜测函数的实现,这种情况需要足够的上下文,才能得到令人满意的结果。


软件测试


AI 生成的内容,并不是完全可信任的,因此,单元测试的重要性变得尤为突出。


对上述代码编写测试代码后,实际上并不能一次通过,因为前面 AI 生成的代码参数有误。


此时需要一边执行单测,一边根据结果与 AI 进行交互:


851fe6805e21c91ff824d407ba572d3b.png


经过修改,最终测试用例通过👏!


ae39fcbef0b2a2c9dc2ee10244773915.png


总结


本文通过案例,展示了 AI 如何结合软件研发的流程,提升我们的编程效率的。


其中,个人认为最重要的是编写伪代码与进行单元测试。有趣的是,这两样实践在 AIGC 时代之前,就已经被认为是最佳实践。这给我们启示:某些方法论、实践经得起时间的考验,技术更新迭代,它们历久弥新。


另外,AI 是否能进一步渗透我们的工作流,还有待探索。此文作引抛砖引玉之用,期待大家的后续分享。


附:CodeWhisperer 安装


下载 2023 年的 IDEA,打开 Plugins Marketplace,找到 AWS Toolkit


ba6954cc089d374ff13a847aeacbf3e5.png


安装完成、重启 IDEA 后,点击左下角,按下图所示操作:


801fc875584121b2dd0a0d09a89420a2.png


3d8675709f89207a0b202075b4ace27b.png


如果第一次使用,就点击 1 处进行注册,如果已经有账号了,就点击 2 处使用自己的账号登录。


081b9a8f0727a31127f33fcfad7bece3.png


注册、登录、授权成功后,出现如图所示页面,即可使用 CodeWhisperer。


d44663be11f0c1b24598e148167aa9fc.png


作者:levy9527
链接:https://juejin.cn/post/7255309681547411513
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册