window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(funktion () { var w = vindue if (w.LeadBooster) { console.warn('LeadBooster findes allerede') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Objektorienteret programmering. Det er ikke sådan, du tænker - The Codest
Codest
  • Om os
  • Serviceydelser
    • Udvikling af software
      • Frontend-udvikling
      • Backend-udvikling
    • Staff Augmentation
      • Frontend-udviklere
      • Backend-udviklere
      • Dataingeniører
      • Cloud-ingeniører
      • QA-ingeniører
      • Andet
    • Det rådgivende
      • Revision og rådgivning
  • Industrier
    • Fintech og bankvirksomhed
    • E-commerce
    • Adtech
    • Sundhedsteknologi
    • Produktion
    • Logistik
    • Biler
    • IOT
  • Værdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leder af levering
  • Vores team
  • Casestudier
  • Ved hvordan
    • Blog
    • Møder
    • Webinarer
    • Ressourcer
Karriere Tag kontakt til os
  • Om os
  • Serviceydelser
    • Udvikling af software
      • Frontend-udvikling
      • Backend-udvikling
    • Staff Augmentation
      • Frontend-udviklere
      • Backend-udviklere
      • Dataingeniører
      • Cloud-ingeniører
      • QA-ingeniører
      • Andet
    • Det rådgivende
      • Revision og rådgivning
  • Værdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leder af levering
  • Vores team
  • Casestudier
  • Ved hvordan
    • Blog
    • Møder
    • Webinarer
    • Ressourcer
Karriere Tag kontakt til os
Pil tilbage GÅ TILBAGE
2019-05-06
Udvikling af software

Objektorienteret programmering. Det er ikke sådan, man tænker

Pawel Wal

Med de mange gratis ressourcer, bøger, onlinekurser og bootcamps i kodning, der er tilgængelige lige nu, kan alle lære at kode. Men der er stadig en kvalitetskløft mellem kodning og softwareudvikling. Skal der være en sådan?

Jeg skrev mit første "Hello world" for over tyve år siden - det er det svar, jeg giver, hvis nogen spørger mig, hvor længe jeg har været koder. I de sidste ti år har jeg haft en karriere, der har givet mig mulighed for at røre ved Kode næsten hver dag - det er det svar, jeg giver, hvis jeg bliver spurgt, hvor længe jeg har været professionel koder.

Hvor længe har jeg været softwareingeniør? Jeg vil sige omkring fem år. Vent lidt, disse tal ser ikke ud til at passe sammen! Så hvad har ændret sig? Hvem ville jeg betragte som en softwareingeniør, og hvem er "bare" en koder?

Definitionen af en softwareingeniør

Det er relativt nemt at kode. Det er ikke længere kun assemblagemønstre på latterligt begrænsede systemer. Og hvis du bruger noget så udtryksfuldt og kraftfuldt som Ruby, er det endnu nemmere.

Du henter bare en billet, finder ud af, hvor du skal indsætte din kode, du finder ud af, hvilken logik du skal bruge der, og bum - færdig. Hvis du er lidt mere avanceret, sørger du for, at din kode er pæn. Logisk opdelt i metoder. Har ordentlige specifikationer, der ikke kun tester den lykkelige vej. Det er, hvad en god koder gør.

En softwareingeniør tænker ikke længere i metoder og klasser, i hvert fald ikke primært. Min erfaring er, at en softwareingeniør tænker i flows. De ser først og fremmest den tordnende, rasende flod af data og interaktion, der bruser gennem systemet. De tænker på, hvad de skal gøre for at aflede eller ændre denne strøm. Den smukke kode, de logiske metoder og de gode specifikationer kommer næsten som en eftertanke.

Det er skildpadder hele vejen ned

Folk tænker generelt på en bestemt måde om de fleste interaktioner med virkeligheden. Lad os i mangel af bedre kalde det "top-down"-perspektivet. Hvis min hjerne arbejder på at lave en kop te til mig selv, vil den først finde ud af de generelle trin: gå ud i køkkenet, sætte kedlen over, lave en kop te, hælde vand op, gå tilbage til skrivebordet.

Den finder ikke først ud af, hvilken kop jeg skal bruge, når jeg står og zoner ud ved mit skrivebord; den zoneudgang kommer senere, når jeg står foran skabet. Den overvejer ikke, at vi måske er løbet tør for te (eller i det mindste for godt ting). Det er bredt, reaktivt og fejlbehæftet. Alt i alt - meget menneske i naturen.

Når softwareingeniøren overvejer ændringer i det noget uoverskuelige dataflow, vil han naturligvis gøre det på en lignende måde. Lad os se på dette eksempel på en brugerhistorie:

En kunde bestiller en widget. Ved prissætning af ordren skal følgende tages i betragtning:

  • Widgets basispris i brugerens lokalitet
  • Widget-form (prismodifikator)
  • Om det er en hasteordre (prismodifikator)
  • Om levering af ordren finder sted på en helligdag i brugerens land (prismodifikator)

Alt dette kan virke konstrueret (og det er det selvfølgelig også), men det er ikke langt fra nogle faktiske brugerhistorier, som jeg har haft fornøjelsen af at knuse for nylig.

Lad os nu gennemgå den tankeproces, som en softwareingeniør kan bruge til at tackle dette:

"Vi skal have fat i brugeren og deres ordre. Så begynder vi at beregne det samlede beløb. Vi starter på nul. Så anvender vi widgetformmodifikatoren. Derefter hastegebyret. Så ser vi, om det er en helligdag, og så er vi færdige inden frokost!"

Ah, det sus, som en simpel brugerhistorie kan give. Men softwareingeniøren er kun et menneske, ikke en perfekt maskine med flere tråde, og ovenstående opskrift er en grovkornet beskrivelse. Så fortsætter ingeniøren med at tænke dybere:

"Widgetformmodifikatoren er ... åh, det er super afhængigt af widgetten, er det ikke. Og de kan være forskellige fra land til land, selv om det ikke er nu, så i fremtiden." tror de, tidligere brændt af på grund af ændrede forretningskrav, "og det kan hastegebyret også være. Og helligdage er også super lokalspecifikke, og tidszoner vil være involveret! Jeg havde en artikel her om håndtering af tider i forskellige tidszoner i Rails her ... åh, gad vide, om bestillingstiden er gemt med zone i databasen! Jeg må hellere tjekke skemaet."

Okay, softwareingeniør. Stop op. Det er meningen, at du skal lave en kop te, men du sidder foran skabet og tænker på, om den blomstrede kop overhovedet er relevant for dit teproblem.

Brygning af den perfekte kop widget

Men det er, hvad der nemt kan ske, når man forsøger at gøre noget så unaturligt for den menneskelige hjerne som at tænke i flere detaljer. på samme tid.

Efter en kort gennemgang af deres store arsenal af links om tidszonehåndtering tager vores ingeniør sig sammen og begynder at nedbryde det til egentlig kode. Hvis de prøvede den naive tilgang, ville det måske se nogenlunde sådan ud:

 def beregn_pris(bruger, ordre)
   ordre.pris = 0
   order.price = WidgetPrices.find_by(widget_type: order.widget.type).price
   order.price = WidgetShapes.find_by(widget_shape: order.widget.shape).modifier
   ...
 end

Og de blev ved og ved, på denne dejlige proceduremæssige måde, kun for at blive lukket ned ved den første kodegennemgang. For hvis man tænker over det, er det helt normalt at tænke på denne måde: de store linjer først og detaljerne meget senere. Du troede ikke engang, at du var ude af den gode te i starten, gjorde du?

Vores ingeniør er imidlertid veluddannet og ikke fremmed for serviceobjektet, så her er, hvad der begynder at ske i stedet:

klasse BaseOrderService
def self.call(bruger, ordre)
new(bruger, ordre).call
slut

def initialize(bruger, ordre)
@user = bruger
@order = ordre
end

def opkald
puts "[WARN] Implementer ikke-standardkald for #{self.class.name}!"
bruger, ordre
end
end

class WidgetPriceService < BaseOrderService; end
class ShapePriceModifier < BaseOrderService; end
class RushPriceModifier < BaseOrderService; end
class HolidayDeliveryPriceModifier < BaseOrderService; end

class OrderPriceCalculator < BaseOrderService
def opkald
bruger, ordre = WidgetPriceService.call(bruger, ordre)
bruger, ordre = ShapePriceModifier.call(bruger, ordre)
bruger, ordre = RushPriceModifier.call(bruger, ordre)
bruger, ordre = HolidayDeliveryPriceModifier.call(bruger, ordre)
bruger, ordre
slut
end
```

Det er godt! Nu kan vi bruge god TDD, skrive en testcase til den og udbygge klasserne, indtil alle brikkerne falder på plads. Og det bliver også smukt.

Og det er helt umuligt at ræsonnere sig frem til.

Fjenden er staten

Ja, det er alle velafgrænsede objekter med et enkelt ansvarsområde. Men her er problemet: De er stadig objekter. Serviceobjektmønsteret med dets "lad med magt som om dette objekt er en funktion" er i virkeligheden en krykke. Der er ikke noget, der forhindrer nogen i at kalde HolidayDeliveryPriceModifier.new(user, order).something_else_entirely. Der er ikke noget, der forhindrer folk i at tilføje intern tilstand til disse objekter.

For ikke at nævne bruger og Bestil er også objekter, og det er lige så nemt at pille ved dem som at snige sig ind i en hurtig ordre.gem et eller andet sted i disse ellers "rene" funktionelle objekter og ændrer den underliggende kilde til sandhedens, dvs. en databases, tilstand. I dette konstruerede eksempel er det ikke så slemt, men det kan komme bag på dig, hvis systemet bliver mere komplekst og udvides med flere, ofte asynkrone, dele.

Ingeniøren havde den rigtige idé. Og brugte en meget naturlig måde at udtrykke denne idé på. Men at vide, hvordan man udtrykker denne idé - på en smuk og letforståelig måde - blev næsten forhindret af det underliggende OOP-paradigme. Og hvis nogen, der endnu ikke har taget springet til at udtrykke deres tanker som afledninger af datastrømmen, forsøger at ændre den underliggende kode på en mindre dygtig måde, vil der ske dårlige ting.

At blive funktionelt ren

Hvis bare der fandtes et paradigme, hvor det ikke kun var nemt, men også nødvendigt at udtrykke sine ideer i form af datastrømme. Hvis ræsonnementer kunne gøres enkle uden mulighed for at indføre uønskede bivirkninger. Hvis data kunne være uforanderlige, ligesom den blomstrede kop, du laver din te i.

Ja, jeg laver selvfølgelig sjov. Det paradigme findes, og det kaldes funktionel programmering.

Lad os se på, hvordan ovenstående eksempel kan se ud i en personlig favorit, Elixir.

defmodule WidgetPrices do
def priceorder([user, order]) do
[bruger, ordre]
|> widgetprice
|> shapepricemodifier
|> rushpricemodifier
|> ferieprismodifikator
slut

defp widgetprice([user, order]) do
%{widget: widget} = ordre
price = WidgetRepo.getbase_price(widget)
[bruger, %{ordre | pris: pris }]
slut

defp shapepricemodifier([user, order]) do
%{widget: widget, price: currentprice} = ordre
modifier = WidgetRepo.getshapeprice(widget)
[bruger, %{ordre | pris: aktuel pris * modifikator} ]
slut

defp rushpricemodifier([user, order]) do
%{rush: rush, price: currentprice} = ordre
hvis rush do
[user, %{order | price: currentprice * 1.75} ]
else
[user, %{order | price: current_price} ]
end
slut

defp holidaypricemodifier([user, order]) do
%{date: date, price: currentprice} = ordre
modifier = HolidayRepo.getholidaymodifier(user, date)
[bruger, %{ordre | pris: aktuel pris * modifikator}]
slut
end
```

Du vil måske bemærke, at det er et fuldt udbygget eksempel på, hvordan brugerhistorien faktisk kan opnås. Det er fordi, det er en mindre mundfuld, end det ville være i Ruby. Vi bruger nogle få nøglefunktioner, som er unikke for Elixir (men som generelt er tilgængelige i funktionelle sprog):

Rene funktioner. Vi ændrer faktisk ikke de indkommende Bestil overhovedet, vi skaber bare nye kopier - nye iterationer af den oprindelige tilstand. Vi hopper heller ikke ud til siden for at ændre noget. Og selv hvis vi ville, Bestil bare er et "dumt" kort, kan vi ikke kalde ordre.gem på noget tidspunkt her, fordi den simpelthen ikke ved, hvad det er.

Mønstermatchning. I lighed med ES6's destrukturering giver dette os mulighed for at plukke Pris og widget af ordren og give den videre, i stedet for at tvinge vores venner WidgetRepo og FerieRepo for at vide, hvordan man håndterer en fuld Bestil.

Røroperatør. Set i pris_ordrelader den os sende data gennem funktioner i en slags "pipeline" - et koncept, der er velkendt for alle, der nogensinde har kørt ps aux | grep postgres for at tjekke, om den stadig kørte.

Det er sådan, du tænker

Bivirkninger er egentlig ikke en grundlæggende del af vores tankegang. Når du har hældt vand i din kop, bekymrer du dig normalt ikke om, at en fejl i kedlen kan få den til at overophede og eksplodere - i hvert fald ikke nok til at gå og rode i dens indre for at tjekke, om nogen ikke utilsigtet har efterladt eksplodere_efter_hældning vendt højt.

Vejen fra koder til softwareingeniør - at gå fra at bekymre sig om objekter og tilstande til at bekymre sig om datastrømme - kan i nogle tilfælde tage flere år. Det gjorde den i hvert fald for undertegnede, der er opvokset med OOP. Med funktionelle sprog kommer du til at tænke på flows på din første aften.

Vi har lavet softwareudvikling kompliceret for os selv og hver eneste nybegynder på området. Programmering behøver ikke at være svært og hjernevridende. Det kan være nemt og naturligt.

Lad os ikke gøre det kompliceret, og lad os blive funktionelle. For det er sådan, vi tænker.

Læs også her:

  • Hvorfor fremskynder teknologien væksten i e-handel, markedspladser og SaaS-virksomheder?
  • Hvorfor er Ruby on Rails et godt valg til softwareudvikling? Mine personlige tanker

Relaterede artikler

Udvikling af software

Byg fremtidssikrede webapps: Indsigt fra The Codest's ekspertteam

Oplev, hvordan The Codest udmærker sig ved at skabe skalerbare, interaktive webapplikationer med banebrydende teknologier, der leverer sømløse brugeroplevelser på tværs af alle platforme. Lær, hvordan vores ekspertise driver digital transformation og...

DENKODEST
Udvikling af software

Top 10 Letlands-baserede softwareudviklingsvirksomheder

Læs om Letlands bedste softwareudviklingsvirksomheder og deres innovative løsninger i vores seneste artikel. Find ud af, hvordan disse teknologiledere kan hjælpe med at løfte din virksomhed.

thecodest
Løsninger til virksomheder og scaleups

Grundlæggende om Java-softwareudvikling: En guide til succesfuld outsourcing

Udforsk denne vigtige guide til vellykket outsourcing af Java-softwareudvikling for at forbedre effektiviteten, få adgang til ekspertise og skabe projektsucces med The Codest.

thecodest
Udvikling af software

Den ultimative guide til outsourcing i Polen

Den voldsomme stigning i outsourcing i Polen er drevet af økonomiske, uddannelsesmæssige og teknologiske fremskridt, der fremmer it-vækst og et erhvervsvenligt klima.

TheCodest
Løsninger til virksomheder og scaleups

Den komplette guide til IT-revisionsværktøjer og -teknikker

IT-revisioner sikrer sikre, effektive og kompatible systemer. Lær mere om deres betydning ved at læse hele artiklen.

Codest
Jakub Jakubowicz CTO og medstifter

Tilmeld dig vores vidensbase, og hold dig opdateret om ekspertisen fra it-sektoren.

    Om os

    The Codest - International softwareudviklingsvirksomhed med tech-hubs i Polen.

    Storbritannien - Hovedkvarter

    • Kontor 303B, 182-184 High Street North E6 2JA
      London, England

    Polen - Lokale teknologiske knudepunkter

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Hjerneambassaden, Konstruktorska
      11, 02-673 Warszawa, Polen

      Codest

    • Hjem
    • Om os
    • Serviceydelser
    • Casestudier
    • Ved hvordan
    • Karriere
    • Ordbog

      Serviceydelser

    • Det rådgivende
    • Udvikling af software
    • Backend-udvikling
    • Frontend-udvikling
    • Staff Augmentation
    • Backend-udviklere
    • Cloud-ingeniører
    • Dataingeniører
    • Andet
    • QA-ingeniører

      Ressourcer

    • Fakta og myter om at samarbejde med en ekstern softwareudviklingspartner
    • Fra USA til Europa: Hvorfor beslutter amerikanske startups sig for at flytte til Europa?
    • Sammenligning af Tech Offshore-udviklingsknudepunkter: Tech Offshore Europa (Polen), ASEAN (Filippinerne), Eurasien (Tyrkiet)
    • Hvad er de største udfordringer for CTO'er og CIO'er?
    • Codest
    • Codest
    • Codest
    • Privacy policy
    • Vilkår for brug af hjemmesiden

    Copyright © 2025 af The Codest. Alle rettigheder forbeholdes.

    da_DKDanish
    en_USEnglish de_DEGerman sv_SESwedish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek da_DKDanish