惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

乔克叔叔的床边故事

乔克叔叔的床边故事 Understanding Claude Code's Skills and Plugins - What Problems Are They Really Solving? Claude Code の Skills と Plugins を理解する:彼らは一体何の問題を解決しているのか? 一文搞懂 Claude Code 的 Skills和Plugins:它们到底在解决什么问题? My Core Agent Coding Workflow on 2025-12-8 Agentic AI Lecture Notes Agentic AI 学習記録 Agentic AI Lecture Note Agent coding experience and future Agent Coding Experience and Future エージェントコーディングの経験と未来 破解 AWS Inspector 与 ECR 的隐藏关联:解决 Terraform 管理的循环困境 Evaluating ChatGPTo1-preview, and Claude 3.5 sonnet 如何在国内拥有一个能够接受境外短信的手机号 How I Understand React as a Backend Developer 新的春天
Clean Code, Refactoring and Test-Driven Development
2024-06-15 · via 乔克叔叔的床边故事

I would like to summarize some of the basic principles and habits of coding that I learned while working at ThoughtWorks. These are some ‘metaphysical’ guidelines, and later I plan to use Kotlin to write some design patterns to practice the ‘physical’ aspects.

In a context where GPT can help us write most of the code, these principles become even more important.

私はThoughtWorksでの勤務中に学んだコーディングの基本原則と習慣をまとめたいと思います。これらはいくつかの「形而上」のガイドラインで、後でKotlinを使用してデザインパターンを書き、その「形而下」の部分を実践する予定です。

GPTがほとんどのコードを書く手助けをする状況では、これらの原則はさらに重要になります。

Reference: - Refactoring: Improving the Design of Existing Code - Clean Code: A Handbook of Agile Software Craftsmanship

## Clean Code

The problem that Clean Code want to solve is raised

Any fool can write code that a machine can understand. GPT is better at this field that you. Good programmers write code that humans can understand.

Code is primarily written for people to read, and only incidentally for machines to execute.

The time spent reading code far exceeds the time spent writing code by a factor of 10x.

Good design is obvious with no issues, while bad design has no obvious issues.

So the things that we values should be - Readability! - Maintainability!

Code should be a Problem Solver, not a *Trouble Maker** .

A Clean Code should be a code that achieve the beforehand mentioned functions and values.

My basic rules of Clean Code are

  • 1-10-50 Rule (exceptions allowed in rare cases)
    • Each method should not have more than one level of indentation.
      • Exceptions for try-catch and JavaScript callbacks.
    • Each method should not exceed 10 lines.
      • Excluding braces and the name itself.
      • Exceptions for try-catch and fetching APIs.
      • Do not force multiple lines into a single line.
    • Each class should not exceed 50 lines.
      • Import statements do not count.
  • Reasonable naming: variables, constants, methods, classes, enum values, files, etc.
  • Formatting
    • Variable
      • Variable declarations should be as close as possible to their point of use
      • Local variables should appear at the top of the function
      • Variable declarations within loops should always occur inside the loop
      • Entity variables should be declared at the top of the class.
    • Method order: if one function calls another, should be placed together, and the caller should be placed above the callee
  • “No” Comments.
  • “No” Else.
    • Favor the Return Early pattern.

Refactoring

Refactoring is the way to achieve clean code. ### Code Smell Reference :Code Smells

  1. Duplicate Code
  2. Long Method
  3. Large Class
  4. Long Parameter List
  5. Primitive Obsession
  6. Data Clumps
  7. Switch Statements
  8. Feature Envy
  9. Comments

example for 5-9 using Kotlin

1
2
3
4
5
6
7
8
9
10

val price: Double = 19.99
val currency: String = "USD"


data class Price(val amount: Double, val currency: Currency)
enum class Currency {
USD, EUR, JPY
}

1
2
3
4
5
6
7
8

fun processUser(firstName: String, lastName: String, address: String, city: String, zipCode: String) {

}


data class User(val firstName: String, val lastName: String, val address: Address)
data class Address(val streetAddress: String, val city: String, val zipCode: String)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

fun calculateTax(productType: String, price: Double): Double {
return when (productType) {
"book" -> price * 0.05
"food" -> price * 0.08
"electronics" -> price * 0.15
else -> price * 0.20
}
}


