Skip to content
Go back

AI 能编写代码,但无法构建软件系统

Published:  at  12:00 AM

AI 能编写代码,但无法构建软件系统

引言:一个值得深思的现象

近期,越来越多非技术背景的创业者开始寻求技术联合创始人或 CTO 的帮助。他们通常会说:“我用 AI 生成了一个应用原型,你能帮我把它做成可投入生产的版本吗?” 这些人可能是律师、销售经理或其他领域的专业人士,他们了解自己的业务,但一直缺乏将想法变为现实的技术能力。

这个现象引发了一个关键问题:如果生成式 AI 真的能够完成软件开发工作,为什么这些人还需要寻找技术专家? 在 AI 辅助编程工具如 GitHub Copilot、GPT-4 等日益成熟的今天,这个问题的答案揭示了软件工程的本质,也指出了当前 AI 技术的能力边界。

答案其实很简单:AI 可以编写代码,但它无法构建软件系统。

编码与软件工程:两个不同的世界

软件行业有一句经典格言:“编码容易,软件工程困难。” 这句话的深刻之处在于,它点出了两个看似相似但本质不同的概念。

什么是编码?

编码(Coding)是解决独立的、定义明确的问题的过程。例如:

在这些场景中,问题的边界是清晰的,输入和输出是明确的,解决方案通常是局部的。大语言模型(LLM)如 GPT-4、Claude 等在这类任务上表现出色,它们可以快速生成高质量的代码片段,甚至能够理解上下文并提供多种实现方案。

什么是软件工程?

软件工程(Software Engineering)则是一个更加宏观和复杂的过程,它涉及:

  1. 需求分析与规划 - 理解业务需求,定义系统边界,制定技术路线
  2. 架构设计 - 选择合适的技术栈,设计系统模块划分,确保可扩展性
  3. 集成与协调 - 将数百个独立的功能组件整合为一个协调一致的系统
  4. 质量保证 - 编写测试,处理边缘情况,确保系统稳定性和安全性
  5. 维护与演进 - 设计易于维护的代码结构,支持需求变化和功能扩展
  6. 性能优化 - 监控系统性能,优化瓶颈,确保用户体验
  7. 部署与运维 - 设计 CI/CD 流程,配置监控告警,处理生产环境问题

软件工程的核心任务是管理复杂度。一个生产级别的应用系统通常包含数百个相对简单的功能,但挑战在于如何同时处理这些功能,并保持整个系统的可维护性、可扩展性和稳定性。

从原型到生产:跨越鸿沟的关键点

许多创业者使用 AI 工具快速构建了功能演示(Demo),这些演示可以展示核心功能,甚至看起来很完整。但当他们尝试将其投入实际使用时,问题就暴露出来了。从演示到生产级应用的转变,正是编码与软件工程的分界线。

演示与生产的差距

一个功能演示通常只需要:

而生产级应用需要:

AI 生成代码的典型问题

当技术专家查看 AI 生成的”演示代码”时,通常会发现以下问题:

  1. 架构缺失 - 所有代码堆砌在一起,没有清晰的分层结构
  2. 硬编码 - 配置信息、密钥、URL 等直接写在代码中
  3. 缺乏错误处理 - 假设一切都会成功,没有处理失败场景
  4. 安全漏洞 - 未验证用户输入,缺少授权检查
  5. 性能问题 - N+1 查询问题,缺少索引,同步阻塞操作
  6. 无法测试 - 紧耦合的代码,难以编写单元测试
  7. 不一致的风格 - 混合使用不同的编码约定和模式

这些问题使得”让应用投入生产”实际上意味着重新开始,而不是在现有基础上改进。

为什么 AI 难以完成软件工程?

1. 复杂度管理的本质

软件工程的核心挑战不是编写单个功能,而是管理整体复杂度。一个典型的企业应用可能包含:

AI 模型擅长局部优化,但难以把握全局视野。它可以为单个功能生成优秀的代码,但无法确保这段代码在整个系统中的位置是合理的,也无法预见它可能引发的连锁反应。

