This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Sunday, 23 November 2025
Γιατί αντιμετωπίζετε το υποκατάστημα σας ως ένα sandboxκαι να παίξετε ως νόμιμη εργασία σας παράγει καλύτερο λογισμικό με λιγότερη ένταση.
Hot take: Οι περισσότεροι προγραμματιστές προσπαθούν να είναι τέλειοι σε κάθε στάδιο της ανάπτυξης, και σκοτώνει τόσο τη δημιουργικότητά τους όσο και την παραγωγικότητά τους.
Έχω χτίσει λογισμικό επαγγελματικά για... Λοιπόν, ας πούμε ότι θυμάμαι όταν "Agile" ήταν μια νέα ιδέα και όχι ένα εταιρικό buzzword οπλισμένο από τους διαχειριστές του έργου για να δικαιολογήσει περισσότερα standups.
Με τα χρόνια, έχω παρατηρήσει κάτι: ο καλύτερος κώδικας που έχω γράψει ποτέ προήλθε από έργα όπου ένιωσα άδεια για να παίξετεΟ χειρότερος κώδικας προήλθε από έργα όπου κάθε πληκτρολόγηση ένιωθε σαν να ήταν υπό έλεγχο, όπου προσπαθούσα να γράψω "έτοιμος παραγωγής" κώδικα από το πρώτο λεπτό.
Δεν είναι τυχαίο. Η δημιουργικότητα και η πίεση δεν αναμειγνύονται καλά.
Έτσι ανέπτυξα μια προσέγγιση που χωρίζει την ακατάστατη, δημιουργική εξερεύνηση από την στιλβωμένη, έτοιμη για παραγωγή παράδοση.Κάνε το να δουλέψει, κάνε το όμορφο, κλείδωσέ το." - αλλά πραγματικά, είναι για να δώσεις στον εαυτό σου την άδεια να πειραματιστεί χωρίς το βάρος της τελειότητας να κρέμεται πάνω σου.
Επιτρέψτε μου να ξεκαθαρίσω εκ των προτέρων: αυτό δεν έχει να κάνει με το να είσαι τσαπατσούλης ή να αποφεύγεις την πειθαρχία. εφαρμογή της σωστής πειθαρχίας την κατάλληλη στιγμή.
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
Το μάντρα: Παίξε πρώτα, επιβεβαίωσε τις υποθέσεις σου.
Αυτή είναι η φάση όπου το κλαδί σας είναι ένα κουτί άμμου. *Ωραία.*Δεν φτιάχνεις καθεδρικό ναό εδώ, σχεδιάζεις σε χαρτοπετσέτα.
Αυτό που προσπαθείς να καταλάβεις:
Η κρίσιμη διορατικότητα: Μέχρι να ανεβάσεις δημόσιες σχέσεις, το υποκατάστημα σου είναι Το δικό σου.. Είναι πειραματικό εργαστήριο σας. Κανείς δεν χρειάζεται να δείτε ψευδείς εκκινήσεις σας, σχολίασε τον κώδικα αποσφαλμάτωσης σας, σας "TODO: αυτό είναι τρομερό, διορθώστε αργότερα" σχόλια. Αλλά ελέγξτε σε OFTEN[lt] κάθε φορά που έχετε κάτι που λειτουργεί, να δεσμευτεί και να ωθήσει. Συνδέστε στον αγωγό CI σας? ένας καλός αγωγός θα σας δώσει περισσότερες πληροφορίες (εξετάσεις ενσωμάτωσης, σπάζοντας αλλαγές αλλού, κλπ.). Είναι ΜΠΟΡΕΙ να ελέγξετε σε άσχημο, μόλις ράβονται μαζί Franken-code. Αυτό είναι το ΣΗΜΕΙΟ. Ακόμα και ως ένας βετεράνος τριών decade, Εξακολουθώ να το κάνω αυτό.
Πλευρικό όφελος: Οι συχνές δεσμεύσεις είναι ένας καρδιακός παλμός. Σε απομακρυσμένες/ασύγχρονες ομάδες, ένα σταθερό μονοπάτι από "άσχημη αλλά προοδευτική" δεσμεύεται καθησυχάζει τους πάντες ότι η εργασία κινείται BAR χωρίς να χρειάζεται να εκτελέσει την παραγωγικότητα στο Slack.
Αυτή η ψυχολογική ελευθερία είναι απαραίτητη. Όταν ξέρετε ότι μπορείτε να πετάξετε τα πάντα μακριά και να ξεκινήσετε εκ νέου, παίρνετε πιο τολμηρές αποφάσεις. Προσπαθείτε αυτή την περίεργη προσέγγιση που πιθανώς δεν θα λειτουργήσει. Μερικές φορές λειτουργεί λαμπρά. Μερικές φορές πρέπει να διαβάσετε ένα άρθρο, να παρακολουθήσετε ένα βίντεο στο YouTube, να σκεφτείτε για λίγο. Θυμηθείτε: η δουλειά σας είναι να παραδώσετε καλό λογισμικό και καλές αποφάσεις, να μην πληκτρολογήσετε γρήγορα. ΔΕΝ ΕΙΝΑΙ ΤΥΠΙΣΤΟΣ.
// 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 };
}
Είναι αυτός ο κώδικας παραγωγής; Θεός όχι. Είναι χρήσιμο; Απολύτως. Σας λέει αν η προσέγγισή σας είναι ακόμη βιώσιμη πριν επενδύσετε ώρες γυαλίζοντας κάτι που δεν θα λειτουργήσει.
Σημείωση σχετικά με την ανατροφοδότηση: Μπορείτε να πάρετε σχόλια από οποιαδήποτε σημείο της Φάσης 1 Ποιος είναι αυτός; Ο στόχος είναι να οικοδομήσουμε το καλύτερο χαρακτηριστικό, όχι να ακολουθήσουμε μια άκαμπτη διαδικασία.
Χτίζοντας ένα API ότι μια άλλη ομάδα θα καταναλώσει; Πάρτε τους εμπλέκονται νωρίς. Ένα γρήγορο "Έχει αυτό το σχήμα έχει νόημα;" συνομιλία μπορεί να σώσει ημέρες της rework. ματιά αντί για το αν είναι έργαΔεν πειράζει, δίνουν ανατροφοδότηση στη Φάση 2.
Χρησιμοποίησε την κρίση σου. διευκρίνηση"Το spec λέει "χειριστείτε τα λάθη χαριτωμένα" does that mean retrike three times, or fail fast and notification?" Αυτό είναι μια συνομιλία Φάσης 1.
Αν η είσοδος των ενδιαφερομένων είναι κρίσιμη, αλλά θα παλέψουν με τον σκληρό κώδικα, θα φτιάξουν ένα ασήμαντο demo. Ένα σκληρό κωδικοποιημένο happy-path που δείχνει ότι η έννοια μπορεί να ξεκλειδώσει πολύτιμες ανατροφοδότηση χωρίς τον περισπασμό των περιπτώσεων που λείπουν.
Ο στόχος είναι το καλύτερο χαρακτηριστικό, όχι η καθαρότητα της διαδικασίας.
Το μάντρα: Τώρα που ξέρεις τι φτιάχνεις, κάντο. Ωραία..
Επιβεβαίωσες ότι η προσέγγιση λειτουργεί, καταλαβαίνεις το σχήμα του προβλήματος, και πιθανότατα ανακάλυψες μια ντουζίνα υποθέσεις που δεν ανέφερε το αρχικό εισιτήριο.
Τώρα καθαρίστε το.
// 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
};
}
Εδώ είσαι εσύ.
Κρίσιμα, αυτή είναι η καλύτερη στιγμή για μη τεχνικές ανατροφοδότηση των ενδιαφερομένων. Το χαρακτηριστικό είναι πλέον ορατό και χρησιμοποιήσιμο, αλλά δεν έχετε επενδύσει ακόμα ώρες γράφοντας δοκιμές γι 'αυτό. Αν λένε "πραγματικά, θέλαμε να κάνει Χ αντ 'αυτού," μπορείτε να περιστρέψετε χωρίς την καρδιά της διαγραφής μια ολοκληρωμένη δοκιμαστική σουίτα.
Το μάντρα: Σκληρώστε το, δοκιμάστε το, κάντε το ανθεκτικό.
Προσθέστε ελέγχους ασφαλείας. Εφαρμόστε τον κατάλληλο χειρισμό λάθους για τις περιπτώσεις άκρη παραγωγής. Προσθέστε την παρακολούθηση και guardrails.
Γιατί να περιμένουμε μέχρι τώρα; Επιτέλους ξέρεις τι δοκιμάζεις..
Οι δοκιμές που γράφτηκαν στη Φάση 1 θα ήταν λάθος. Δεν καταλάβατε ακόμα το πρόβλημα. Οι δοκιμές που γράφτηκαν στη Φάση 2 θα είχαν ανατραπεί. Εξακολουθούσατε να εξευγενίζετε το API. Οι δοκιμές που γράφτηκαν στη Φάση 3 είναι σωστό, διότι η εφαρμογή είναι σταθερή.
[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);
}
Η φάση αυτή περιλαμβάνει επίσης:
Διαφορετικοί άνθρωποι πρέπει να εμπλέκονται σε διαφορετικά στάδια, να κάνουν λάθος και θα πνιγείς στην τριβή.
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: Τεχνικές φωνές μόνο devs, αρχιτέκτονες. Μπορούν να δουν πέρα από το χάος στο σχήμα της λύσης. Μη-τεχνικοί ενδιαφερόμενοι θα πανικοβληθούν σε πρόχειρο κώδικα και θα ρωτήσουν για χρώματα κουμπί όταν είστε ακόμα υπολογίζει το μοντέλο δεδομένων.
Φάση 2: Μη τεχνικές φωνές ευπρόσδεκτες. Το χαρακτηριστικό είναι χρησιμοποιήσιμο, κουμπιά κάνουν πράγματα. Πάρτε ιδιοκτήτες προϊόντων και σχεδιαστές που εμπλέκονται τώρα οι αλλαγές είναι ακόμα φθηνές, δεν έχετε γράψει δοκιμές ακόμα.
Φάση 3: "Κι αν αυτό έχει 10x κίνηση;" "Κι αν κάποιος περάσει κακόβουλη είσοδο;" Αυτές οι ανησυχίες έχουν σημασία μόνο όταν το χαρακτηριστικό λειτουργεί πραγματικά.
Εδώ είναι το πράγμα που άλλαξε την αναπτυξιακή μου ζωή: Μέχρι να ανεβάσεις δημόσιες σχέσεις, το υποκατάστημα σου είναι εντελώς ιδιωτικό..
Αυτό μπορεί να ακούγεται προφανές, αλλά βλέπω τους προγραμματιστές να συμπεριφέρονται σε κάθε δέσμευση σαν να πηγαίνει στο μόνιμο φάκελό τους, φοβούνται να πειραματιστούν, φοβούνται να γράψουν άσχημο κώδικα, φοβούνται να σπάσουν τα πράγματα.
Θέλω να σκεφτείς το κλαδί σου σαν μια παιδική χαρά, ένα εργαστήριο όπου αναμένονται εκρήξεις και κανείς δεν πληγώνεται.
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
Στην πράξη, αυτό σημαίνει:
FIXME και TODO σχόλια παντούΤότε, πριν ανεβάσεις δημόσιες σχέσεις
Οι κριτικοί των δημοσίων σχέσεων βλέπουν καθαρό, επαγγελματικό κώδικα με μια σαφή αφήγηση. Δεν βλέπουν τα έξι ψευδή ξεκινά, το 3π.μ. "γιατί αυτό το αιματηρό έργο" διαπράττει, ή η "μη αναιρέσει" ιστορία.
Το γυαλιστερό κουτί παραμένει ιδιωτικό.
Κάθε γραμμή αισθάνεται μόνιμη. Κάθε απόφαση αισθάνεται ως συνέπεια. Αυτή η προσέγγιση αφαιρεί την πίεση που περιέχει το χάος: Το παιχνίδι είναι νόμιμη δουλειά. στη Φάση 1, η ανάδραση έρχεται όταν η περιστροφή είναι φθηνή στη Φάση 2, και οι δοκιμές γράφονται μια φορά σωστά στη Φάση 3 επειδή τελικά ξέρετε τι δοκιμάζετε.
"Το παιχνίδι είναι νόμιμη δουλειά."
Το TDD λειτουργεί έξοχα όταν ο τομέας είναι καλά κατανοητός ή είστε καρφώνοντας κάτω από ένα γνωστό σφάλμα. Αλλά όταν το πρόβλημα εξακολουθεί να είναι θολή, γράφοντας δοκιμές για πρώτη φορά σημαίνει δοκιμή το λάθος πράγμα τρεις φορές στη σειρά. Αυτή η προσέγγιση παρακάμπτει ότι: εξερευνήστε πρώτα, δοκιμή όταν είναι σταθερή.
Τι κάνει αυτή η τρισδιάστατη νοοτροπία στις αρχές του σχεδιασμού σας; Με λίγα λόγια: σκοτώνει το δόγμα. Εδώ είναι πώς αλλάζει τη σκέψη μου για SOLID, DRY, και διεπαφές σε C#.
Ανέφερα την εφαρμογή των αρχών SOLID "πραγματικά" στη Φάση 2. Ας είμαι συγκεκριμένος σχετικά με το τι εννοώ.
Το SOLID είναι ένα καλό σύνολο αρχών. Τους διδάσκω, τις χρησιμοποιώ, αλλά έχω δει ομάδες να εξαφανίζονται αφαιρώντας τρύπες κουνελιού στο όνομα της Ενιαίας Ευθύνης ή Open/Closed, δημιουργώντας συστήματα τόσο ευέλικτα που είναι ακατανόητα.
Εδώ είναι η ουριστική μου:
Εφαρμόστε το SOLID όταν:
Μην εφαρμόσετε το SOLID όταν:
Τρεις παρόμοιες γραμμές κώδικα είναι καλύτερες από μια πρόωρη αφαίρεση. Μπορείτε πάντα να εξάγετε αργότερα όταν βλέπετε το μοτίβο καθαρά. Δεν μπορείτε εύκολα να αναιρέσετε μια αφαίρεση που είναι ψημένη στην αρχιτεκτονική σας.
// 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
}
}
Αν χρειάζεστε την ευελιξία αργότερα, αναπροσανατολισμός είναι φθηνή. Υπερμηχανική εκ των προτέρων είναι ακριβό, επειδή είστε διατηρώντας στρώματα αφαίρεσης που δεν κερδίζουν το κράτημά τους.
Και ενώ σκοτώνουμε ιερές αγελάδες, ας μιλήσουμε για 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 είναι ένας εφιάλτης για να διατηρηθεί επειδή προσπαθεί να είναι όλα τα πράγματα για όλους τους καλούντες. Κάθε αλλαγή απαιτεί την κατανόηση όλων των περιπτώσεων χρήσης.
Ο κανόνας μου: Ανέχεστε την επικάλυψη μέχρι να δείτε το ίδια πράγμα τρεις φορές και είστε σίγουροι ότι αντιπροσωπεύει το ίδια Μια ιδέα που θα εξελιχθεί μαζί. Μέχρι τότε, ένα κομμάτι της αντιγραφής-επικόλλησης είναι μια χαρά. Δεν είναι μια ηθική αποτυχία, είναι η κατάλληλη προσοχή.
Μπορείτε πάντα να αποτυπώσετε αργότερα όταν το μοτίβο είναι σαφές. Δεν μπορείτε εύκολα να αναιρέσετε μια κακή αφαίρεση που είναι υφασμένο μέσω της βάσης κώδικα σας.
Εδώ είναι μια άλλη ιερή αγελάδα που χρειάζεται σφαγή: το μοτίβο "κάθε τάξη χρειάζεται μια διεπαφή".
Πίσω στις πρώτες ημέρες της ένεσης εξάρτησης .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
Αυτό ήταν ο προγραμματισμός της λατρείας φορτίων. θεωρητική Δοκιμασία και θεωρητική μελλοντική ευελιξία που σπάνια υλοποιήθηκε.
Αυτό είναι το θέμα: δεν το χρειάζεσαι πια αυτό.
Σύγχρονα πλαίσια κοροϊδίας όπως N Substituto και ΜοκCity name (optional, probably does not need a translation) Το πιο σημαντικό είναι ότι το δοχείο DI του ASP.NET Core λειτουργεί απόλυτα καλά με τύπους σκυροδέματος:
// 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Ακριβώς η υπηρεσία που χρειάζεστε, εγχέεται άμεσα.
"Αλλά τι γίνεται με τις δοκιμές;" Σε ακούω να κλαις.
Για δοκιμές μονάδας, έχετε επιλογές:
virtual και να χρησιμοποιήσετε ένα πλαίσιο κοροϊδίαςΤο τρίτο σημείο είναι κρίσιμο: τα εργαλεία αναπαραγωγιμότητας είναι εξαιρετικά καλά στην εξαγωγή διεπαφών.
Στο Rider ή στο Visual Studio, είναι κυριολεκτικά Ctrl+. → "Extract Interface" και είστε έτοιμοι. Κάθε μέθοδος εξάγεται, η τάξη ενημερώνεται για την εφαρμογή του, και μπορείτε να βρείτε/αντικαταστήσετε όλες τις χρήσεις αν χρειαστεί.
// 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.
Κατά τη διάρκεια του "να το κάνετε να λειτουργήσει" και "να το κάνει όμορφο," απλά γράφω τάξεις. Δεν πρόωρη αφαίρεση. Δεν υπάρχει φόρος διεπαφής σε κάθε τύπο. Ο κώδικας είναι απλούστερος, ευκολότερος να πλοηγηθεί (δεν άλμα μεταξύ IFoo και Foo), και γρηγορότερα για να γράψετε.
Όταν χτυπήσω το "κλείδωσέ το" και πρέπει να γράψω εξετάσεις, τότε Συνήθως είναι λιγότερο από ό, τι θα σκεφτόσουν συχνά μόνο εξωτερικές ενότητες όπως πελάτες HTTP, βάσεις δεδομένων, και ουρές μηνυμάτων.
Οι εξετάσεις είναι πιο πολύτιμες ούτως ή άλλως επειδή δοκιμάζουν την πραγματική συμπεριφορά, όχι ένα χλευασμό του τι εγώ Σκέψου. η συμπεριφορά θα πρέπει να είναι.
// 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
Το θέμα είναι: Σταματήστε να γράφετε διεπαφές μπροστά "σε περίπτωση" . Γράψτε τάξεις σκυροδέματος . Αν χρειάζεστε μια διεπαφή για δοκιμή ή γνήσιο πολυμορφισμό αργότερα , η εξαγωγή ενός παίρνει κυριολεκτικά δευτερόλεπτα με σύγχρονα εργαλεία .
Η βάση κώδικα σας θα είναι απλούστερη, πιο πλοήγηση, και δεν θα έχετε το βάρος συντήρησης της διατήρησης των διεπαφών σε συγχρονισμό με τις εφαρμογές για κανένα όφελος.
Η ειρωνεία είναι ότι η προσέγγιση αυτή ευθυγραμμίζεται περισσότερο με την πρωτότυπο Γήινο μανιφέστο από τις περισσότερες διαδικασίες "Agile" που έχω συναντήσει. Εργαζόμενο λογισμικό γρήγορα (Φάση 1).Απαντώντας στην αλλαγή (Φάσεις 1-2). Η συνεργασία των πελατών όταν το χαρακτηριστικό είναι αποδεδειγμένο (Φάση 2).
Το σύγχρονο "Agile" έχει συλληφθεί από τους λάτρεις της διαδικασίας που έχουν προσθέσει τόσες πολλές τελετές δεν υπάρχει χρόνος για εξερεύνηση. Αυτή η προσέγγιση φέρνει πίσω παιχνίδι όχι ως επιείκεια, αλλά ως μια νόμιμη φάση δημιουργικής εργασίας.
Πρέπει να είμαι ειλικρινής: αυτή δεν είναι πάντα η σωστή προσέγγιση.
Επιδιορθώσεις σφαλμάτων: Όταν φτιάχνεις ένα γνωστό έντομο, το στυλ TDD βγάζει νόημα. Γράψε ένα τεστ που αναπαράγει το έντομο, το φτιάχνεις, το τελειώνεις.
Κατανοητό πρόβλημα: Αν εφαρμόζετε έναν τυποποιημένο αλγόριθμο ή ένα μοτίβο που έχετε χρησιμοποιήσει εκατό φορές, δεν χρειάζεστε μια φάση εξερεύνησης.
Σφιχτές προθεσμίες με γνωστές απαιτήσεις: Αν πραγματικά ξέρεις ακριβώς τι φτιάχνεις και όταν χρειάζεται να στείλεις, μπορεί να αποφύγεις την εξερεύνηση της Φάσης 1.
Υψηλά ρυθμιζόμενα περιβάλλοντα: Αν κάθε δέσμευση χρειάζεται να υπογράψει, sandboxing είναι πιο δύσκολο. Αν και μπορείτε ακόμα να κάνετε την εξερεύνηση τοπικά πριν σπρώξετε.
Αλλά για περισσότερο feature development όπου οι απαιτήσεις είναι λίγο ασαφείς, η τεχνική προσέγγιση δεν είναι προφανής, και χρειάζεστε χώρο για να σκεφτείτε αυτή η προσέγγιση λειτουργεί έξοχα.
Αν είστε νωρίς στην καριέρα σας, μπορεί να αισθάνεστε πίεση για να δείξετε "τέλειο" κώδικα όλη την ώρα. Δεν χρειάζεται να. Χρησιμοποιήστε αυτή την τριφασική προσέγγιση απλά να είναι σαφής σχετικά με το ποια φάση είστε σε, και πάντα να τελειώσει τη δουλειά σε όλη τη φάση 3. Κανείς δεν θα σας κατηγορήσει για βρώμικο κώδικα εξερεύνησης αν οδηγεί σε γυαλισμένο, δοκιμασμένο, έτοιμο κώδικα παραγωγής στο τέλος.
Κάντε το να δουλέψει, κάντε το όμορφο, κλειδώστε το.
Αρχίστε απλά. Σχεδιάστε με προνοητικότητα αλλά όχι κερδοσκοπία. Εξετάστε γρήγορα. Προσθέστε την πολυπλοκότητα μόνο όταν αποπληρώνεται.
"Η σύλληψη είναι πολύ φθηνότερη από τη λάθος αφαίρεση."
Η φάση εξερεύνησης δεν είναι ένα ένοχο μυστικό είναι ένα καθορισμένο μέρος της διαδικασίας. Παρακλάδι σας είναι σας sandbox μέχρι να αυξήσετε μια PR. Τεχνική ανατροφοδότηση έρχεται νωρίς, μη τεχνική ανατροφοδότηση έρχεται μέσα, ops και ανατροφοδότηση ασφάλειας έρχεται αργά.
Αυτό κρατάει ζωντανή τη δημιουργικότητα, μειώνει το άγχος και παράγει συστήματα που κλιμακώνονται κομψά γιατί καταλάβατε το πρόβλημα πριν δεσμευτείτε για τη λύση.
Σταμάτα να προσπαθείς να είσαι τέλειος από την πρώτη στιγμή.
Αν αυτό αντηχεί, θα μπορούσατε επίσης να απολαύσετε αυτές τις σχετικές θέσεις:
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.