window.pipedriveLeadboosterConfig = { base: pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster on jo olemassa') } 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 }) }, } } })() Koodin optimointi kyselyobjektien avulla - The Codest
Codest
  • Tietoa meistä
  • Palvelut
    • Ohjelmistokehitys
      • Frontend-kehitys
      • Backend-kehitys
    • Staff Augmentation
      • Frontend-kehittäjät
      • Backend-kehittäjät
      • Tietoinsinöörit
      • Pilvi-insinöörit
      • QA insinöörit
      • Muut
    • Se neuvoa-antava
      • Tilintarkastus & konsultointi
  • Toimialat
    • Fintech & pankkitoiminta
    • E-commerce
    • Adtech
    • Terveysteknologia
    • Valmistus
    • Logistiikka
    • Autoteollisuus
    • IOT
  • Arvo
    • TOIMITUSJOHTAJA
    • CTO
    • Toimituspäällikkö
  • Tiimimme
  • Tapaustutkimukset
  • Tiedä miten
    • Blogi
    • Tapaamiset
    • Webinaarit
    • Resurssit
Työurat Ota yhteyttä
  • Tietoa meistä
  • Palvelut
    • Ohjelmistokehitys
      • Frontend-kehitys
      • Backend-kehitys
    • Staff Augmentation
      • Frontend-kehittäjät
      • Backend-kehittäjät
      • Tietoinsinöörit
      • Pilvi-insinöörit
      • QA insinöörit
      • Muut
    • Se neuvoa-antava
      • Tilintarkastus & konsultointi
  • Arvo
    • TOIMITUSJOHTAJA
    • CTO
    • Toimituspäällikkö
  • Tiimimme
  • Tapaustutkimukset
  • Tiedä miten
    • Blogi
    • Tapaamiset
    • Webinaarit
    • Resurssit
Työurat Ota yhteyttä
Takaisin nuoli PALAA TAAKSE
2019-03-08
Ohjelmistokehitys

Koodin optimointi kyselyobjektien avulla

Codest

Tomasz Szkaradek

Kehitysarkkitehti

On melko todennäköistä, että olet työssänne kohdannut ylikuormitettuja malleja ja valtavan määrän puheluita ohjaimissa melko monta kertaa. Rails-ympäristön tuntemukseen perustuen aion tässä artikkelissa ehdottaa yksinkertaista ratkaisua tähän ongelmaan.

Erittäin tärkeä osa Rails-sovellusta on minimoida turhien riippuvuuksien määrä, minkä vuoksi koko Rails-ympäristö on viime aikoina edistänyt palveluobjekti-lähestymistapaa ja PORO-menetelmän (Pure Old Ruby Object) käyttöä. Kuvauksen tällaisen ratkaisun käyttämisestä löydät osoitteesta täällä. Tässä artikkelissa ratkaisemme käsitteen askel askeleelta ja sovitamme sen ongelmaan.

Ongelma

Hypoteettisessa sovelluksessa on kyse monimutkaisesta tapahtumajärjestelmästä. Mallimme, joka edustaa kutakin transaktiota, sisältää joukon soveltamisaloja, joiden avulla voit saada tietoja. Se helpottaa työtä huomattavasti, koska se löytyy yhdestä paikasta. Tämä ei kuitenkaan kestä kauan. Sovelluksen kehittämisen myötä projekti on muuttumassa yhä monimutkaisemmaksi. Laajuusalueilla ei ole enää yksinkertaisia "missä"-viittauksia, meiltä puuttuu tietoja ja alamme ladata suhteita. Jonkin ajan kuluttua se muistuttaa monimutkaista peilijärjestelmää. Ja mikä pahinta, emme tiedä, miten tehdä monirivinen lambda!

Alta löydät jo laajennetun sovellusmallin. Maksujärjestelmän tapahtumat tallennetaan. Kuten näet alla olevasta esimerkistä:

class Transaction  { where(visible: true) }

  scope(:active, lambda do
    joins(<<-SQL
      LEFT OUTER JOIN source ON transactions.source_id = source.id
      AND source.accepted_at IS NOT NULL
    SQL
  end)
end

Malli on yksi asia, mutta kun hankkeemme mittakaava kasvaa, myös valvojat alkavat paisua. Katsotaanpa alla olevaa esimerkkiä:

class TransactionsController < ApplicationController
  def index
    @transactions = Transaction.for_publishers
                                   .active
                                   .visible
                                   .joins("LEFT JOIN withdrawal_items ON withdrawal_items.transaction_id = transactions.id")
                                   .joins("LEFT JOIN withdrawalals ON withdrawalals.id = withdrawal_items.withdrawal_id OR
 (withdrawalals.id = source.resource_id AND source.resource_type = 'Withdrawal')"))
                                   .order(:created_at)
                                   .page(params[:page])
                                   .per(params[:page])
    @transactions = apply_filters(@transactions)
  end
end

Tässä näemme monta riviä ketjutettuja metodeja sekä ylimääräisiä liitoksia, joita emme halua suorittaa monissa paikoissa, vain tässä nimenomaisessa. Liitettyjä tietoja käytetään myöhemmin apply_filters-metodissa, joka lisää GET-parametreihin perustuvan asianmukaisen tietojen suodatuksen. Voimme tietysti siirtää osan näistä viittauksista scopeen, mutta eikö tämä ole se ongelma, jota itse asiassa yritämme ratkaista?

Ratkaisu

Koska tiedämme jo, että meillä on ongelma, meidän on ratkaistava se. Johdannossa esitetyn viittauksen perusteella käytämme tässä PORO-lähestymistapaa. Tässä nimenomaisessa tapauksessa tätä lähestymistapaa kutsutaan kyselyobjektiksi, joka on palveluobjektien käsitteen kehitys.

Luodaan uusi hakemisto nimeltä "services", joka sijaitsee projektimme apps-hakemistossa. Luomme sinne luokan nimeltä TransactionsQuery.

luokka TransactionsQuery
end

Seuraavaksi meidän on luotava alustusohjelma, jossa luodaan objektin oletuskutsupolku.

luokka TransactionsQuery
  def initialize(scope = Transaction.all)
    @scope = scope
  end
end

Tämän ansiosta pystymme siirtämään suhteen aktiivisesta tietueesta laitoksellemme. Nyt voimme siirtää luokkaan kaikki soveltamisalamme, joita tarvitaan vain esitetyssä ohjaimessa.

luokka TransactionsQuery
  def initialize(scope = Transaction.all)
    @scope = scope
  end

  private

  def active(scope)
    scope.joins(<<-SQL
      LEFT OUTER JOIN source ON transactions.source_id = source.id
      AND source.accepted_at IS NOT NULL
    SQL
  end

  def visible(scope)
    scope.where(visible: true)
  end

  def for_publishers(scope)
    scope.select("transaktiot.*")
         .joins(:account)
         .where("accounts.owner_type = 'Publisher'")
         .joins("JOIN publishers ON owner_id = publishers.id")
  end
end

Meiltä puuttuu edelleen tärkein osa, eli tietojen kerääminen yhteen merkkijonoon ja käyttöliittymän julkistaminen. Metodi, jolla me liitämme kaiken yhteen, on nimeltään "call".

Todella tärkeää on, että käytämme @scope-muuttujaa, jossa kutsumme laajuus sijaitsee.

luokka TransactionsQuery
  ...
  def call
    visible(@scope)
        .then(&method(:active))
        .then(&method(:for_publishers))
        .order(:created_at)
  end

  private
  ...
end

Koko luokka esittäytyy seuraavasti:

luokka TransactionsQuery
  def initialize(scope = Transaction.all)
    @scope = scope
  end

  def call
    visible(@scope)
        .then(&method(:active))
        .then(&method(:for_publishers))
        .order(:created_at)
  end

  private

  def active(scope)
    scope.joins(<<-SQL
      LEFT OUTER JOIN source ON transactions.source_id = source.id
      AND source.accepted_at IS NOT NULL
    SQL
  end

  def visible(scope)
    scope.where(visible: true)
  end

  def for_publishers(scope)
    scope.select("transaktiot.*")
         .joins(:account)
         .where("accounts.owner_type = 'Publisher'")
         .joins("JOIN publishers ON owner_id = publishers.id")
  end
end

Siivouksen jälkeen malli näyttää selvästi kevyemmältä. Keskitymme nyt vain tietojen validointiin ja muiden mallien välisiin suhteisiin.

class Transaction < ActiveRecord::Base
  belongs_to :account
  has_one :withdrawal_item
end

Ohjain on jo toteuttanut ratkaisumme; olemme siirtäneet kaikki lisäkyselyt erilliseen luokkaan. Kuitenkin kutsut, joita meillä ei ollut mallissa, ovat edelleen ratkaisematta. Joidenkin muutosten jälkeen indeksitoimintomme näyttää tältä:

class TransactionsController < ApplicationController
  def index
    @transactions = TransactionsQuery.new
                                     .call
                                     .joins("LEFT JOIN withdrawal_items ON withdrawal_items.accounting_event_id = transactions.id")
                                     .joins("LEFT JOIN withdrawalals ON withdrawalals.id = withdrawal_items.withdrawal_id OR
 (withdrawalals.id = source.resource_id AND source.resource_type = 'Withdrawal')"))
                                     .order(:created_at)
                                     .page(params[:page])
                                     .per(params[:page])
    @transactions = apply_filters(@transactions)
  end
end

Ratkaisu

Hyvien käytänteiden ja yleissopimusten soveltamisessa voi olla hyvä ajatus korvata kaikki tietyn ongelman samankaltaiset esiintymät. Siksi siirretään SQL-kysely indeksitoiminnosta erilliseen kyselyobjektiin. Kutsumme tätä TransactionsFilterableQuery luokka. Tyyli, jolla valmistelemme luokan, tulee olemaan samanlainen kuin se, joka esitellään TransactionsQuery. Osana koodi muutosten myötä suurten SQL-kyselyjen intuitiivisempi tallennus salakuljetetaan käyttämällä monirivisiä merkkijonoja nimeltä heredoc. Saatavilla olevan ratkaisun löydät alta:

luokka TransactionsFilterableQuery
  def initialize(scope = Transaction.all)
    @scope = scope
  end

  def call
    withdrawal(@scope).then(&method(:withdrawal_items))
  end

  private

  def withdrawal(scope)
    scope.joins(<<-SQL
      LEFT JOIN withdrawalals ON withdrawalals.id = withdrawal_items.withdrawal_id OR
      (withdrawalals.id = source.resource_id AND source.resource_type = 'Withdrawal')
    SQL
  end

  def withdrawal_items(scope)
    scope.joins(<<-SQL
      LEFT JOIN withdrawal_items ON withdrawal_items.accounting_event_id = transactions.id
    SQL
  end
end

Jos ohjaimeen tehdään muutoksia, vähennämme rivien määrää lisäämällä kyselyobjektin. On tärkeää, että erottelemme kaiken muun paitsi sivunmuodostuksesta vastaavan osan.

class TransactionsController < ApplicationController
  def index
    @transactions = TransactionsQuery.new.call.then do |scope|
      TransactionsFilterableQuery.new(scope).call
    end.page(params[:page]).per(params[:page])

    @transactions = apply_filters(@transactions)
  end
end

Yhteenveto

Query object muuttaa paljon lähestymistapaa SQL-kyselyjen kirjoittamiseen. ActiveRecordissa kaikki liiketoiminta- ja tietokantalogiikka on erittäin helppo sijoittaa malliin, koska kaikki on yhdessä paikassa. Tämä toimii varsin hyvin pienemmissä sovelluksissa. Kun projektin monimutkaisuus kasvaa, asetamme logiikan muihin paikkoihin. Saman kyselyobjektin avulla voit ryhmitellä jäsenkyselyjä tiettyyn ongelmaan.

Tämän ansiosta meillä on helppo mahdollisuus koodin myöhempään periytymiseen, ja ankkatyypityksen ansiosta voit käyttää näitä ratkaisuja myös muissa malleissa. Tämän ratkaisun haittapuolena on suurempi koodin määrä ja vastuun pirstaloituminen. Se, haluammeko tarttua tällaiseen haasteeseen vai emme, riippuu kuitenkin meistä itsestämme ja siitä, kuinka pahasti meitä häiritsevät lihavat mallit.

Aiheeseen liittyvät artikkelit

Ohjelmistokehitys

Tulevaisuuden web-sovellusten rakentaminen: The Codest:n asiantuntijatiimin näkemyksiä

Tutustu siihen, miten The Codest loistaa skaalautuvien, interaktiivisten verkkosovellusten luomisessa huipputeknologian avulla ja tarjoaa saumattomia käyttäjäkokemuksia kaikilla alustoilla. Lue, miten asiantuntemuksemme edistää digitaalista muutosta ja liiketoimintaa...

THECODEST
Ohjelmistokehitys

Top 10 Latviassa toimivaa ohjelmistokehitysyritystä

Tutustu Latvian parhaisiin ohjelmistokehitysyrityksiin ja niiden innovatiivisiin ratkaisuihin uusimmassa artikkelissamme. Tutustu siihen, miten nämä teknologiajohtajat voivat auttaa nostamaan liiketoimintaasi.

thecodest
Yritys- ja skaalausratkaisut

Java-ohjelmistokehityksen perusteet: A Guide to Outsourcing Successfully

Tutustu tähän keskeiseen oppaaseen Java-ohjelmistokehityksen onnistuneesta ulkoistamisesta tehokkuuden parantamiseksi, asiantuntemuksen saamiseksi ja projektin onnistumiseksi The Codestin avulla.

thecodest
Ohjelmistokehitys

Perimmäinen opas ulkoistamiseen Puolassa

Ulkoistamisen lisääntyminen Puolassa johtuu taloudellisesta, koulutuksellisesta ja teknologisesta kehityksestä, joka edistää tietotekniikan kasvua ja yritysystävällistä ilmapiiriä.

TheCodest
Yritys- ja skaalausratkaisut

Täydellinen opas IT-tarkastustyökaluihin ja -tekniikoihin

Tietotekniikan tarkastuksilla varmistetaan turvalliset, tehokkaat ja vaatimustenmukaiset järjestelmät. Lue lisää niiden merkityksestä lukemalla koko artikkeli.

Codest
Jakub Jakubowicz teknologiajohtaja ja toinen perustaja

Tilaa tietopankkimme ja pysy ajan tasalla IT-alan asiantuntemuksesta.

    Tietoa meistä

    The Codest - Kansainvälinen ohjelmistokehitysyritys, jolla on teknologiakeskuksia Puolassa.

    Yhdistynyt kuningaskunta - pääkonttori

    • Toimisto 303B, 182-184 High Street North E6 2JA
      Lontoo, Englanti

    Puola - Paikalliset teknologiakeskukset

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Krakova
    • Brain Embassy, Konstruktorska
      11, 02-673 Varsova, Puola

      Codest

    • Etusivu
    • Tietoa meistä
    • Palvelut
    • Tapaustutkimukset
    • Tiedä miten
    • Työurat
    • Sanakirja

      Palvelut

    • Se neuvoa-antava
    • Ohjelmistokehitys
    • Backend-kehitys
    • Frontend-kehitys
    • Staff Augmentation
    • Backend-kehittäjät
    • Pilvi-insinöörit
    • Tietoinsinöörit
    • Muut
    • QA insinöörit

      Resurssit

    • Faktoja ja myyttejä yhteistyöstä ulkoisen ohjelmistokehityskumppanin kanssa
    • Yhdysvalloista Eurooppaan: Miksi amerikkalaiset startup-yritykset päättävät muuttaa Eurooppaan?
    • Tech Offshore -kehityskeskusten vertailu: Tech Offshore Eurooppa (Puola), ASEAN (Filippiinit), Euraasia (Turkki).
    • Mitkä ovat teknologiajohtajien ja tietohallintojohtajien tärkeimmät haasteet?
    • Codest
    • Codest
    • Codest
    • Privacy policy
    • Verkkosivuston käyttöehdot

    Tekijänoikeus © 2025 by The Codest. Kaikki oikeudet pidätetään.

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