AI 驱动的开发者(MEAP)(二)(3)

简介: AI 驱动的开发者(MEAP)(二)

AI 驱动的开发者(MEAP)(二)(2)https://developer.aliyun.com/article/1516330

第六章:测试、评估和解释大型语言模型

本章内容包括

  • 轻松草拟单元测试
  • 生成集成测试
  • 确定代码质量和覆盖率
  • 评估软件复杂性
  • 翻译代码和文本

本章将探讨软件工程的一个关键方面:测试。测试软件的行为有多个重要目的。首先,它有助于识别可能会影响软件功能、可用性或性能的错误和问题。此外,它确保软件符合所需的质量标准。通过进行全面的测试,我们可以验证软件是否满足指定的要求,正如预期的那样工作,并产生预期的结果。通过全面的测试,开发人员可以评估软件在各种平台和环境中的可靠性、准确性、效率、安全性和兼容性。在开发过程的早期检测和解决软件缺陷可以节省大量的时间和成本。

当我们完成测试的制定后,我们将评估代码的质量。你将了解到几个有助于评估软件质量和复杂性的度量标准。此外,如果我们需要对代码的目的有更清晰的了解,或者是首次审核代码,我们将寻求解释以确保全面理解。

6.1 测试,测试…一、二、三种类型

测试在软件工程中扮演着重要的角色,因此我们将详细探讨各种类型的测试。这包括单元测试、集成测试和行为测试。首先,我们将利用 Copilot Chat 来帮助我们创建一个单元测试

单元测试

单元测试是一种专注于测试单个组件或代码单元的测试类型,以确保它们在独立环境中的正确运行。通常由开发人员执行这种测试,以帮助识别特定软件单元中的错误和问题。

6.1.1 单元测试

在本节中,我们将创建单元测试来测试我们的软件组件。Python 的有几个用于单元测试的测试框架。每个框架都有其独特的特点,适用于不同的场景。在我们的 AI 工具提供的建议基础上,我们将简要介绍每个框架,然后选择一个特定的框架。

第一个框架是unittest:这是 Python 用于创建单元测试的标准库。它与 Python 捆绑在一起,无需单独安装。unittest提供了丰富的断言集,并非常适合编写简单到复杂的测试用例,但是代码量可能会相当庞大。unittest适合编写基本的单元测试,特别是如果您不想在项目中引入其他依赖项时。在任何需要独立于系统其余部分确认代码功能的情况下,它都非常有用。

接下来,让我们来看一下pytestpytest是一个流行的第三方库,用于单元测试,尽管它足够灵活,可以处理更多不仅仅是单元测试。它比unittest需要更少的样板代码,并且具有强大的功能,例如设置和拆卸的 fixture,参数化测试,以及运行unittest和 nose 测试套件的能力。pytest非常适合简单和复杂的单元测试用例。它也适用于功能和集成测试。如果你重视简单和易用性,并且你的项目不限于仅使用 Python 标准库,那么pytest是一个绝佳的选择。

接下来,我们有nose2,它是被废弃的"nose"测试框架的继承者。它扩展了unittest,使测试变得更容易。它以其测试发现功能而闻名,该功能可以自动找到您项目中的测试,因此您无需手动列出它们。nose2适用于大型项目,其中测试发现可以节省时间。与pytest一样,它可以运行unittest测试套件,因此如果您正在从unittest迁移但希望保留现有的测试,它也是一个不错的选择。

最后,还有doctest。这是 Python 标准库的另一个模块。它不像其他模块那样是一个功能齐全的测试框架,但它允许你直接在文档字符串中编写测试。doctest最适合简单的情况,你想演示如何使用一个函数或模块,并确认示例代码是否按预期工作。这是确保你的文档与代码保持最新的好方法。

Copilot Chat 建议我们使用unittest,所以我们会这样做。你可以自己尝试询问它,并看看它是否会得出不同的结论,这取决于你如何提问。

首先,我们将通过创建从unittest.TestCase类继承的类来定义测试用例。在编写我们的第一个单元测试时,我们将发现一个相当隐匿的错误,这个错误迄今为止一直使我们束手无策。我们马上就要解决这个问题了。最后,我们将测试DepartmentStatisticsVisitor类的正确性。

