玩游戏代码=:}高效敏捷方法 (中文 (Chinese Simplified))

玩游戏代码=:}高效敏捷方法

Sunday, 23 November 2025

//

9 minute read

为何当你的分行是沙箱? —? 和作为合法工作玩耍?

热辣辣椒 多数开发商都试图在发展的各个阶段做到完美,

一. 导言导言 导言 导言 导言

I' 一直在为"... 好了,,"而专业地建立软件 只是说我记得 当""Agile""是一个新想法

这些年来,, I' 已经注意到一些事情 : 播放权限最差的代码来自每个键盘都觉得被仔细检查过的项目 , 我试图从第一分钟开始 写"

这是意外事件 . 创意与压力

因此,I'已经开发出一种方法 将乱七八糟的,创意探索与光滑的,生产区分开来让它运作起来,让它漂亮一点@" @ @ - @ 但其实是, @ it@'}关于允许自己在没有完美重量的情况下进行实验,

三阶段

让我先说清楚 : 这是关于草率或避免纪律的 在适当的时候运用正确的纪律.

graph LR
    subgraph "Phase 1: Make It Work"
        A[New Requirement] --> B[Explore & Experiment]
        B --> C{Does It Work?}
        C -->|No| D[Try Different Approach]
        D --> B
        C -->|Yes| E[Basic Solution]
    end

    subgraph "Phase 2: Make It Pretty"
        E --> F[Refactor & Clean]
        F --> G[Apply SOLID Pragmatically]
        G --> H[Get Stakeholder Feedback]
        H --> I[Polished Solution]
    end

    subgraph "Phase 3: Lock It Down"
        I --> J[Add Tests]
        J --> K[Security Review]
        K --> L[Add Monitoring]
        L --> M[Production Ready]
    end

    style A stroke:#f59e0b,stroke-width:3px
    style E stroke:#0ea5e9,stroke-width:3px
    style I stroke:#8b5cf6,stroke-width:3px
    style M stroke:#10b981,stroke-width:4px

阶段"1: 使它发挥作用

咒语: 首先播放“.”确认您的假设 “.” 获取正在运行的“MS K2”

这就是你的分支是沙箱的阶段 MSMK0 误差代码是好的 . 罚款“. ”您不是在这里建教堂吗?“;” 您是在餐巾纸上画的草图

你试图找出什么 :

  • 此 API 实际上是否表现得如何, 医生们声称 @? @ @ ( @Spoiler@: @ 它很少做 @MS K3}
  • 我能用我拥有的工具来解决这个问题吗?
  • 实际要求是多少?
  • 这是两个时间问题还是两周问题?

关键洞察力 直到你升起一个PL, 你的分行就是 您 的I',但每次在Optechnology , 承诺和推动. Hook 进入你的CI输油管时 没有人需要看到你的假启动吗? , 你的评论=-}解调代码@, *你的评论"*TODO}这太可怕了

附带利益=: 常务是心跳.在远程MS K1async队}♪,穩定的足迹"{"但进展中〞"承诺让每个人都放心,

这个心理自由是必需的 @. 当你知道你可以把一切都扔掉, 并开始新鲜的@,}你就会做出更大胆的决定. 你尝试那种可能赢得'_t working}.}有时它会很成功 不是一个特质.

// Phase 1 code looks like this - and THAT'S OKAY
public async Task<Result> ProcessThing(Request req)
{
    // TODO: what if this is null?
    var data = await _api.GetSomething(req.Id);

    // This probably isn't right but let's see what happens
    var transformed = data.Items
        .Where(x => x.Status != "deleted") // Is this the right filter?
        .Select(x => new Thing { Name = x.Name }); // Missing loads of fields

    // HACK: hardcoded for now
    return new Result { Items = transformed.ToList(), Total = 42 };
}

这是生产代码吗? ?? 上帝没有! 它有用吗?

关于反馈的说明:* 您可以在下列时间获得反馈 任何 正在选择的密钥 人 或 目标是建立最佳功能... ...,,不要遵循僵硬的流程.

