目录
作为一名程序员,大家总有一些“小秘密”是不想让老板知道的,尤其是那些能够让我们在工作中“摸鱼”或是提高效率的神器。当然,这些并不是为了偷懒,而是为了更好地管理我们的工作流程,提升代码质量,甚至是在繁忙的工作中找到一丝乐趣。下面,就让我来揭秘这些程序员们私藏的神器吧!
摸鱼神器:韭菜盒子
说起这个工具,懂的都懂-_-||b 经济大环境发展趋缓,你不得给自己额外”创收“?比如你是否曾在工作时想要偷偷关注一下股市动态,却又怕被老板发现?回忆19年,”超跌“让我买车的预算从A6L直接下滑到A4,这说起来都是眼泪啊(此处省略1000字)。跑题了,还是回来说咱的神器:让“韭菜盒子”来帮你及时了解股票基金的涨跌情况吧!这款VSCode插件不仅可以让你在编写代码的同时,实时查看投资情况,还提供了资金走向、基金历史净值查看等功能。这样一来,你在编写代码的同时,也能随时掌握市场动态,一举两得!
注意这个摸鱼神器帮助你赚钱了,你可以不告诉我,所以如果你在错误的时间有了错误的操作,出了问题也别说我让你干的 哈哈
以上就是程序员们不会告诉老板的那些神器啦!当然了,使用这些神器的目的是为了更好地完成工作,提高工作效率。如果你也想成为一名高效的程序员,不妨试试这些神器吧!
下面说点儿正经程序员神器吧:
1. 持续集成工具:CruiseControl(简称CC)
CruiseControl是一款强大的持续集成工具,它可以帮助团队自动感知代码变化,并进行持续集成。最初我在公司的TFS中将其集成,通过它,各位项目经理可以及时获取代码构建报告(我们要求开发库每天必须提交代码),并通过Email、Jabber等方式得到通知。这样一来,代码审核人员就可以在第一时间发现并解决代码中的问题,提高开发效率。更重要的是,CruiseControl的平台核心非常小,但扩展性非常强,可以根据自己的需求进行定制。
2. 代码风格、质量检查工具:StyleCop
最早接触StyleCorp是在微软的VS这个IDE中,当时也是尝试让团队的代码编写更规范(主要是交接时更简单),引入了两款工具,一个是FxCop,另一个是StyleCop.Analyzer。后来接触了StyleCop。这是一款开源的代码规范检查工具,它不仅可以检查代码的格式,还能检查编码规范,包括命名、注释等。通过StyleCop,团队可以轻松确保代码的可读性和可维护性,提高代码质量。更重要的是,StyleCop的规则可以自定义,我们根据公司的开发规范开发了许多自定义的检查规则,也可以根据自己的项目需求来设定规则,屏蔽不适用的规则。这样一来,就可以更加灵活地管理你的代码库,提高开发效率。
3.AI工具
这其实才是我要重点说的-_-||b
在当今这个信息爆炸的时代,程序员面临着前所未有的挑战。项目的复杂度不断增加,而交付周期却日益缩短。幸运的是,随着人工智能技术的飞速发展,特别是大模型AI的崛起,我们有了新的方法来应对这些挑战。下面,我将详细介绍程序员如何利用大模型AI在软件开发过程中的多个环节实现工作效率的显著提升。
3.1 AI助力编写开发日报
在软件开发过程中,记录每天的开发进展和代码改动是至关重要的。然而,手动编写开发卷宗既耗时又容易出错。通过将每天开发的代码发送给AI,我们可以利用其强大的自然语言处理和文本生成能力,自动提炼和记录代码变更、完成任务的情况,从而生成详细的开发卷宗。这不仅节省了程序员的时间,还提高了日报的准确性和完整性。
比如根据一段代码(代码参考3.2),我让AI完成了如下开发日报:
怎么样,这份日报(工作日志)格式严谨、内容充实,看着还像那么回事吧!如果你头疼每天必须写日志,不妨把代码发给AI,让它帮你完成,你也好继续“摸鱼”,或者继续为开源社区做贡献去。
3.2 AI助力编写普适性代码
编写高效且健壮的通用算法是程序员的日常工作之一,但这也是一项复杂且耗时的任务。大模型AI能够快速分析和理解大量代码库,为程序员提供经过优化的算法模板或代码片段,从而加速通用算法的开发过程。比如下面我曾在项目中需要对某一临时数据在终端落地,但考虑安全性时,想到需要进行数据加密保存,于是我借助ChatGPT完成了这个功能:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace FileEncryption
{
public static class FileEncryptor
{
// 设置密码
private const string Password = "20220304_DJZC";
// 设置加密迭代次数
private const int Iterations = 1000;
public static async Task EncryptFileAsync(string inputFile, string outputFile)
{
// 生成随机盐值
byte[] salt = GenerateSalt();
// 创建 AES 加密器
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Key = GenerateKey();
aes.IV = salt;
aes.Mode = CipherMode.CBC;
// 创建加密流
using (FileStream input = new FileStream(inputFile, FileMode.Open))
using (FileStream output = new FileStream(outputFile, FileMode.Create))
using (BufferedStream bufferedInput = new BufferedStream(input))
using (BufferedStream bufferedOutput = new BufferedStream(output))
using (ICryptoTransform encryptor = aes.CreateEncryptor())
{
// 写入盐值和加密算法信息
await WriteHeaderAsync(bufferedOutput, salt, aes.KeySize, aes.BlockSize, Iterations);
// 开始加密
await EncryptStreamAsync(bufferedInput, bufferedOutput, encryptor);
}
}
public static async Task DecryptFileAsync(string inputFile, string outputFile)
{
// 创建解密流
using (FileStream input = new FileStream(inputFile, FileMode.Open))
using (FileStream output = new FileStream(outputFile, FileMode.Create))
using (BufferedStream bufferedInput = new BufferedStream(input))
using (BufferedStream bufferedOutput = new BufferedStream(output))
{
// 读取加密算法信息
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
await ReadHeaderAsync(bufferedInput);
// 创建解密器
using (ICryptoTransform decryptor = aes.CreateDecryptor())
{
// 开始解密
await DecryptStreamAsync(bufferedInput, bufferedOutput, decryptor);
}
}
}
private static byte[] GenerateSalt()
{
byte[] salt = new byte[16];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
return salt;
}
private static byte[] GenerateKey()
{
// 将密码转换为字节数组
//byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(Password);
// HMACSHA256 算法可以用于从密码中派生出安全的密钥
var pbkdf2 = new Rfc2898DeriveBytes(Password, 16, Iterations);
return pbkdf2.GetBytes(32); // 返回一个 32 字节的 AES 密钥
}
private static async Task WriteHeaderAsync(Stream output, byte[] salt, int keySize, int blockSize, int iterations)
{
// 写入盐值
await output.WriteAsync(salt, 0, salt.Length);
// 写入加密算法信息
await output.WriteAsync(BitConverter.GetBytes(keySize), 0, sizeof(int));
await output.WriteAsync(BitConverter.GetBytes(blockSize), 0, sizeof(int));
await output.WriteAsync(BitConverter.GetBytes(iterations), 0, sizeof(int));
}
private static async Task ReadHeaderAsync(Stream input)
{
// 读取盐值
byte[] salt = new byte[16];
await input.ReadAsync(salt, 0, salt.Length);
// 读取加密算法信息
byte[] keySizeBytes = new byte[sizeof(int)];
await input.ReadAsync(keySizeBytes, 0, keySizeBytes.Length);
int keySize = BitConverter.ToInt32(keySizeBytes, 0);
byte[] blockSizeBytes = new byte[sizeof(int)];
await input.ReadAsync(blockSizeBytes, 0, blockSizeBytes.Length);
int blockSize = BitConverter.ToInt32(blockSizeBytes, 0);
byte[] iterationsBytes = new byte[sizeof(int)];
await input.ReadAsync(iterationsBytes, 0, iterationsBytes.Length);
int iterations = BitConverter.ToInt32(iterationsBytes, 0);
// 创建 AES 解密器
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.KeySize = keySize;
aes.BlockSize = blockSize;
aes.IV = salt;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
// 生成密钥
aes.Key = GenerateKey();
return;
}
private static async Task EncryptStreamAsync(Stream input, Stream output, ICryptoTransform encryptor)
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = await input.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
// 加密数据并写入输出流
byte[] encrypted = encryptor.TransformFinalBlock(buffer, 0, bytesRead);
await output.WriteAsync(encrypted, 0, encrypted.Length);
}
}
private static async Task DecryptStreamAsync(Stream input, Stream output, ICryptoTransform decryptor)
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = await input.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
// 解密数据并写入输出流
byte[] decrypted = decryptor.TransformFinalBlock(buffer, 0, bytesRead);
await output.WriteAsync(decrypted, 0, decrypted.Length);
}
}
}
}
注:AI生成代码还是有些问题的,部分时候需要你多次对话才可完成,并且得到期望的代码后,还是得适当修改才可以。
3.3 AI助力生成代码注释
良好的代码注释对于代码的可读性和可维护性至关重要。然而,编写详尽的注释同样是一项繁琐的工作。AI可以根据代码的结构和逻辑,自动生成准确且清晰的注释,极大地提高了代码的可读性,同时减轻了程序员的负担。
比如下面的代码被AI添加了注释:
/// <summary>
/// 根据给定的灰度图像和y坐标范围,找到人脸的ABS X坐标。
/// </summary>
/// <param name="imgSrc">源灰度图像</param>
/// <param name="y1">Y坐标范围的起始值</param>
/// <param name="y2">Y坐标范围的结束值</param>
/// <param name="faceX">输出的人脸ABS X坐标</param>
/// <param name="isLeft">如果为真,则从左侧开始查找;否则从右侧开始</param>
private void GetFaceABSFaceX(Image<Gray, Byte> imgSrc, int y1, int y2, out int faceX, bool isLeft)
{
// 将源图像二值化,并保存为新的灰度图像
Image<Gray, byte> imgThreshold = imgSrc.ThresholdBinary(new Gray(0.1d), new Gray(255d));
double iTotal = 0.0, iLoc = 0; // 用于统计像素数量和记录位置
// 定义遍历方向,如果isLeft为真则从左到右,否则从右到左
int step = isLeft ? 1 : -1;
// 定义起始位置,如果isLeft为真则从0开始,否则从imgThreshold.Width - 1开始
int startIndex = isLeft ? 0 : imgThreshold.Width - 1;
// 遍历图像,查找人脸边界
for (int i = startIndex; isLeft ? i < imgThreshold.Width / 2 : i > imgThreshold.Width / 2; i += step)
{
iTotal = 0; // 重置当前列的像素统计数量
// 遍历给定的y坐标范围,统计当前列的白色像素数量
for (int j = y1; j < y2; j++)
{
if (imgThreshold[j, i].Intensity != 0) // 使用Emgu CV的索引器访问像素值,更加简洁
{
iTotal++; // 如果像素值不为0(白色),则增加计数
}
}
// 计算当前列白色像素的占比
double r = iTotal * 1.0d / ((y2 - y1) * 1.0d);
// 如果白色像素占比超过50%,则认为找到了人脸边界,记录位置并退出循环
if (r > 0.5)
{
iLoc = i;
break;
}
}
// 将找到的人脸边界位置转换为整数,并输出
faceX = Convert.ToInt32(iLoc);
// 释放二值化图像占用的资源
imgThreshold.Dispose();
}
这个能力,对于那些懒得写注释,代码“一片荒漠”的兄弟来说,绝对是福音啊!你要做的只需把代码发给AI即可。后续每周的代码Review时,团队成员看着“足够绿化”的代码,那时的你绝对是会场上那个“最靓的仔”。不夸张地说:用来“泡”新来的实习小姐姐足够了哈哦~
3.4 AI助力重构代码去掉“坏味道”
AI在代码重构中的应用,无疑是程序员们提升工作效率的神器。通过智能分析和优化,AI工具能够迅速识别代码中的潜在问题,提出精准的重构建议,从而显著提升代码质量、统一代码风格,并自动化完成测试工作。随着AI技术的不断进步,这些工具在支持更复杂重构任务、集成更多开发工具方面的能力也将不断增强,为程序员们带来更加高效、智能的开发体验。
比如一段有“坏味道”的代码如下:
if (isLeft)
{
for (int i = 0; i < imgThreshold.Width / 2; i++)
{
iTotal = 0;
for (int j = y1; j < y2; j++)
{
if (CvInvoke.cvGet2D(imgThreshold.Ptr, j, i).v0 != 0)
iTotal++;
}
double r = iTotal *1.0d / ((y2 - y1) *1.0d);
if (r > 0.5)
{
iLoc = i;
break;
}
}
}
else
{
for (int i = imgThreshold.Width - 1; i > imgThreshold.Width / 2; i--)
{
iTotal = 0;
for (int j = y1; j < y2; j++)
{
if (CvInvoke.cvGet2D(imgThreshold.Ptr, j, i).v0 != 0)
iTotal++;
}
double r = iTotal * 1.0d / ((y2 - y1) * 1.0d);
if (r > 0.5)
{
iLoc = i;
break;
}
}
}
经AI重构后:
// 定义遍历方向,如果isLeft为真则从左到右,否则从右到左
int step = isLeft ? 1 : -1;
// 定义起始位置,如果isLeft为真则从0开始,否则从imgThreshold.Width - 1开始
int startIndex = isLeft ? 0 : imgThreshold.Width - 1;
// 遍历图像
for (int i = startIndex; isLeft ? i < imgThreshold.Width / 2 : i > imgThreshold.Width / 2; i += step)
{
iTotal = 0;
for (int j = y1; j < y2; j++)
{
if (imgThreshold[j, i].Intensity != 0) // 使用Emgu CV的索引器访问像素值,更加简洁
iTotal++;
}
double r = iTotal * 1.0d / ((y2 - y1) * 1.0d);
if (r > 0.5)
{
iLoc = i;
break;
}
}
注意:由于AI目前对于多态、继承等面向对象的理解能力问题,还没办法较好的从更好的维度对代码进行重构,但是可以用来消除重复代码,这对于那些习惯于“C/V大法”的程序员来说,是一个较好的助力。
3.5 AI助力完成伪代码流程
在编写复杂算法或系统之前,创建伪代码流程是一个很好的习惯。AI能够快速生成逻辑清晰、结构合理的伪代码,帮助程序员更快地规划和设计代码结构,减少开发过程中的错误和返工。
比如,我给了AI一段关于伪代码任务书的编写要求:
AI生成了任务书如下:
3.6 AI助力编写测试用例
测试是软件开发中不可或缺的一环,但编写全面的测试用例同样是一项艰巨的任务。AI可以根据代码的结构和功能,自动生成相应的测试用例,确保代码的健壮性和稳定性,同时节省了程序员大量的时间和精力。
比如有如下代码:
private int GetFitArea(Control control, string str, out SizeF size)
{
int fontInitSize = 80; //根据测试目前界面上的PictureBox适合的字体大小为76,此处由大到小循环计算
using (System.Drawing.Graphics g = control.CreateGraphics())
{// 获得一个Graphics实例
int margin = 10; //边距,对于多字组成的词语输出时有用
using (FontFamily fontFamily = new System.Drawing.FontFamily(theme.FontName))
{
using (System.Drawing.Font font = new System.Drawing.Font(fontFamily, fontInitSize))
{
size = g.MeasureString(str, font);
}
while (((control.Size.Width - size.Width) < margin) || ((control.Size.Height - size.Height) < margin)) //循环计算合适的大小
{
fontInitSize--;
using (System.Drawing.Font font = new System.Drawing.Font(fontFamily, fontInitSize))
{
size = g.MeasureString(str, font); // 计算字符串所需要的大小
}
}
}
}
return fontInitSize - 1;
}
你可以让AI生成测试用例的代码如下:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Drawing;
using System.Windows.Forms;
// 假设你的GetFitArea方法在某个类中,比如名为GraphicsHelper
[TestClass]
public class GraphicsHelperTest
{
[TestMethod]
public void TestGetFitAreaWithLongString()
{
// 创建一个模拟的Control对象,并设置其大小
Control control = new Control();
control.Size = new Size(200, 100); // 假设控制的大小是200x100像素
// 调用被测试的方法,并传入一个较长的字符串
string testStr = "This is a relatively long string to test the fitting area.";
SizeF measuredSize;
int fontSize = new GraphicsHelper().GetFitArea(control, testStr, out measuredSize);
// 断言字体大小是否在预期范围内(这个范围需要根据实际情况调整)
Assert.IsTrue(fontSize > 0 && fontSize < 80, "Font size should be between 1 and 79.");
// 可以添加更多的断言来验证measuredSize是否符合预期,比如是否小于control的大小等。
}
[TestMethod]
public void TestGetFitAreaWithShortString()
{
// 创建一个模拟的Control对象,并设置其大小
Control control = new Control();
control.Size = new Size(200, 100); // 假设控制的大小是200x100像素
// 调用被测试的方法,并传入一个较短的字符串
string testStr = "Hi!";
SizeF measuredSize;
int fontSize = new GraphicsHelper().GetFitArea(control, testStr, out measuredSize);
// 对于短字符串,字体大小应该接近初始设定的最大值(比如70左右,具体数值需要根据实际情况调整)
Assert.IsTrue(fontSize > 70, "Font size should be greater than 70 for a short string.");
// 可以添加更多的断言来验证measuredSize是否符合预期。
}
}
另外,作为QC的小伙伴别着急,你可以将上面的原始代码发给AI,要求他给你出一个专业、美观的测试用例表,这也是没问题的:
怎么样,上面的表格完全是AI根据待测试的代码生成的,专业性还不错哦~
总结一下:AI在软件开发过程中的应用,越来越能显著提高程序员的工作效率,减少错误和返工,让程序员能够更专注于创新和解决复杂问题。