我们从提示开始,请 Copilot Chat 创建一个DepartmentStatisticsVisitor的单元测试。回复将提醒我们上下文的重要性。Copilot Chat,考虑到我们开始了一个新的聊天会话,将尝试创建这个单元测试,但它缺乏我们任何类的定义。

列表 6.1:为DepartmentStatisticsVisitor定义单元测试的第一次尝试
import unittest
from department_visitor import DepartmentStatisticsVisitor
class TestDepartmentStatisticsVisitor(unittest.TestCase):
    def test_visit_department(self):
        visitor = DepartmentStatisticsVisitor()
        department = {'name': 'Sales', 'employees': [{'name': 'John', 'salary': 50000}, {'name': 'Jane', 'salary': 60000}]}
        visitor.visit_department(department)
        self.assertEqual(visitor.total_salaries, 110000)
        self.assertEqual(visitor.num_employees, 2)
        self.assertEqual(visitor.avg_salary, 55000)

我们应该继续将定义输入到 Copilot Chat 中,以便它可以完善测试用例。我们可以告诉它更多关于访问者类的信息,如下面的代码片段所示。

The DepartmentStatisticsVisitor class visits to determine the total asset depreciation based off of the asset allocation for each department

有了这些更新的信息,Copilot Chat 即将更好地估计我们的单元测试应该如何运行。

列表 6.1:为DepartmentStatisticsVisitor定义单元测试的第一次尝试
import unittest
from department_visitor import DepartmentStatisticsVisitor, Asset
class TestDepartmentStatisticsVisitor(unittest.TestCase):
    def test_visit(self):
        visitor = DepartmentStatisticsVisitor()
        asset1 = Asset(1000, 500, 0.5)
        asset2 = Asset(2000, 1000, 0.3)
        visitor.visit(asset1)
        visitor.visit(asset2)
        self.assertEqual(visitor.get_total_cost(), 3000)
        self.assertEqual(visitor.get_total_depreciation(), 1500)
        self.assertEqual(visitor.get_total_allocation(), 0.8)

单元测试接近所需的内容;但是,Asset 的定义是错误的。我们应该从我们的 asset.py 类中输入正确的定义。Copilot 聊天将继续完善单元测试。

第 6.2 节 在 Copilot 聊天了解如何定义 Asset 后,对 DepartmentStatisticsVisitor n 定义单元测试的下一次尝试。
import unittest
from datetime import date
from typing import List
from dataclasses import dataclass
@dataclass
class Location:
    name: str
    address: str
@dataclass
class Asset:
    id: int
    name: str
    status: str
    category: str
    cost: float
    useful_life: int
    salvage_value: float
    purchase_date: date
    locations: List[Location]
class TestAsset(unittest.TestCase):
    def test_asset(self):
        location1 = Location('Office', '123 Main St')
        location2 = Location('Warehouse', '456 Elm St')
        asset = Asset(1, 'Computer', 'In use', 'Hardware', 1000.0, 3, 100.0, date.today(), [location1, location2])
        self.assertEqual(asset.id, 1)
        self.assertEqual(asset.name, 'Computer')
        self.assertEqual(asset.status, 'In use')
        self.assertEqual(asset.category, 'Hardware')
        self.assertEqual(asset.cost, 1000.0)
        self.assertEqual(asset.useful_life, 3)
        self.assertEqual(asset.salvage_value, 100.0)
        self.assertEqual(asset.purchase_date, date.today())
        self.assertEqual(asset.locations, [location1, location2])

这更接近了,我们还应该提醒 Copilot 聊天,Asset 类还有一个名为 FundingDetails 的类。一旦我们提供了 FundingDetails 的定义,并告知 Copilot 聊天它应该是 Asset 的一部分,我们就更接近了。

第 6.3 节 第三次尝试编写一个相当接近的单元测试。
import unittest
from department_visitor import DepartmentStatisticsVisitor, Asset, FundingDetails
from datetime import date
from typing import List, Dict
from dataclasses import dataclass
@dataclass
class Location:
    name: str
    address: str