建立另一个团队将消费的API, 另一个团队将会消耗#?}让它们参与进来 早点做一个. 一个快速的“"%does”这个形状就有意义了..."?"}对话可以节省重新工作的日子 外观 而不是它是否 工程@.}他们在「2.」的阶段里提供反馈。

使用您的判断@. @% 有时您需要反馈 澄清@ , @ 不批准@ MS K1 @ spec 已做此决定: @ . @ @ I"_ spect 上面写着“ '} handle 差错 优雅地” @'— @does, 意思是重试三次+, @ 或快速失败, 然后通知@?"@ that'_ 是一个阶段 @ MPK9# talking MSG10 @

如果一个利益攸关方@' @%s 输入是关键, 但是他们与粗略代码“ ,” 的争斗会构建一个微不足道的演示 < . > a hardcoded happy*-path, 它能显示这个概念可以解开有价值的反馈, 而不会分散缺失边缘案例的注意力}

切换实用性:.+B 目标为最佳特征 @,_BARBAR_纯度进程=.}

阶段2: 使它美丽

咒语: 现在你知道自己在建什么了了吗? 良好.

探索阶段已经完成了它的工作 “.你 '你确认了这个方法的功效 你理解问题的形状“,” 而您可能发现了十几个边缘病例 最初的票号是"'T提到'.′

现在你把它清理干净吧 :

// Phase 2: Same logic, but actually maintainable
public async Task<ProcessingResult> ProcessItemsAsync(
    ProcessingRequest request,
    CancellationToken cancellationToken = default)
{
    ArgumentNullException.ThrowIfNull(request);

    var items = await _itemRepository.GetActiveItemsAsync(
        request.AccountId,
        cancellationToken);

    var processedItems = items
        .Where(item => item.Status != ItemStatus.Deleted)
        .Select(item => _mapper.ToProcessedItem(item))
        .ToList();

    return new ProcessingResult
    {
        Items = processedItems,
        TotalCount = processedItems.Count,
        ProcessedAt = _timeProvider.UtcNow
    };
}

这里就是你的 :

  • 适用SOLID原则 注重实际 {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}但不要崇拜他们
  • 给事物以适当名称
  • 添加类型提示和 XML 文档
  • 从调用器@'s 角度考虑 API 表面
  • 处理您在“1”阶段发现的边缘病例

关键地说,,这是非-的最佳时机 技术利益攸关方反馈=. 该功能现已可见且可用@ , @ {但您已经有'} 还没有投入时间来为它进行写作测试 MS K2} 如果他们说“ "” 其实是 @ MSSK4} 我们想要做 X 而不是 “,"” 您可以在删除一个综合测试套件时不心碎地跳过

阶段3:锁定它

咒语: 让它具有弹性 .

Now — @ @ @ and only now @—}你才寫下你的測試.#新增安全檢查@. 實施生产邊緣病例的正確錯誤處理Q.}新增監控與守護列 *.}

为什么等到现在 你终于知道自己在测试什么.

在“1”阶段中写作的测试本会是错误的 @—}你没有理解问题 但是在 “2” 阶段里写的._Tests 正确@,#因为执行稳定 #.#

