Verbeter de onderhoudbaarheid, leesbaarheid en prestaties van uw Python-code met effectieve refactoring-technieken. Leer praktische strategieën en best practices.
Python Refactoring Technieken: Een Uitgebreide Gids voor Verbetering van Codekwaliteit
In het steeds evoluerende landschap van softwareontwikkeling is het handhaven van schone, efficiënte en begrijpelijke code van cruciaal belang. Python, bekend om zijn leesbaarheid, kan nog steeds ten prooi vallen aan 'code smells' en technische schuld als het niet zorgvuldig wordt beheerd. Refactoring is het proces van het herstructureren van bestaande computercode - het wijzigen van de factorering - zonder het externe gedrag ervan te veranderen. In wezen is het het opschonen van uw code zonder deze te verbreken. Deze gids verkent verschillende Python refactoring technieken, met praktische voorbeelden en best practices om uw codekwaliteit te verhogen.
Waarom Python Code Refactoren?
Refactoring biedt tal van voordelen, waaronder:
- Verbeterde Leesbaarheid: Maakt code gemakkelijker te begrijpen en te onderhouden.
- Verminderde Complexiteit: Vereenvoudigt complexe logica, waardoor de kans op fouten wordt verminderd.
- Verbeterde Onderhoudbaarheid: Vergemakkelijkt het gemakkelijker wijzigen en uitbreiden van code.
- Verhoogde Prestaties: Kan code optimaliseren voor een betere uitvoeringssnelheid.
- Lagere Technische Schuld: Voorkomt de accumulatie van code die moeilijk te onderhouden of uit te breiden is.
- Beter Ontwerp: Leidt tot een robuustere en flexibelere code-architectuur.
Het negeren van refactoring kan leiden tot code die moeilijk te begrijpen, aan te passen en te testen is. Dit kan de ontwikkelingstijd aanzienlijk verlengen en het risico op het introduceren van bugs vergroten.
Wanneer te Refactoren?
Weten wanneer je moet refactoren is cruciaal. Hier zijn enkele veelvoorkomende scenario's:
- Voordat u Nieuwe Functies Toevoegt: Refactoren van bestaande code kan het gemakkelijker maken om nieuwe functionaliteit te integreren.
- Na het Oplossen van een Bug: Refactoren van de omringende code kan voorkomen dat vergelijkbare bugs terugkeren.
- Tijdens Code Reviews: Identificeer gebieden die kunnen worden verbeterd en refactor deze.
- Wanneer u "Code Smells" tegenkomt: Code smells zijn indicaties van potentiële problemen in uw code.
- Regelmatige Geplande Refactoring: Neem refactoring als een regelmatige activiteit op in uw ontwikkelingsproces.
Code Smells Identificeren
Code smells zijn oppervlakkige indicaties die meestal overeenkomen met een dieper probleem in het systeem. Ze duiden niet altijd op een probleem, maar ze rechtvaardigen vaak verder onderzoek.
Veelvoorkomende Python Code Smells:
- Gedupliceerde Code: Identieke of zeer vergelijkbare code die op meerdere plaatsen voorkomt.
- Lange Methode/Functie: Methoden of functies die buitensporig lang en complex zijn.
- Grote Klasse: Klassen die te veel verantwoordelijkheden hebben.
- Lange Parameterlijst: Methoden of functies met te veel parameters.
- Dataklonten: Groepen gegevens die vaak samen verschijnen.
- Primitieve Obsessie: Het gebruik van primitieve gegevenstypen in plaats van het maken van objecten.
- Switch-Statements: Lange ketens van if/elif/else-statements of switch-statements.
- Shotgun Surgery: Een enkele wijziging vereist het maken van veel kleine wijzigingen in verschillende klassen.
- Divergente Verandering: Een klasse wordt vaak op verschillende manieren gewijzigd om verschillende redenen.
- Feature Envy: Een methode heeft toegang tot de gegevens van een ander object meer dan zijn eigen gegevens.
- Berichtenketens: Een client vraagt ​​een object om een ​​ander object te vragen om weer een ander object te vragen...
Python Refactoring Technieken: Een Praktische Gids
Deze sectie beschrijft verschillende veelvoorkomende Python refactoring technieken met praktische voorbeelden.
1. Methode/Functie Extraceren
Deze techniek houdt in dat een blok code binnen een methode of functie wordt genomen en naar een nieuwe, afzonderlijke methode of functie wordt verplaatst. Dit vermindert de complexiteit van de oorspronkelijke methode en maakt de geëxtraheerde code herbruikbaar.
Voorbeeld:
def print_factuur(klant, details):
print("***********************")
print(f"Klant: {klant}")
print("***********************")
totaal_bedrag = 0
for bestelling in details["bestellingen"]:
totaal_bedrag += bestelling["bedrag"]
print(f"Bedrag is: {totaal_bedrag}")
if totaal_bedrag > 1000:
print("U heeft korting verdiend!")
Gerefactored:
def print_kop(klant):
print("***********************")
print(f"Klant: {klant}")
print("***********************")
def bereken_totaal(details):
totaal_bedrag = 0
for bestelling in details["bestellingen"]:
totaal_bedrag += bestelling["bedrag"]
return totaal_bedrag
def print_factuur(klant, details):
print_kop(klant)
totaal_bedrag = bereken_totaal(details)
print(f"Bedrag is: {totaal_bedrag}")
if totaal_bedrag > 1000:
print("U heeft korting verdiend!")
2. Klasse Extraceren
Wanneer een klasse te veel verantwoordelijkheden heeft, extraheer er dan een paar in een nieuwe klasse. Dit bevordert het Single Responsibility Principle.
Voorbeeld:
class Persoon:
def __init__(self, naam, telefoonnummer, netnummer, kantoornummer):
self.naam = naam
self.telefoonnummer = telefoonnummer
self.netnummer = netnummer
self.kantoornummer = kantoornummer
def krijg_naam(self):
return self.naam
def krijg_telefoonnummer(self):
return f"({self.netnummer}) {self.kantoornummer}"
Gerefactored:
class Telefoonnummer:
def __init__(self, netnummer, nummer):
self.netnummer = netnummer
self.nummer = nummer
def krijg_telefoonnummer(self):
return f"({self.netnummer}) {self.nummer}"
class Persoon:
def __init__(self, naam, telefoonnummer):
self.naam = naam
self.telefoonnummer = telefoonnummer
def krijg_naam(self):
return self.naam
3. Methode/Functie Inline
Dit is het tegenovergestelde van Methode Extraceren. Als de body van een methode zo duidelijk is als zijn naam, kunt u de methode inline maken door aanroepen naar de methode te vervangen door de inhoud van de methode.
Voorbeeld:
def krijg_waardering(bestuurder):
return meer_dan_vijf_te_late_leveringen(bestuurder) ? 2 : 1
def meer_dan_vijf_te_late_leveringen(bestuurder):
return bestuurder.aantal_te_late_leveringen > 5
Gerefactored:
def krijg_waardering(bestuurder):
return bestuurder.aantal_te_late_leveringen > 5 ? 2 : 1
4. Vervang Temp met Query
In plaats van een tijdelijke variabele te gebruiken om het resultaat van een expressie vast te houden, extraheer de expressie in een methode. Dit voorkomt code-duplicatie en bevordert een betere leesbaarheid.
Voorbeeld:
def krijg_prijs(bestelling):
basis_prijs = bestelling.hoeveelheid * bestelling.artikel_prijs
korting_factor = 0.98 if basis_prijs > 1000 else 0.95
return basis_prijs * korting_factor
Gerefactored:
def krijg_prijs(bestelling):
return basis_prijs(bestelling) * korting_factor(bestelling)
def basis_prijs(bestelling):
return bestelling.hoeveelheid * bestelling.artikel_prijs
def korting_factor(bestelling):
return 0.98 if basis_prijs(bestelling) > 1000 else 0.95
5. Introduceer Parameter Object
Als u een lange lijst met parameters heeft die vaak samen verschijnen, overweeg dan om een ​​parameterobject te maken om deze in te kapselen. Dit vermindert de lengte van de parameterlijst en verbetert de code-organisatie.
Voorbeeld:
def bereken_totaal(breedte, hoogte, diepte, gewicht, verzendmethode):
# Berekeningslogica
pass
Gerefactored:
class Verzenddetails:
def __init__(self, breedte, hoogte, diepte, gewicht, verzendmethode):
self.breedte = breedte
self.hoogte = hoogte
self.diepte = diepte
self.gewicht = gewicht
self.verzendmethode = verzendmethode
def bereken_totaal(verzenddetails):
# Berekeningslogica met behulp van verzenddetails attributen
pass
6. Vervang Voorwaardelijk met Polymorfisme
Wanneer u een complexe voorwaardelijke uitspraak heeft die gedrag kiest op basis van het type van een object, overweeg dan om polymorfisme te gebruiken om het gedrag aan subklassen te delegeren. Dit bevordert een betere code-organisatie en maakt het gemakkelijker om nieuwe typen toe te voegen.
Voorbeeld:
def bereken_bonus(medewerker):
if medewerker.medewerker_type == "VERKOOP":
return medewerker.verkoop * 0.1
elif medewerker.medewerker_type == "ENGINEUR":
return medewerker.projecten_afgerond * 100
elif medewerker.medewerker_type == "MANAGER":
return 1000
else:
return 0
Gerefactored:
class Medewerker:
def bereken_bonus(self):
return 0
class VerkoopMedewerker(Medewerker):
def __init__(self, verkoop):
self.verkoop = verkoop
def bereken_bonus(self):
return self.verkoop * 0.1
class EngineerMedewerker(Medewerker):
def __init__(self, projecten_afgerond):
self.projecten_afgerond = projecten_afgerond
def bereken_bonus(self):
return self.projecten_afgerond * 100
class ManagerMedewerker(Medewerker):
def bereken_bonus(self):
return 1000
7. Voorwaardelijk Ontbinden
Net als bij Methode Extraceren, houdt dit in dat een complexe voorwaardelijke uitspraak wordt opgesplitst in kleinere, beter beheersbare methoden. Dit verbetert de leesbaarheid en maakt het gemakkelijker om de logica van het voorwaardelijke begrip te begrijpen.
Voorbeeld:
if (platform.upper().index("MAC") > -1) and (browser.upper().index("IE") > -1) and was_initialized() and resize > MAX_RESIZE:
# Doe iets
pass
Gerefactored:
def is_mac_os():
return platform.upper().index("MAC") > -1
def is_ie_browser():
return browser.upper().index("IE") > -1
if is_mac_os() and is_ie_browser() and was_initialized() and resize > MAX_RESIZE:
# Doe iets
pass
8. Magisch Getal Vervangen met Symbolische Constante
Vervang letterlijke numerieke waarden door benoemde constanten. Dit verbetert de leesbaarheid en maakt het gemakkelijker om de waarden later te wijzigen. Dit geldt ook voor andere letterlijke waarden zoals strings. Overweeg valutacodes (bijv. 'USD', 'EUR', 'JPY') of statuscodes (bijv. 'ACTIEF', 'INACTIEF', 'IN AFWACHTING') vanuit een globaal perspectief.
Voorbeeld:
def bereken_oppervlakte(straal):
return 3.14159 * straal * straal
Gerefactored:
PI = 3.14159
def bereken_oppervlakte(straal):
return PI * straal * straal
9. Middelman Verwijderen
Als een klasse eenvoudigweg aanroepen aan een andere klasse delegeert, overweeg dan om de tussenpersoon te verwijderen en de client direct toegang te geven tot de doelklasse.
Voorbeeld:
class Persoon:
def __init__(self, afdeling):
self.afdeling = afdeling
def krijg_manager(self):
return self.afdeling.krijg_manager()
class Afdeling:
def __init__(self, manager):
self.manager = manager
def krijg_manager(self):
return self.manager
Gerefactored:
class Persoon:
def __init__(self, manager):
self.manager = manager
def krijg_manager(self):
return self.manager
10. Assertie Introduceren
Gebruik assertions om aannames over de status van het programma te documenteren. Dit kan helpen om fouten vroegtijdig op te sporen en code robuuster te maken.
Voorbeeld:
def bereken_korting(prijs, kortings_percentage):
if kortings_percentage < 0 or kortings_percentage > 100:
raise ValueError("Kortingspercentage moet tussen 0 en 100 liggen")
return prijs * (1 - kortings_percentage / 100)
Gerefactored:
def bereken_korting(prijs, kortings_percentage):
assert 0 <= kortings_percentage <= 100, "Kortingspercentage moet tussen 0 en 100 liggen"
return prijs * (1 - kortings_percentage / 100)
Hulpmiddelen voor Python Refactoring
Verschillende tools kunnen helpen bij Python refactoring:
- Rope: Een refactoring-bibliotheek voor Python.
- PyCharm: Een populaire Python IDE met ingebouwde refactoring-ondersteuning.
- VS Code met Python Extension: Een veelzijdige editor met refactoring-mogelijkheden via extensies.
- Sourcery: Een geautomatiseerde refactoring-tool.
- Bowler: Een refactoring-tool van Facebook voor grootschalige code-wijzigingen.
Best Practices voor Python Refactoring
- Schrijf Unit Tests: Zorg ervoor dat uw code goed is getest voordat u gaat refactoren.
- Refactor in Kleine Stappen: Breng kleine, incrementele wijzigingen aan om het risico op het introduceren van fouten te minimaliseren.
- Test Na Elke Refactoring Stap: Controleer of uw wijzigingen niets hebben stukgemaakt.
- Gebruik Versiebeheer: Commit uw wijzigingen regelmatig om indien nodig gemakkelijk terug te keren.
- Communiceer met Uw Team: Laat uw team weten over uw refactoringplannen.
- Focus op Leesbaarheid: Geef prioriteit aan het gemakkelijker maken van uw code.
- Refactor niet alleen omwille van het refactoren: Refactor wanneer het een specifiek probleem oplost.
- Automatiseer Refactoring Waar Mogelijk: Gebruik tools om repetitieve refactoring-taken te automatiseren.
Globale Overwegingen voor Refactoring
Houd bij het werken aan internationale projecten of voor een wereldwijd publiek rekening met deze factoren tijdens het refactoren:
- Lokalisatie (L10n) en Internationalisatie (I18n): Zorg ervoor dat uw code verschillende talen, valuta's en datumnotaties correct ondersteunt. Refactor om landinstelling-specifieke logica te isoleren.
- Tekencodering: Gebruik UTF-8-codering om een ​​breed scala aan tekens te ondersteunen. Refactor code die uitgaat van een specifieke codering.
- Culturele Gevoeligheid: Houd rekening met culturele normen en vermijd het gebruik van taal of beelden die aanstootgevend kunnen zijn. Bekijk stringliteralen en elementen van de gebruikersinterface tijdens het refactoren.
- Tijdzones: Verwerk tijdzoneconversies correct. Refactor code die aannames maakt over de tijdzone van de gebruiker. Gebruik bibliotheken zoals `pytz`.
- Valuta Behandeling: Gebruik geschikte gegevenstypen en bibliotheken voor het verwerken van monetaire waarden. Refactor code die handmatige valutaconversies uitvoert. Bibliotheken zoals `babel` zijn handig.
Voorbeeld: Lokalisatie van Datumnotaties
import datetime
def formatteer_datum(datum):
return datum.strftime("%m/%d/%Y") # Amerikaanse datumnotatie
Gerefactored:
import datetime
import locale
def formatteer_datum(datum, locale_code):
locale.setlocale(locale.LC_TIME, locale_code)
return datum.strftime("%x") # Landinstelling-specifieke datumnotatie
# Voorbeeldgebruik:
# formatteer_datum(datetime.date(2024, 1, 1), 'en_US.UTF-8') # Output: '01/01/2024'
# formatteer_datum(datetime.date(2024, 1, 1), 'de_DE.UTF-8') # Output: '01.01.2024'
Conclusie
Refactoring is een essentiële praktijk voor het behouden van Python-code van hoge kwaliteit. Door code smells te identificeren en aan te pakken, geschikte refactoring-technieken toe te passen en best practices te volgen, kunt u de leesbaarheid, onderhoudbaarheid en prestaties van uw code aanzienlijk verbeteren. Vergeet niet om prioriteit te geven aan testen en communicatie tijdens het refactoringproces. Het omarmen van refactoring als een continu proces leidt tot een robuustere en duurzamere softwareontwikkelingsworkflow, met name bij het ontwikkelen voor een wereldwijd en divers publiek.