class TestDepartmentStatisticsVisitor(unittest.TestCase):
    def test_visit(self):
        visitor = DepartmentStatisticsVisitor()
        location1 = Location('Office', '123 Main St')
        location2 = Location('Warehouse', '456 Elm St')
        asset1 = Asset(1, 'Computer', 'In use', 'Hardware', 1000.0, 3, 100.0, date.today(), [location1, location2])
        asset2 = Asset(2, 'Printer', 'In use', 'Hardware', 500.0, 2, 50.0, date.today(), [location1])
        funding_details1 = FundingDetails(asset1, 'Straight Line', 0.33, { 'IT': 0.5, 'HR': 0.5 })
        funding_details2 = FundingDetails(asset2, 'Double Declining Balance', 0.25, { 'IT': 0.3, 'HR': 0.7 })
        visitor.visit(asset1, funding_details1)
        visitor.visit(asset2, funding_details2)
        self.assertEqual(visitor.get_total_cost(), 1500.0)
        self.assertEqual(visitor.get_total_depreciation(), 550.0)
        self.assertEqual(visitor.get_total_allocation(), 0.8)

唯一需要手动更新的是导入语句。

注意

让这个练习成为对使用大型语言模型的警示,强迫它们在高度专注的任务上表现得很具有挑战性,甚至可能不值得付出这种努力。在现实世界中,没有人会责怪您放弃提示工程,而回到只是编写出这个测试的代码。然而,通过一些坚持,您可能能够建立一个模板库,用于构建一套类似形状的类的单元测试。另一个额外的注意是 Copilot 聊天可以生成编辑器窗口中文件的测试,如果您指示它“为我的代码生成一个单元测试”,但是,它将模拟所有不直接属于正在测试的类的对象/属性。根据您尝试测试的内容,此功能的效用可能值得怀疑。

当我们尝试运行此测试时,我们发现 visitor、asset、funding details 和 depreciation strategy 之间存在循环依赖。循环依赖是指两个或多个模块或组件直接或间接地彼此依赖的情况。在我们的情况下,当 Python 尝试实例化 Asset 时,它会加载 FundingDetails 的定义。

我们通过摆脱对 FundingDetails 类的直接实例化或引用来修复这个问题。

第 6.4 节 更新后的 Asset 类,不再直接引用 FundingDetails 类。
@dataclass
class Asset():
    id: int
    name: str
    status: str
    category: str
    cost: float
    useful_life: int
    salvage_value: float
    purchase_date: date
    locations: List[Location]
    funding_details: None or 'itam.domain.funding_details.FundingDetails'

我们需要对 FundingDetails 类执行相同的操作。它不应该直接引用 DepreciationStrategy 类。

第 6.5 节 更新后的 FundingDetails 类,不再直接引用 DepreciationStrategy 类。
@dataclass
class FundingDetails:
    depreciation_rate: float
    department_allocations: Dict[Department, float]
    depreciation_strategy: DepreciationStrategy or 'itam.domain.depreciation_strategy.DepreciationStrategy'
    asset: None or 'itam.domain.asset.Asset'

正如我们所见,我们能够使用 Copilot 聊天创建一个单元测试。然而,如果我们没有使用 Copilot,可能会更容易地创建它。这个工具非常擅长提供何时以及如何测试您的代码的指导,但是实施(至少目前)还有待改进。

在现实世界中,我们将继续添加单元测试来建立一个实质性的测试体系。你可能会问,什么样的测试是实质性的?我们马上就会探讨这个问题。但是,我们应该首先把注意力转向下一种类型的测试:集成测试

集成测试

集成测试涉及测试软件的不同组件或模块之间的交互,以确保它们能够无缝地配合工作。它验证集成系统是否按预期功能,并检测模块之间的任何不一致或通信问题。

6.1.2 集成测试

在本节中,我们将开发一个集成测试,以便测试端到端的系统。幸运的是,fastapi 自带了自己的测试客户端,这将帮助我们创建这个测试。