[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(100)]
public async Task ProcessItemsAsync_WithValidRequest_ReturnsCorrectCount(
    int itemCount)
{
    // Arrange
    var items = _fixture.CreateMany<Item>(itemCount).ToList();
    _mockRepository
        .Setup(r => r.GetActiveItemsAsync(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(items);

    // Act
    var result = await _sut.ProcessItemsAsync(
        new ProcessingRequest { AccountId = Guid.NewGuid() });

    // Assert
    result.TotalCount.Should().Be(itemCount);
    result.Items.Should().HaveCount(itemCount);
}

[Fact]
public async Task ProcessItemsAsync_WithNullRequest_ThrowsArgumentNullException()
{
    // Act & Assert
    await _sut.Invoking(s => s.ProcessItemsAsync(null!))
        .Should().ThrowAsync<ArgumentNullException>();
}

[Fact]
public async Task ProcessItemsAsync_ExcludesDeletedItems()
{
    // Arrange
    var items = new[]
    {
        new Item { Status = ItemStatus.Active },
        new Item { Status = ItemStatus.Deleted },
        new Item { Status = ItemStatus.Active }
    };
    _mockRepository
        .Setup(r => r.GetActiveItemsAsync(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(items);

    // Act
    var result = await _sut.ProcessItemsAsync(
        new ProcessingRequest { AccountId = Guid.NewGuid() });

    // Assert
    result.Items.Should().HaveCount(2);
}

这一阶段还包括:

  • 安全审查: @(@auditation_,}授权,}输入验证=)}
  • 组合货币因素 @(}在负载下发生的一切*?)
  • 失败模式分析@( @ what if the database is slow #?}如果 API 乘以% ?)#
  • 监控我们如何知道这种生产中断?

反馈编程

不同的人应该参与到不同阶段... ..."."你搞错了,你会沉溺在摩擦中

graph TB
    subgraph "Phase 1: Technical Voices"
        P1[Make It Work] --> T1[Senior Dev Review]
        T1 --> T2["Does the approach<br/>make sense?"]
        T2 --> T3["Any obvious<br/>architectural issues?"]
    end

    subgraph "Phase 2: Non-Technical Voices"
        P2[Make It Pretty] --> N1[Product Owner Demo]
        N1 --> N2["Does it meet<br/>the requirement?"]
        N2 --> N3["Is the UX<br/>intuitive?"]
    end

    subgraph "Phase 3: Ops/Security Voices"
        P3[Lock It Down] --> O1[Security Review]
        O1 --> O2[Operations Review]
        O2 --> O3["Will it hold up<br/>in production?"]
    end

    T3 --> P2
    N3 --> P3

    style T1 stroke:#3b82f6,stroke-width:2px
    style N1 stroke:#8b5cf6,stroke-width:2px
    style O1 stroke:#ef4444,stroke-width:2px

阶段1: 科技界的利益攸关方会因粗略代码而惊慌并询问按钮颜色,

阶段2: 非- 技术声音欢迎@. @% 此功能可用@ , @ buttons do things @ MS K3} 让产品所有者和设计者参与进来吧$—#changes are still cheap *,}你已经拥有了'_ t书面测试@.}

阶段3: 若有人通过恶意输入 ?" 仅当功能真正有效时才重要 @.

作为沙箱的分支

这里的' 改变了我的发展生活 直到你升起一个PR,, 你的分行是完全私人的.

但我看到开发商会处理每件事情 就像它一样... '...

我要你将你的特色分支 当作一个沙箱. 一个操场•. 一个实验室 那里预计会发生爆炸 没有人会受到伤害

graph TD
    A[Feature Branch Created] --> B[Experiment Freely]
    B --> C{Did it work?}
    C -->|No| D[Try Something Else]
    D --> B
    C -->|Yes| E[Clean Up the Mess]
    E --> F[Interactive Rebase]
    F --> G[Squash to Clean Commits]
    G --> H[Raise PR]
    H --> I[Public Code Review]

    style B stroke:#f59e0b,stroke-width:3px
    style D stroke:#f59e0b,stroke-width:2px
    style H stroke:#10b981,stroke-width:3px

    subgraph "Private - Go Mental"
        B
        C
        D
        E
    end

    subgraph "Public - Be Professional"
        H
        I
    end

在实践中,这代表着:

  • 经常提交@ , @ 即使代码是'_ t编译的
  • 写入 FIXME 和 TODO 各地的评论
  • 您正在探索时请保留调试代码@ ' @ label
  • 拥有多个@ "_ 尝试此方法 @ MS K1\ 承诺
  • @ '_ 不要担心发送信件@ MS K1_you'_ll global later @)}

在你升起PR:之前

  1. 清理代码“(”阶段 “2)”
  2. 添加测试@( @ 阶段 @ 3)}
  3. 交互反弹以粉碎所有混乱的历史
  4. 写入正确的承诺信件