2. 长期维护性的考量

编写一次性运行的脚本和构建需要维护多年的系统,是完全不同的思维方式。软件工程师在编写代码时,需要考虑:

AI 模型缺乏对”未来”的理解,它无法预见代码在六个月后的维护成本,也难以在当下的便利性和长期的可维护性之间做出权衡。

3. 隐性知识与经验

软件工程中存在大量无法明确描述的”隐性知识”:

这些决策依赖于对业务领域的深入理解、对技术栈的全面掌握,以及多年积累的实战经验。AI 可以生成符合语法的代码,但难以做出这些需要综合判断的决策。

4. 集成与一致性

在一个真实的软件项目中,每个新功能都需要与现有系统无缝集成:

AI 在处理孤立问题时表现出色,但在确保整体一致性方面力不从心。

软件工程师的不可替代价值

理解 AI 的局限性,也就理解了软件工程师的核心价值:

1. 架构师角色

软件工程师需要从宏观层面设计系统架构:

┌─────────────────────────────────────────┐
│           前端应用层                      │
│  (React/Vue/Angular)                    │
└──────────────┬──────────────────────────┘
               │ HTTPS
┌──────────────▼──────────────────────────┐
│           API 网关层                     │
│  (认证、限流、路由)                       │
└──────────────┬──────────────────────────┘

      ┌────────┴────────┐
      │                 │
┌─────▼─────┐     ┌────▼──────┐
│ 业务服务A  │     │ 业务服务B  │
│ (微服务)   │     │ (微服务)   │
└─────┬─────┘     └────┬──────┘
      │                 │
      └────────┬────────┘

┌──────────────▼──────────────────────────┐
│           数据层                         │
│  (PostgreSQL/Redis/消息队列)            │
└─────────────────────────────────────────┘

这种架构决策需要权衡多个维度:性能、可扩展性、成本、开发效率等,AI 无法替代这种高层次的决策能力。

2. 质量守护者

软件工程师确保代码质量:

// AI 可能生成的代码 - 功能性但不完整
public class UserService
{
    public async Task<User> GetUser(int id)
    {
        var user = await _database.Users.FindAsync(id);
        return user;
    }
}

// 工程师改进后的代码 - 完整、健壮、可维护
public class UserService : IUserService
{
    private readonly IUserRepository _userRepository;
    private readonly ILogger<UserService> _logger;
    private readonly IMemoryCache _cache;

    public UserService(
        IUserRepository userRepository,
        ILogger<UserService> logger,
        IMemoryCache cache)
    {
        _userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _cache = cache ?? throw new ArgumentNullException(nameof(cache));
    }

    public async Task<Result<User>> GetUserAsync(int id, CancellationToken cancellationToken = default)
    {
        try
        {
            // 参数验证
            if (id <= 0)
            {
                _logger.LogWarning("Invalid user ID: {UserId}", id);
                return Result<User>.Failure("Invalid user ID");
            }

            // 缓存检查
            var cacheKey = $"user_{id}";
            if (_cache.TryGetValue(cacheKey, out User cachedUser))
            {
                _logger.LogDebug("User {UserId} retrieved from cache", id);
                return Result<User>.Success(cachedUser);
            }

            // 数据库查询
            var user = await _userRepository.GetByIdAsync(id, cancellationToken);
            
            if (user == null)
            {
                _logger.LogInformation("User {UserId} not found", id);
                return Result<User>.Failure("User not found");
            }

            // 更新缓存
            var cacheOptions = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromMinutes(5));
            _cache.Set(cacheKey, user, cacheOptions);

            _logger.LogInformation("User {UserId} retrieved successfully", id);
            return Result<User>.Success(user);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error retrieving user {UserId}", id);
            return Result<User>.Failure("An error occurred while retrieving the user");
        }
    }
}

工程师添加的改进包括:

3. 技术债务管理者

软件工程师需要在速度和质量之间找到平衡:

4. 团队协作者

在真实的软件项目中,工程师需要:

AI 辅助编程的正确定位

这并不是说 AI 工具毫无用处,恰恰相反,它们在以下场景中非常有价值:

1. 加速常规编码任务

// 让 AI 生成样板代码
public class CreateUserCommand : IRequest<Result<int>>
{
    public string Email { get; set; }
    public string Name { get; set; }
    public string Password { get; set; }
}

public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Result<int>>
{
    // AI 快速生成处理器结构
    private readonly IUserRepository _userRepository;
    private readonly IPasswordHasher _passwordHasher;

    public CreateUserCommandHandler(
        IUserRepository userRepository,
        IPasswordHasher passwordHasher)
    {
        _userRepository = userRepository;
        _passwordHasher = passwordHasher;
    }

    public async Task<Result<int>> Handle(
        CreateUserCommand request,
        CancellationToken cancellationToken)
    {
        // 工程师专注于业务逻辑实现
        // ...
    }
}

2. 探索 API 和库的用法

AI 可以快速提供示例代码,帮助工程师了解新技术:

// 询问 AI:"如何在 ASP.NET Core 中配置 JWT 认证?"
// AI 提供基础示例,工程师根据项目需求调整
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = configuration["Jwt:Issuer"],
            ValidAudience = configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(configuration["Jwt:Key"]))
        };
    });

3. 重构和代码转换

AI 擅长机械性的重构任务:

4. 生成测试用例

// AI 可以帮助生成测试骨架
public class UserServiceTests
{
    private readonly Mock<IUserRepository> _mockRepository;
    private readonly Mock<ILogger<UserService>> _mockLogger;
    private readonly UserService _userService;

    public UserServiceTests()
    {
        _mockRepository = new Mock<IUserRepository>();
        _mockLogger = new Mock<ILogger<UserService>>();
        _userService = new UserService(_mockRepository.Object, _mockLogger.Object);
    }

    [Fact]
    public async Task GetUserAsync_ValidId_ReturnsUser()
    {
        // AI 生成测试结构,工程师填充业务逻辑
        // Arrange
        var userId = 1;
        var expectedUser = new User { Id = userId, Name = "Test User" };
        _mockRepository.Setup(r => r.GetByIdAsync(userId, default))
            .ReturnsAsync(expectedUser);

        // Act
        var result = await _userService.GetUserAsync(userId);

        // Assert
        Assert.True(result.IsSuccess);
        Assert.Equal(expectedUser.Id, result.Value.Id);
    }
}

结论:人机协作的未来

当前的 AI 技术状态揭示了一个重要事实:编码可以部分自动化,但软件工程仍然需要人类的智慧和经验。

软件工程的本质是管理复杂度、做出权衡决策、确保长期可维护性,这些都是当前 AI 难以胜任的任务。一个功能演示和一个生产就绪的系统之间存在巨大差距,跨越这个差距需要的不仅仅是代码生成能力。

这并不意味着 AI 工具没有价值。相反,它们正在改变软件工程师的工作方式,使工程师能够将更多精力集中在高价值的架构决策、复杂问题解决和创新性设计上,而将重复性的编码任务交给 AI 辅助工具。

对于那些寻求技术联合创始人的创业者来说,理解这个差异至关重要:AI 可以帮助你快速验证想法和构建原型,但要将产品推向市场并持续运营,你仍然需要具备软件工程经验的专业人才。

未来的软件开发将是人机协作的模式:AI 处理机械性的编码任务,人类负责架构设计、复杂度管理和质量保证。这种协作将大幅提升开发效率,但软件工程师的核心价值不仅不会消失,反而会变得更加重要。

在这个 AI 快速发展的时代,理解 AI 能做什么和不能做什么,同样重要。编码是技能,软件工程是艺术,而艺术,始终需要人类的创造力和判断力。



Previous Post
六位工程师的 AI 辅助开发工作流深度解析
Next Post
智能体 AI 的工作原理:从概念到实践的完整解析