我们首先将 AssetController 的定义复制到 Copilot Chat 窗口中。然后我们可以询问 Copilot Chat 如何为这个控制器创建集成测试。鉴于我们在定义中包含了路由,Copilot Chat 应该能够为我们提供准确的集成测试。我们需要指定我们将使用 InMemoryAssetRepository 类,或者在生成测试后修复它。

列表 6.6 AssetController 生成的 Copilot Chat 集成测试
from fastapi.testclient import TestClient
from itam.infrastructure.adapters.memory_asset_repository import MemoryAssetRepository
from itam.infrastructure.ports.asset_rest_port import AssetRestPort
from itam.interfaces.asset_controller import AssetController
def test_get_assets():
    # Create an instance of the InMemoryAssetRepository
    asset_repository = InMemoryAssetRepository()
    # Add some assets to the repository
    asset_repository.create(Asset(name="Asset 1", unit_cost=1000))
    asset_repository.create(Asset(name="Asset 2", unit_cost=2000))
    # Create an instance of the AssetRestPort using the MemoryAssetRepository
    asset_rest_port = AssetRestPort(asset_repository)
    # Create an instance of the AssetController using the AssetRestPort
    asset_controller = AssetController(asset_rest_port)
    # Create a TestClient instance using the AssetController's router
    client = TestClient(asset_controller.get_router())
    # Send a GET request to the /assets endpoint
    response = client.get("/assets")
    # Check that the response status code is 200 OK
    assert response.status_code == 200
    # Check that the response body contains the expected assets
    assert response.json() == [
        {"id": 1, "name": "Asset 1", "unit_cost": 1000},
        {"id": 2, "name": "Asset 2", "unit_cost": 2000},

现在我们将注意力转向我们要检查的最后一种测试类型:行为测试

行为测试

行为测试是一种侧重于系统整体行为的测试类型,从最终用户的角度来看待。行为测试通常用于测试系统的功能,并确保它符合为其定义的要求和规范。

6.1.3 行为测试

从某种意义上说,所有测试都是行为测试,因为测试验证系统的行为。然而,行为测试在某些方面是独特的。让我们总结一下到目前为止我们遇到的不同类型的测试,并将其与行为测试进行对比。

单元测试是一种侧重于测试系统的单个单元或组件的测试类型,通常使用自动化测试。单元测试旨在测试单个函数或方法的功能,并确保它们在各种条件下表现正确。

另一方面,集成测试是一种侧重于测试系统的不同组件或单元之间的交互的测试类型。集成测试通常用于测试不同组件或单元之间的接口,并确保它们正确地配合工作。集成测试可以手动执行或使用自动化测试,并且通常涉及测试系统的不同组件或单元之间的交互,而不是整个系统。

行为测试侧重于根据用户故事或场景定义软件的行为。这些场景以一种特定的格式写入,称为“给定-当-那么”(GWT),用于驱动开发过程。GWT 格式描述了特定场景的前提条件(给定)、操作(当)和预期结果(那么)。

随着我们在测试中的进展,我们可能会发现一些行为或组件在我们的测试中很难设置。此外,我们可能会发现难以隔离特定对象或模块的行为,并测试不同对象之间的交互。为了解决这个限制,我们可以使用一个模拟对象

模拟对象

模拟对象是一种以受控方式模拟真实对象行为的测试替身。它们也可以用来模拟难以通过真实对象复制的错误条件或边缘情况。模拟对象可以手动创建,使用诸如unittest.mockpytest-mock等模拟库。这些库提供了用于创建和配置模拟对象的函数和类。模拟对象可以配置为在调用其方法时返回特定值或引发特定异常。它们还可以用于记录对其方法的调用,以便您可以验证是否正确地使用了正确的参数调用了正确的方法。

我们将在提示中引入模拟对象,以创建AssetManager的行为测试。

列表 6.7 设置AssetManager行为测试的提示
We have a class called AssetManager. AssetManager's constructor takes two class BaseRepository and AssetLocationMediator. The BaseRepository is a repository in which Assets are stored. We want to use InMemoryAssetRepository, which is a subclass of BaseRepository that stores the Assets in memory. Use a mock object for AssetLocationMediator. The AssetManager stores Assets using the method create and gets all of the Assets using the method get_assets. An asset has 10 required positional arguments: 'id', 'name', 'status', 'category', 'cost', 'useful_life', 'salvage_value', 'purchase_date', 'locations', and 'funding_details'. Use named parameters to make it clear which param is going where. Create a BDD script that will add two Assets to the AssetManager, confirming that all Assets cost $4000.00\. This should be implemented in Python. Take it step by step, telling us the tools and libraries you will use.

Copilot Chat 将告诉我们需要创建一个名为asset_manager.feature的新文件(称为特性文件)。在这个文件中,我们将定义AssetManager的属性(以及任何支持类)。例如,在特性文件中定义了一个场景,将两个资产添加到AssetManager,确认所有资产的总成本为$4000.00,并模拟AssetLocationMediator类。

列表 6.8 根据 Copilot Chat 定义的asset_manager.feature文件
Feature: Asset Manager
  As an IT Asset Manager
  I want to be able to manage assets
  So that I can keep track of all IT assets in my organization
  Scenario: Add two assets to the Asset Manager
    Given the Asset Manager is running
    And the InMemoryAssetRepository is initialized
    And the AssetLocationMediator is mocked
    When I create an asset with a cost of $2000.00
    And I create another asset with a cost of $2000.00
    Then the total cost of all assets should be $4000.00

我们应该在项目的根目录中创建一个名为features的目录。我们应该将这个文件放在那个目录中。此外,我们应该添加一个名为steps的子目录。我们将很快得到steps

接下来,我们将创建一个名为 steps.py 的新 Python 文件,并将其放置在 steps 目录中。这个 Python 文件定义了用于场景的步骤实现。AssetManagerInMemoryAssetRepositoryAssetLocationMediatorAsset 类被导入,并定义了六个函数来对应场景中的步骤。这些函数使用 context 对象在步骤之间存储和检索数据。使用 unittest.mock 库的 Mock 类来为 AssetLocationMediator 类创建一个模拟对象。Asset 类使用命名参数来实例化,以澄清哪个参数属于哪个属性。如果我们向 Copilot Chat 请求 steps.py 文件的内容,我们将看到类似以下列表的输出。

列出 6.9 我们在 steps.py 中定义的行为测试的实现细节
from behave import given, when, then
from itam.service.asset_manager import AssetManager
from itam.infrastructure.repository.in_memory_asset_repository import InMemoryAssetRepository
from itam.domain.asset import Asset
from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator
from unittest.mock import Mock
@given('the Asset Manager is running')
def step_impl(context):
    context.asset_repository = InMemoryAssetRepository()
    context.asset_location_mediator = Mock(spec=AssetLocationMediator)
    context.asset_manager = AssetManager(context.asset_repository, context.asset_location_mediator)
@given('the InMemoryAssetRepository is initialized')
def step_impl(context):
    pass
@given('the AssetLocationMediator is mocked')
def step_impl(context):
    pass
@when('I create an asset with a cost of ${cost}')
def step_impl(context, cost):
    asset = Asset(id=1, name='Test Asset 1', status='Available', category='Test Category', cost=float(cost), useful_life=5, salvage_value=0, purchase_date='2022-01-01', locations=['Test Location'], funding_details={'Test Funding': 1000})
    context.asset_manager.create(asset)
@when('I create another asset with a cost of ${cost}')
def step_impl(context, cost):
    asset = Asset(id=2, name='Test Asset 2', status='Available', category='Test Category', cost=float(cost), useful_life=5, salvage_value=0, purchase_date='2022-01-01', locations=['Test Location'], funding_details={'Test Funding': 1000})
    context.asset_manager.create(asset)
@then('the total cost of all assets should be ${total_cost}')
def step_impl(context, total_cost):
    assets = context.asset_manager.get_assets()
    assert sum(asset.cost for asset in assets) == float(total_cost)

如果您尚未安装它,请使用 pip 安装 behave 库:pip install behave. 此外,您应将其添加到 requirements.txt 文件中,以确保在稍后构建可部署版本的此应用程序时会被引入。我们将通过从项目的根目录发出以下命令来运行行为测试。

列出 6.10 运行行为测试并生成输出
% behave features
Feature: Asset Manager # features/asset_manager.feature:1
  As an IT Asset Manager
  I want to be able to manage assets
  So that I can keep track of all IT assets in my organization
  Scenario: Add two assets to the Asset Manager          # features/asset_manager.feature:6
    Given the Asset Manager is running                   # features/steps/steps.py:8 0.000s
    And the InMemoryAssetRepository is initialized       # features/steps/steps.py:14 0.000s
    And the AssetLocationMediator is mocked              # features/steps/steps.py:18 0.000s
    When I create an asset with a cost of $2000.00       # features/steps/steps.py:22 0.000s
    And I create another asset with a cost of $2000.00   # features/steps/steps.py:27 0.000s
    Then the total cost of all assets should be $4000.00 # features/steps/steps.py:32 0.000s
1 feature passed, 0 failed, 0 skipped
1 scenario passed, 0 failed, 0 skipped
6 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.001s

在本节中,我们通过使用三种类型的测试:单元测试、集成测试和行为测试,为良好的软件开发奠定了基础。现在,有人可能会争辩说它在项目的开发生命周期中出现得很晚。这个争论也不无道理。在现实世界中,我们会在开发代码时开发我们的测试。有些人可能会认为我们应该在编写代码之前构建测试。您可能持有这种信念,也可能不持有,但无论如何,您都应该尽早测试,并经常测试。

在本书的下一部分中,我们将深入研究一些可用于确定我们软件总体质量的指标,并请求 Copilot 帮助我们评估到目前为止我们代码的质量。

6.2 评估质量

理解软件应用程序的性能、可靠性、可维护性和总体质量是软件工程的重要方面。本章将深入探讨软件质量指标领域的迷人和复杂内容 – 这些量化标准和基准指导我们理解软件系统质量的。

软件质量指标是必不可少的工具,它允许利益相关者 – 开发人员、测试人员、经理和用户 – 评估软件产品的状态,识别其优点和改进空间。它们为产品开发、测试、调试、维护和改进倡议等各种流程提供了经验基础。通过量化软件的特定特性,这些指标提供了一种具体的方法来理解软件质量这一抽象概念。

在本节中,我们将探讨软件质量度量的几个重要类别,包括产品度量、过程度量和项目度量。我们将分析它们的重要性、计算方法以及如何有效利用它们来评估和提高软件质量。这个探讨将包括静态度量,即应用于静态软件系统的度量,以及动态度量,它们评估系统在执行过程中的行为。

软件质量度量不仅有助于软件系统的技术完整性,还有助于确保客户满意度、盈利能力和长期的商业成功。因此,了解这些度量是对软件开发领域的任何从业人员都是非常宝贵的,从工程师和项目经理到高管和软件用户。

在本节中,我们将研究类或代码复杂性和可维护性的一些常见指标。复杂的软件很难理解,这使得开发人员,尤其是新手开发人员,很难把握软件不同部分是如何相互交互的。这可能会减慢员工的适应速度和开发时间。

复杂的代码往往会导致更高的维护工作量。当代码复杂时,修改或修复 bug 可能需要更长的时间,因为很难预测改动系统中某一部分的影响。这可能会导致软件整个生命周期的更高成本。

复杂的软件往往更容易出错。因为它更难理解,开发人员在进行改动时更有可能引入 bug。此外,复杂的代码可能存在许多相互依赖的关系,一处的改动可能在其他地方产生意想不到的影响。

软件越复杂,就需要更多的测试用例来进行彻底测试。由于涉及逻辑的复杂性,编写这些测试用例可能也更加困难。

编写简单和易维护的代码应该是我们的首要任务之一。观察与我们的代码相伴的度量变化应该有助于我们在这方面的努力。在这个目标的推动下,我们可以(也应该)首先使用的度量是圈复杂度

圈复杂度

圈复杂度是量化软件模块中独立路径的数量的度量。它衡量了代码中的决策复杂性,包括循环、条件和分支。较高的圈复杂度值表示增加的复杂性,并暗示着可能存在更多的 bug 和理解、维护代码的挑战。

在文件 department_visitor.py 中,输入片段 6.3 的提示任何位置。Copilot 将立即输出答案。

# Question: What is the cyclomatic complexity of the class DepartmentStatisticsVisitor?
# Answer: 1

Copilot 会告诉您这个类的复杂性为 1。您可能不清楚这个值的含义。如果是后者,您可以要求 Copilot 加以解释。

# Question: Is 1 an excellent cyclomatic complexity?
# Answer: Yes
# Question: Why is one a good value for cyclomatic complexity?
# Answer: Because it is low

Copilot 告诉我们,如果圈复杂度低,则好。 这在直觉上是有道理的。 代码复杂度低意味着更容易理解,因此更容易理解和推理。 也更有可能更容易维护。 我们将要探讨的下一个指标是Halstead 复杂度度量

Halstead 复杂度度量

Halstead 复杂度度量评估软件程序的复杂性,基于代码中使用的唯一运算符和操作数的数量。 这些度量包括程序长度(N1)、程序词汇量(n1)、体积(V)、难度(D)、工作量(E)等。 这些度量提供了有关代码的大小和认知复杂性的见解。

与上次类似,我们将从一个提示开始,要求 Copilot 确定我们的访问者类的 Halstead 复杂度度量。

# Question: What is the Halstead Complexity Measure of the class DepartmentStatisticsVisitor?
# Answer: 2
# Question: What is the Halstead Difficulty Measure of the class DepartmentStatisticsVisitor?
# Answer: 1
# Question: Is 2 a good Halstead Complexity Measure?
# Answer: Yes
# Question: Is 1 a good Halstead Difficulty Measure?
# Answer: Yes
# Question: What is a bad Halstead Difficulty Measure?
# Answer: 10
# Question: What is a bad Halstead Complexity Measure?
# Answer: 10
# Question: What does a high Halstead Difficulty Measures mean?
# Answer: It means that the code is hard to understand

您可能想要继续进行一段时间的问答会话,以查看 Copilot 可以从中获取的信息。 一旦您准备好继续,还有一个指标要探讨:可维护性指数

可维护性指数

可维护性指数是一个综合指标,结合了多个因素,包括圈复杂度、代码行数和 Halstead 复杂度度量,以提供软件可维护性的整体度量。 更高的可维护性指数表示更容易维护和潜在较低的复杂性。

您应该在访问者文件中开始一个类似的讨论,以了解可维护性指数。

# Question: What is the maintainability index of the class DepartmentStatisticsVisitor?
# Answer: 100
# Question: Do we want a high Maintainability Index or low Maintainability Index?
# Answer: high
# Question: Why do we want a high Maintainability Index?
# Answer: Because it is easier to maintain

如果我们得到一个较低的可维护性指数,我们可以重构以减少这个数字。 指标在于它给了我们一个钉子来挂我们的帽子;也就是说,我们可以采取这个措施来改善它。 指标使我们超越了个体的纯美感或主观性。 指标是真实的、可操作的数据。 但 Copilot 还有(至少)一项更多的技巧。 Copilot 不仅能够编写和评估我们的代码,还可以解决代码的缺陷。 让我们来捕虫吧。

AI 驱动的开发者(MEAP)(二)(4)https://developer.aliyun.com/article/1516333

相关文章
|
7天前
|
人工智能 数据管理 API
阿里云百炼又获大奖!阿里云百炼入选 2024 最受开发者欢迎的 AI 应用开发平台榜15强
2024年最受开发者欢迎的AI应用开发平台榜单发布,阿里云百炼入选15强。持续推动AI开发者生态建设,提供开放平台、培训支持、行业解决方案,注重数据安全与合规,致力于生态合作与共赢,加速企业数智化转型。
|
6天前
|
机器学习/深度学习 人工智能 算法
转载:【AI系统】AI 发展驱动力
本文介绍了AI的起源与发展历程,强调了2016年AlphaGo胜利对AI关注度的提升。文中详细解析了AI技术在搜索引擎、图片检索、广告推荐等领域的应用,并阐述了机器学习、深度学习和神经网络之间的关系。文章还深入探讨了AI的学习方法,包括模型的输入输出确定、模型设计与开发、训练过程(前向传播、反向传播、梯度更新)及推理过程。最后,文章概述了AI算法的现状与发展趋势,以及AI系统出现的背景,包括大数据、算法进步和算力提升三大关键因素。
转载:【AI系统】AI 发展驱动力
|
18天前
|
机器学习/深度学习 人工智能 自然语言处理
AI驱动的个性化学习路径优化
在当前教育领域,个性化学习正逐渐成为一种趋势。本文探讨了如何利用人工智能技术来优化个性化学习路径,提高学习效率和质量。通过分析学生的学习行为、偏好和表现,AI可以动态调整学习内容和难度,实现真正的因材施教。文章还讨论了实施这种技术所面临的挑战和潜在的解决方案。
53 7
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
智能化软件测试:AI驱动的自动化测试策略与实践####
本文深入探讨了人工智能(AI)在软件测试领域的创新应用,通过分析AI技术如何优化测试流程、提升测试效率及质量,阐述了智能化软件测试的核心价值。文章首先概述了传统软件测试面临的挑战,随后详细介绍了AI驱动的自动化测试工具与框架,包括自然语言处理(NLP)、机器学习(ML)算法在缺陷预测、测试用例生成及自动化回归测试中的应用实例。最后,文章展望了智能化软件测试的未来发展趋势,强调了持续学习与适应能力对于保持测试策略有效性的重要性。 ####
|
21天前
|
机器学习/深度学习 人工智能 算法
【AI系统】AI芯片驱动智能革命
本课程深入解析AI模型设计演进,探讨AI算法如何影响AI芯片设计,涵盖CPU、GPU、FPGA、ASIC等主流AI芯片,旨在全面理解AI系统体系,适应后摩尔定律时代的技术挑战。
34 5
|
19天前
|
人工智能 机器人 数据库
使用FlowiseAI轻松搭建AI驱动的交互式应用
FlowiseAI 是一款开源低代码工具,旨在帮助开发者构建自定义的语言学习模型应用。它提供拖放界面,支持与多种AI模型和数据库集成,适用于创建聊天机器人等交互式应用。使用阿里云的计算巢,用户可通过一键部署快速启动FlowiseAI,并通过简单的步骤配置和运行自定义的LLM应用。
|
20天前
|
人工智能 大数据 云计算
【AI系统】AI 发展驱动力
本文介绍了阿里云在2023年云栖大会上发布的多项新技术和产品,涵盖云计算、大数据、人工智能等领域,展示了阿里云最新的技术成果和行业解决方案,助力企业数字化转型。
|
22天前
|
数据采集 人工智能 机器人
AMD的CIO谈AI驱动转型和IT的未来
AMD的CIO谈AI驱动转型和IT的未来
|
25天前
|
机器学习/深度学习 人工智能 运维
智能运维:AI驱动的IT运维革命###
【10月更文挑战第21天】 随着数字化转型的深入,智能运维(AIOps)正逐步成为企业IT管理的核心。本文将探讨AI技术如何赋能运维领域,通过自动化、智能化手段提升系统稳定性和效率,降低运营成本,并分享实施智能运维的最佳实践与挑战应对策略。 ###
51 1
|
22天前
|
机器学习/深度学习 人工智能 自然语言处理
【AI系统】AI 发展驱动力
AI起源于20世纪50年代,经历起伏后,2016年AlphaGo的胜利重燃公众热情。实际上,AI技术早已在互联网公司广泛应用,如搜索引擎、广告推荐等。机器学习是实现AI的方法之一,深度学习则是机器学习的重要技术,通过神经网络实现。近年来,随着大数据积累、算法进步及算力增强,AI取得了显著成就,特别是在图像识别、自然语言处理等领域。AI系统的设计需考虑数据驱动、算法优化及高性能计算,以适应更大规模、更复杂的应用需求。
58 0