PR审查员看到的是干净的, 专业代码,并有明确的叙事性. 他们没有看到6个错误开头吗?

沙箱保持私人状态 . 抛光工作公之于众

为何如此减轻压力

传统"在任何时候都是专业的 "发展正在粉碎." 每条线都感觉永久"MS K3" 每个决定都会感到后果. 通过抑制混乱来消除这种压力 游戏是合法工作 在“1,”阶段中,当轴线在“2,”阶段是廉价的时会收到反馈,测试一旦正确写入了 “3” 阶段,因为你终于知道什么是你''re testation".}

"Play是合法的工作

当域名被很好地理解或您're 锁定一个已知的错误时, TDD工作非常出色。 但是当问题仍然不明朗的时候, ,写测试通常意味着在行中三次检测错误的东西。

柔软的固态(和DRY'"肮脏的秘密)"

所以这三种“-”阶段的思维模式 对你的设计原理有什么影响呢? “?” 在简而言之, 它杀死了狗狗. 这里它如何改变我对 SOLID’, DRY,}和CQ#.中的界面的想法

我提到在“2.”阶段应用了SOLID原则,

SOLID是一套好的原则 我教他们.我使用它们 但I'曾见过球队 以"单一责任"或 Open/的名号 从抽象兔子洞中消失

在这里,' ~这是我的奢侈 ~: ~

当“:” 时应用 SOLID

  • 您有证据您需要灵活度
  • 抽象使代码更加清晰
  • 您正在建造其它用的东西

Doná't 使用 SOLID 当 @ :

  • 你怀疑未来的需求
  • 抽象性增加了复杂性,而没有清晰
  • 您正在建立只有您维持的内部代码

三个相似的代码线比一个不成熟的抽象线更好@ .} 当您看到这个模式清晰可见时, 您总是可以稍后提取 .\ _ 您可以 ' 无法轻易地解开在您的架构中烤熟了的抽象元素“ MS K3”\ Name.

// Over-engineered SOLID worship
public interface IThingProcessor { }
public interface IThingProcessorFactory { }
public class ThingProcessorFactory : IThingProcessorFactory { }
public class ThingProcessor : IThingProcessor { }
public class ThingProcessorDecorator : IThingProcessor { }
public class ThingProcessorValidationDecorator : IThingProcessor { }

// What you probably actually need
public class ThingProcessor
{
    public async Task<Result> ProcessAsync(Thing thing)
    {
        // Just do the thing
    }
}

如果您需要灵活性, 稍后@ , @ 重新设置是便宜的 @ MS K1+% Over-# 工程设计前方成本昂贵, 因为您在保留抽象层( 正在维持) '} # 没有赚钱来保持@ I. @ *

稻草陷阱

当我们屠杀神圣的牛群时 让我们谈论 试 “(Don'不重复你自己). ItMS K3}或许是我们行业中最教条性应用的原则 ‘,’当不加思索地运用它时, 它造成的伤害比好的还大。”

问题是这个: 并非所有重复工作都是同样的重复工作.

当两种代码看起来相似,但用途不同时 , 将它们带入一个共同的抽象夫妇中 应该独立进化的东西

  1. 添加处理这两个案件的参数和条件
  2. 打破另一个使用大小写
  3. 将共享代码复制出来并编辑@(_Admitting DRY是错误的 @)}这是错的
// "DRY" solution - looks clever, causes pain
public async Task<Result> ProcessEntity<T>(
    T entity,
    bool validateFirst = true,
    bool sendNotification = false,
    Func<T, bool>? customFilter = null,
    Action<T>? preProcess = null,
    Action<T>? postProcess = null) where T : IEntity
{
    // 50 lines of conditional spaghetti trying to handle
    // "processing" for Users, Orders, and Products
    // because they all had 3 similar lines once
}