interface Product {
fun calculateTax(): Double
}

class Book(private val price: Double) : Product {
override fun calculateTax() = price * 0.05
}

class Food(private val price: Double) : Product {
override fun calculateTax() = price * 0.08
}

class Electronics(private val price: Double) : Product {
override fun calculateTax() = price * 0.15
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

class Order {
fun totalPrice() = 20.0
}

class Payment {
fun processPayment(order: Order) {
val price = order.totalPrice()

}
}


class Order {
fun totalPrice() = 20.0

fun processPayment() {
val price = totalPrice()

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

fun calculate() {

if (user.isLoggedIn && session.isValid) {


if (user.type == "admin") {
performCalculation() * 1.10
} else {
performCalculation()
}
}
}


fun calculate() {
if (isValidSession()) {
performUserSpecificCalculation()
}
}

private fun isValidSession() = user.isLoggedIn && session.isValid
private fun performUserSpecificCalculation() = when (user.type) {
"admin" -> performCalculation() * 1.10
else -> performCalculation()
}

Refactoring Techniques

Reference : Refactoring Techniques 1. Extract Variable 2. Inline Temp 3. Extract Method 4. Inline Method

When is refactoring needed?

  • Code Review: Detect bad smells during code reviews and politely suggest improvements.
  • Every Commit: Each commit you make should leave the code cleaner than it was before.
  • When Taking Over a Difficult-to-Read Project: Convince the project team to treat refactoring as a necessary task.
  • When Iteration Efficiency Is Below Expectations: Treat refactoring as a specific task, and if necessary, pause to iterate on requirements.

Rules of Refactoring

  • Use keyboard shortcuts.

  • Refactoring should not break the functionality of the code; it should always be able to compile and run.

  • Avoid starting to write new code while in the middle of refactoring.

    Test-Driven-Development

To ensure that refactoring does not break the functionality of the code, we require a reliable method to verify its integrity. This is where Test-Driven Development (TDD) proves invaluable. By integrating TDD, we establish a safety net of tests that confirm the code continues to perform as expected throughout the refactoring process.

TDD cycle

The 3 Laws of TDD

  1. You are not allowed to write any production code unless it is to make a failed pass
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures
  3. You are not allowed to write any more production code than is sufficient to pass on failing unit test .

Test Double and Test Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface CreditCardProcessor {
fun chargeCard(cardInfo: String, amount: Double): Boolean
}

interface TransactionLog {
fun logTransaction(status: String)
}

class PaymentService(
private val processor: CreditCardProcessor,
private val transactionLog: TransactionLog
) {
fun processPayment(cardInfo: String, amount: Double): Boolean {
val success = processor.chargeCard(cardInfo, amount)
if (success) {
transactionLog.logTransaction("Success")
} else {
transactionLog.logTransaction("Failure")
}
return success
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.Test

class PaymentServiceTest {

@Test
fun `Given credit card is valid, When processing payment, Then log success`() {

val mockProcessor = mockk<CreditCardProcessor>()
val mockTransactionLog = mockk<TransactionLog>(relaxed = true)

every { mockProcessor.chargeCard(any(), any()) } returns true

val paymentService = PaymentService(mockProcessor, mockTransactionLog)


val paymentResult = paymentService.processPayment("1234567890", 100.0)


assert(paymentResult)
verify { mockTransactionLog.logTransaction("Success") }
}
}


  • Stub: In the test above, mockProcessor is used as a stub. It is configured to return a specific response (true in this case) when its chargeCard method is called. Stubs are used to provide predetermined responses to method calls during tests.

  • Mock: mockTransactionLog is used as a mock. While it could also be seen as a stub because it is providing predefined behavior (due to relaxed = true), the key aspect here is that we’re verifying its behavior post-factum. We are checking whether the logTransaction method was called with the correct argument (“Success”). This is typical mocking behavior, where the emphasis is on verifying that certain methods are called correctly.

    More detailed ( Reference: Mocks Aren’t Stubs)

  • Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.

  • Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).

  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test.

  • Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.

  • Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive. ### Test Pyramid

Example of a web application
Test Pyramid