window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versjon: 2, } ;(function () { var w = vindu if (w.LeadBooster) { console.warn('LeadBooster finnes 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 }) }, } } })() Objektorientert programmering. Det er ikke slik du tenker - The Codest
The Codest
  • Om oss
  • Tjenester
    • Programvareutvikling
      • Frontend-utvikling
      • Backend-utvikling
    • Staff Augmentation
      • Frontend-utviklere
      • Backend-utviklere
      • Dataingeniører
      • Ingeniører i skyen
      • QA-ingeniører
      • Annet
    • Det rådgivende
      • Revisjon og rådgivning
  • Industrier
    • Fintech og bankvirksomhet
    • E-commerce
    • Adtech
    • Helseteknologi
    • Produksjon
    • Logistikk
    • Bilindustrien
    • IOT
  • Verdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leveransesjef
  • Vårt team
  • Casestudier
  • Vet hvordan
    • Blogg
    • Møter
    • Webinarer
    • Ressurser
Karriere Ta kontakt med oss
  • Om oss
  • Tjenester
    • Programvareutvikling
      • Frontend-utvikling
      • Backend-utvikling
    • Staff Augmentation
      • Frontend-utviklere
      • Backend-utviklere
      • Dataingeniører
      • Ingeniører i skyen
      • QA-ingeniører
      • Annet
    • Det rådgivende
      • Revisjon og rådgivning
  • Verdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leveransesjef
  • Vårt team
  • Casestudier
  • Vet hvordan
    • Blogg
    • Møter
    • Webinarer
    • Ressurser
Karriere Ta kontakt med oss
Pil tilbake GÅ TILBAKE
2019-05-06
Programvareutvikling

Objektorientert programmering. Det er ikke slik du tenker

Pawel Wal

Med alle de gratis ressursene, bøkene og nettkursene i koding som er tilgjengelige akkurat nå, kan alle lære å kode. Men det er fortsatt et kvalitetsgap mellom koding og programvareteknikk. Må det være et slikt gap?

Jeg skrev mitt første "Hello world" for over tjue år siden - det er svaret jeg gir hvis noen spør meg hvor lenge jeg har vært koder. De siste ti årene har jeg hatt en karriere som har gitt meg mulighet til å berøre kode nesten hver dag - det er svaret jeg gir hvis jeg blir spurt om hvor lenge jeg har vært profesjonell koder.

Hvor lenge har jeg vært programvareingeniør? Jeg vil si rundt fem år. Vent litt, disse tallene ser ikke ut til å stemme! Så hva er det som har endret seg? Hvem vil jeg betrakte som programvareingeniør, og hvem er "bare" en koder?

Definisjonen av en programvareingeniør

Koding er relativt enkelt. Det er ikke lenger bare assemblermnemonikk på latterlig begrensede systemer. Og hvis du bruker noe så uttrykksfullt og kraftfullt som Ruby, er det enda enklere.

Du bare plukker opp en billett, finner ut hvor du skal sette inn koden, finner ut hvilken logikk du skal legge inn der, og pang - ferdig. Hvis du er litt mer avansert, sørger du for at koden din er pen. Logisk delt inn i metoder. Har skikkelige spesifikasjoner som ikke bare tester den lykkelige stien. Det er det en god koder gjør.

En programvareingeniør tenker ikke i metoder og klasser lenger, i hvert fall ikke først og fremst. Min erfaring er at en programvareingeniør tenker i flyter. De ser først og fremst den tordnende, rasende elven av data og interaksjon som bruser gjennom systemet. De tenker på hva de må gjøre for å avlede eller endre denne strømmen. Den pene koden, de logiske metodene og de gode spesifikasjonene kommer nesten som en ettertanke.

Det er skilpadder hele veien ned

Folk tenker generelt på en bestemt måte om de fleste interaksjoner med virkeligheten. I mangel av et bedre begrep kan vi kalle det "ovenfra-og-ned"-perspektivet. Hvis hjernen min jobber med å lage meg en kopp te, vil den først finne ut av de generelle trinnene: gå til kjøkkenet, sette på kjelen, tilberede koppen, helle vann, gå tilbake til skrivebordet.

Den vil ikke først finne ut hvilken kopp jeg skal bruke mens jeg står avsondret ved skrivebordet; den avsondringen kommer senere, når jeg står foran skapet. Den vil ikke tenke på at vi kanskje er tomme for te (eller i det minste tomme for bra ting). Det er bredt, reaktivt og feilutsatt. Alt i alt - veldig menneske i naturen.

Når programvareingeniøren vurderer endringer i den noe forvirrende dataflyten, vil han eller hun naturligvis gjøre det på en lignende måte. La oss se på dette eksempelet på en brukerhistorie:

En kunde bestiller en widget. Ved prising av bestillingen må følgende tas i betraktning:

  • Widgets grunnpris i brukerens lokalitet
  • Widgetform (prismodifikator)
  • Om det er en hastebestilling (prismodifikator)
  • Om bestillingen skal leveres på en helligdag i brukerens hjemland (prismodifikator)

Alt dette kan virke konstruert (og det er det selvsagt også), men det er ikke langt unna noen faktiske brukerhistorier jeg har hatt gleden av å knuse i det siste.

La oss nå gå gjennom tankeprosessen som en programvareingeniør kan bruke for å takle dette:

"Vi må få tak i brukeren og bestillingen deres. Så begynner vi å beregne totalsummen. Vi begynner på null. Så bruker vi widgetformmodifikatoren. Så hasteavgiften. Så ser vi om det er en helligdag, og vips, så er vi ferdige før lunsj!"

Å, rusen som en enkel brukerhistorie kan gi. Men programvareingeniøren er bare et menneske, ikke en perfekt flertrådet maskin, og oppskriften ovenfor er bare grove trekk. Ingeniøren fortsetter å tenke dypere da:

"Modifikatoren for widgetform er ... å, det er veldig avhengig av widgeten, ikke sant. Og de kan være forskjellige fra land til land, om ikke nå, så i fremtiden." de tror, tidligere brent av endrede forretningskrav, "og rushtidsavgiften kan også være det. Og helligdager er også superlokalspesifikke, og tidssoner vil være involvert! Jeg hadde en artikkel her om hvordan man håndterer tider i ulike tidssoner i Rails her ... åh, jeg lurer på om bestillingstiden er lagret med sone i databasen! Best å sjekke skjemaet."

Greit, programvareingeniør. Stopp! Du skal egentlig lage en kopp te, men du sitter foran skapet og tenker på om den blomstrete koppen i det hele tatt er relevant for teproblemet ditt.

Brygger den perfekte koppwidgeten

Men det er lett det som kan skje når du prøver å gjøre noe så unaturlig for menneskehjernen som å tenke på flere detaljnivåer samtidig.

Etter en kort gjennomgang av det store arsenalet av lenker om håndtering av tidssoner, tar ingeniøren vår seg sammen og begynner å bryte dette ned til faktisk kode. Hvis de prøvde den naive tilnærmingen, kunne det se omtrent slik ut:

 def calculate_price(bruker, 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 så fortsatte de på denne herlige prosedyreaktige måten, bare for å bli kraftig nedstemt ved første kodegjennomgang. For hvis du tenker deg om, er det helt normalt å tenke på denne måten: de store linjene først, og detaljene mye senere. Du trodde vel ikke engang at du var ute av den gode teen til å begynne med?

Ingeniøren vår er imidlertid godt trent og ikke fremmed for Service Object, så her er hva som begynner å skje i stedet:

klasse BaseOrderService
def self.call(bruker, ordre)
new(bruker, ordre).call
end

def initialize(bruker, ordre)
@user = bruker
@ordre = ordre
end

def call
puts "[WARN] Implementere ikke-standardkall for #{self.class.name}!"
bruker, rekkefølge
end
end

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

class OrderPriceCalculator < BaseOrderService
def anrop
user, order = WidgetPriceService.call(user, order)
user, order = ShapePriceModifier.call(user, order)
user, order = RushPriceModifier.call(user, order)
bruker, bestilling = HolidayDeliveryPriceModifier.call(bruker, bestilling)
bruker, bestilling
end
end
```

Så bra! Nå kan vi bruke god TDD, skrive et testtilfelle for det, og fylle ut klassene til alle bitene faller på plass. Og det blir vakkert også.

I tillegg til at det er helt umulig å resonnere seg frem til.

Fienden er staten

Joda, dette er alle godt adskilte objekter med enkeltansvar. Men her er problemet: De er fortsatt objekter. Tjenesteobjektmønsteret med sitt "lat som om dette objektet er en funksjon" er egentlig en krykke. Det er ingenting som hindrer noen i å kalle HolidayDeliveryPriceModifier.new(user, order).something_else_entirely. Ingenting hindrer folk i å legge til intern tilstand i disse objektene.

For ikke å nevne bruker og rekkefølge er også objekter, og det er like enkelt å tukle med dem som å snike seg inn en rask ordre.lagre et eller annet sted i disse ellers "rene" funksjonelle objektene, og endrer den underliggende kilden til sannhetens, dvs. databasens, tilstand. I dette konstruerte eksemplet er det ikke så farlig, men det kan bli et problem hvis systemet blir mer komplekst og utvides med flere, ofte asynkrone, deler.

Ingeniøren hadde den rette ideen. Og brukte en veldig naturlig måte å uttrykke denne ideen på. Men å vite hvordan man skulle uttrykke denne ideen - på en vakker og lettfattelig måte - ble nærmest forhindret av det underliggende OOP-paradigmet. Og hvis noen som ennå ikke har tatt spranget til å uttrykke tankene sine som avledninger av dataflyten, prøver å endre den underliggende koden på en mindre dyktig måte, vil det skje dårlige ting.

Å bli funksjonelt ren

Hvis det bare fantes et paradigme der det ikke bare var enkelt, men også nødvendig, å uttrykke ideene dine i form av dataflyt. Hvis resonnementer kunne gjøres enkle, uten mulighet for å introdusere uønskede bieffekter. Hvis data kunne være uforanderlige, akkurat som den blomstrende koppen du koker teen din i.

Ja, jeg tuller selvfølgelig. Det paradigmet finnes, og det kalles funksjonell programmering.

La oss se på hvordan eksempelet ovenfor kan se ut i en personlig favoritt, Elixir.

defmodule WidgetPrices do
def priceorder([bruker, ordre]) do
[bruker, ordre]
|> widgetprice
|> shapepricemodifier
|> rushpricemodifier
|> ferieprismodifikator
slutt

defp widgetprice([bruker, ordre]) do
%{widget: widget} = ordre
price = WidgetRepo.getbase_price(widget)
[bruker, %{ordre | pris: pris }]
end

defp shapepricemodifier([user, order]) do
%{widget: widget, price: currentprice} = ordre
modifier = WidgetRepo.getshapeprice(widget)
[bruker, %{bestilling | pris: gjeldende pris * modifikator} ]
end

defp rushpricemodifier([user, order]) do
%{rush: rush, price: currentprice} = ordre
if rush do
[user, %{ordre | pris: gjeldende pris * 1,75} ]
else
[bruker, %{ordre | pris: nåværende_pris} ]
end
end

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

Du vil kanskje legge merke til at det er et fullverdig eksempel på hvordan brukerhistorien faktisk kan realiseres. Det er fordi det er mindre av en munnfull enn det ville vært i Ruby. Vi bruker noen nøkkelfunksjoner som er unike for Elixir (men som generelt er tilgjengelige i funksjonelle språk):

Rene funksjoner. Vi endrer faktisk ikke de innkommende rekkefølge Vi lager bare nye kopier - nye iterasjoner av den opprinnelige tilstanden. Vi hopper heller ikke til siden for å endre noe. Og selv om vi ville det, rekkefølge bare er et "dumt" kart, kan vi ikke kalle ordre.lagre på noe tidspunkt her, fordi den rett og slett ikke vet hva det er.

Mønstermatching. På samme måte som ES6s destrukturering, gjør dette at vi kan plukke pris og widget av ordren og sende den videre, i stedet for å tvinge kompisene våre til å WidgetRepo og HolidayRepo å vite hvordan man skal håndtere en full rekkefølge.

Røroperatør. Sett i price_orderkan vi sende data gjennom funksjoner i en slags "pipeline" - et konsept som er velkjent for alle som noen gang har kjørt ps aux | grep postgres for å sjekke om den pokkers greia fortsatt var i gang.

Det er slik du tenker

Bivirkninger er egentlig ikke en grunnleggende del av tankeprosessen vår. Etter at du har skjenket vann i koppen din, bekymrer du deg vanligvis ikke for at en feil i vannkokeren kan føre til at den overopphetes og eksploderer - i hvert fall ikke nok til at du går og roter i innmaten for å sjekke om noen utilsiktet har glemt eksplodere_etter_påfylling vendt høyt.

Veien fra koder til programvareingeniør - fra å bekymre seg for objekter og tilstander til å bekymre seg for dataflyt - kan i noen tilfeller ta flere år. Det gjorde den i hvert fall for undertegnede, som er OOP-oppvokst. Med funksjonelle språk begynner du å tenke på dataflyt på din første natt.

Vi har laget programvareutvikling komplisert for oss selv og alle nykommere på feltet. Programmering trenger ikke å være vanskelig og hjernevridende. Det kan være enkelt og naturlig.

La oss ikke gjøre dette komplisert, og la oss bli funksjonelle. For det er slik vi tenker.

Les også:

  • Hvorfor fremskynder teknologien veksten i e-handel, markedsplasser og SaaS-selskaper?
  • Hvorfor er Ruby on Rails et godt valg for programvareutvikling? Mine personlige tanker

Relaterte artikler

Programvareutvikling

Bygg fremtidssikre webapper: Innsikt fra The Codests ekspertteam

Oppdag hvordan The Codest utmerker seg når det gjelder å skape skalerbare, interaktive webapplikasjoner med banebrytende teknologi som gir sømløse brukeropplevelser på tvers av alle plattformer. Finn ut hvordan ekspertisen vår driver digital transformasjon og...

THECODEST
Programvareutvikling

Topp 10 Latvia-baserte programvareutviklingsselskaper

I vår nyeste artikkel kan du lese mer om Latvias beste programvareutviklingsselskaper og deres innovative løsninger. Oppdag hvordan disse teknologilederne kan bidra til å løfte virksomheten din.

thecodest
Løsninger for bedrifter og oppskalering

Grunnleggende om Java-programvareutvikling: En guide til vellykket outsourcing

Utforsk denne viktige veiledningen om vellykket outsourcing av Java-programvareutvikling for å øke effektiviteten, få tilgang til ekspertise og drive frem prosjektsuksess med The Codest.

thecodest
Programvareutvikling

Den ultimate guiden til outsourcing i Polen

Den kraftige økningen i outsourcing i Polen er drevet av økonomiske, utdanningsmessige og teknologiske fremskritt, noe som fremmer IT-vekst og et forretningsvennlig klima.

TheCodest
Løsninger for bedrifter og oppskalering

Den komplette guiden til verktøy og teknikker for IT-revisjon

IT-revisjoner sørger for sikre, effektive og kompatible systemer. Les hele artikkelen for å lære mer om viktigheten av dem.

The Codest
Jakub Jakubowicz CTO og medgrunnlegger

Abonner på vår kunnskapsbase og hold deg oppdatert på ekspertisen fra IT-sektoren.

    Om oss

    The Codest - Internasjonalt programvareutviklingsselskap med teknologisentre i Polen.

    Storbritannia - Hovedkvarter

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

    Polen - Lokale teknologisentre

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

      The Codest

    • Hjem
    • Om oss
    • Tjenester
    • Casestudier
    • Vet hvordan
    • Karriere
    • Ordbok

      Tjenester

    • Det rådgivende
    • Programvareutvikling
    • Backend-utvikling
    • Frontend-utvikling
    • Staff Augmentation
    • Backend-utviklere
    • Ingeniører i skyen
    • Dataingeniører
    • Annet
    • QA-ingeniører

      Ressurser

    • Fakta og myter om samarbeid med en ekstern programvareutviklingspartner
    • Fra USA til Europa: Hvorfor velger amerikanske oppstartsbedrifter å flytte til Europa?
    • Sammenligning av Tech Offshore Development Hubs: Tech Offshore Europa (Polen), ASEAN (Filippinene), Eurasia (Tyrkia)
    • Hva er de største utfordringene for CTO-er og CIO-er?
    • The Codest
    • The Codest
    • The Codest
    • Retningslinjer for personver
    • Vilkår for bruk av nettstedet

    Opphavsrett © 2025 av The Codest. Alle rettigheter forbeholdt.

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