// What you probably actually need
public async Task<Result> ProcessUser(User user) { /* 15 clear lines */ }
public async Task<Result> ProcessOrder(Order order) { /* 15 clear lines */ }
public async Task<Result> ProcessProduct(Product product) { /* 15 clear lines */ }

是的.}但每种方法都是:

  • 孤立地容易理解
  • 容易修改,无副作用
  • 当该实体类型消失时容易删除
  • 容易用明确的投入和产出进行测试

DRY 版本是一个要维持的噩梦, 因为它“'”试图成为所有呼叫者的所有事物。 “. ” 每一个变化都需要理解所有的使用案例 ‘. ’ 每个错误修正都有可能打破其它东西 ’. }

我的规则 : 保持重复,直到你看到 相同 你相信它代表着 相同 将会一起进化的理念 到那时为止 , 来点拷贝 MS K2\paste是好的 它不是道德上的失败

重复比错误的抽象更便宜@ . @ 您可以稍后在模式清晰时进行复制 .} 您可以 MS K2 不能轻易地解开一个错误的摘要, 它通过您的代码库编织了\ I'%s

C# 中的界面问题

这是又一头需要宰杀的圣母牛 每个班级都需要一个接口\ "}模式.

在“.NET 依赖性注射”的早期, 有人决定要制作代码测试@,}您需要在每个地方输入界面。逻辑是 @: 您可以模拟一个混凝土类,}所以每个服务都需要 IService 和 ServiceImpl@. 忽然每个 C# 代码库都堆满了纯用于测试@.}的单一#-实施接口

// The interface tax - early 2010s style
public interface IUserService { }
public interface IOrderService { }
public interface IEmailService { }
public interface INotificationService { }
public interface IPaymentProcessor { }
public interface IInventoryManager { }

// Each with exactly ONE implementation
public class UserService : IUserService { }
public class OrderService : IOrderService { }
// ... you get the idea

这是货物邪教编程... .... 我们为此缴纳了复杂税 理论理论 可检验性和可转让性 理论理论 很少实现的未来灵活性 @.

在这里,'的东西\ :}你不需要这个了?

现代模拟框架等 替代物 和 摩卡 以虚拟方法模拟混凝土类@(}更重要的是#,}ASPQ.NET Core{'}DI容器使用混凝固型態做得很好

// Modern approach - just register the concrete type
services.AddScoped<UserService>();
services.AddScoped<OrderService>();
services.AddScoped<EmailService>();

// In your controller or service
public class OrderController(OrderService orderService, UserService userService)
{
    // Primary constructor injection - clean and simple
}

无接口@. @ 否 IOrderService{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你需要什么服务?

"但是测试呢??" 我听到你哭泣的叫声

单位测试@, 您有选项 @:

  1. 制作密钥方法 virtual 使用模拟框架
  2. 使用测试数据库的实际服务@(集成检测通常更有价值,反之亦然 @)#
  3. 添加接口 当您实际需要测试时

第三点是关键 重构工具在提取接口方面特别好.

在骑士或视觉演播室 , * It'* *字面上 Ctrl+. →{"_Extractime}" 和您MS K3re}. 每套方法都得到解析 , 班级得到更新 以实施它MSKO6 你能找到/ 替换所有需要的用法

// Phase 1 & 2: Just write the class
public class OrderService
{
    public async Task<Order> CreateOrderAsync(CreateOrderRequest request) { ... }
    public async Task<Order?> GetOrderAsync(int orderId) { ... }
    public async Task CancelOrderAsync(int orderId) { ... }
}

// Phase 3: Need to mock it for testing? Extract interface in 2 seconds
public interface IOrderService
{
    Task<Order> CreateOrderAsync(CreateOrderRequest request);
    Task<Order?> GetOrderAsync(int orderId);
    Task CancelOrderAsync(int orderId);
}

public class OrderService : IOrderService { ... }

我的工作流程现在: *介面在 3,}不是阶段 1.

在“"”期间, 让它正常工作。 “"”和“"”使它漂亮一点。 我只是写了几堂课。“.”没有过早的抽象性;“MS K5” 没有对每种类型征收界面税。” IFoo 和 Foo@),和更快写@.#

当我打"的时候 把它锁住 " 然后需要写测试报告 时当时 我决定哪些服务实际需要嘲笑@. @ 通常需要它='}少于您 @'d think_ —}通常只是外部整合, 如 HTTP 客戶端@MS K4}数据库@,和信件队列@MSSK6{

对于内部商业逻辑服务来说 ? 一半时间我只是直接用真正的依赖性测试它们 思考 行为应该为“.”

// Services I typically DO extract interfaces for (external boundaries)
public interface IPaymentGateway { }      // Third-party API
public interface IEmailSender { }         // External service
public interface IBlobStorage { }         // Cloud storage

// Services I typically DON'T need interfaces for (internal logic)
public class OrderValidator { }           // Pure logic, test directly
public class PriceCalculator { }          // Pure logic, test directly
public class OrderService { }             // Test with real repo + in-memory DB

要点是: 停止前端的“"”接口@ just in case @". 写入混凝土类\ . 如果您需要测试或真正的多形态学界面, 稍后@,}用现代工具抽取一秒

您的代码库将更简单@ , @ 更多的导航@ I, 并赢得了您的维护重任, 让接口与执行同步, 没有好处@ MPK3}

Agile 连接

具有讽刺意味的“,”这个方法更符合 原原件 @(Q 阶段@1).Q 响应变化:#(-阶段 @1-2).Q客户协作, 当功能明显可见时, 请与客户合作 {(_ 阶段+2).}没有指纹点,} 没有速度追踪>,* 没有血腥的烧焦图表 *.

现代的“" @Agile"}”被进程爱好者所捕捉,他们加了如此多的仪式。 “'_没有时间进行探索”,这让大家回想起“MS K5{不是作为一种宽容,而是作为一个创造性工作的合法阶段 ‘.’

当不使用此方法时

我应该诚实地说 这是' 总是正确的做法

错误修正@: @% 当您@ '_ 正在修补已知的bug@ MPK1} TDD 风格更有意义 @ MS K2} 写一个测试来复制 bug@ ,} 修正它\ , done @ OMK5}

好了,好了。 明白了问题。 如果您正在实施标准算法或模式, 您已经使用过百倍的 ,您不需要一个勘探阶段@.}

有已知要求的紧凑期限@: @ 如果您真的知道您正在建造什么 're 以及何时需要发运什么 ,, 您可能会跳过“ MS K2 探索” 的阶段@.

高度受监管的环境 @: 如果每个承诺需要签名“-@off @,}沙箱更难 #.}尽管您仍然可以在推前在本地进行勘探_.}

但对于 多数 要求有点模糊的, 技术方法是 ' t显而易见\ I,\ 并且你需要空间去思考\ -—\ 这种方法非常管用

给初级开发者的说明

如果您在职业生涯的早期 '@,}你可能会感到压力 要显示""\perfect @"}代码 您必须使用这三种“.”来表示 “-_Phase Projession” MSk7}—}只是要弄清楚你在“MS K9>re in,’中是哪个阶段,并且总是完成整个工作直到“MSC11”阶段 如果导致在末端“MSG15”上擦亮了‘,’测试了“MSHK13 生产<-{\resident 代码”) 没人会责怪您乱糟蹋勘探代码

底线

让它运作起来 使它漂亮点 关上门

启动简单@ . @ 设计前瞻而非猜测@ I. @ Iterate 快速@ O.} 只给钱时添加复杂性@ MPK3 @

@"@Dexplication 远比错误的抽象更便宜 #."#

探索阶段是' 一个有罪的秘密 '—iit ''s a confident part of the process '."你的分支就是你的沙箱 直到你提出一个 P."技术反馈

这保持了创造力的活力 , 减少了压力 MS K1 并产生了规模优雅的系统

停止尝试从第1分钟开始完美到完美的状态 @ . @ 允许自己播放@ MS K1} @


相关阅读

若此回响响应@,, 您可能也会享受这些相关文章 @:#

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.