window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster υπάρχει ήδη') } 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 }) }, } } })() Βελτιστοποίηση κώδικα με αντικείμενα ερωτήσεων - The Codest
The Codest
  • Σχετικά με εμάς
  • Υπηρεσίες
    • Ανάπτυξη λογισμικού
      • Ανάπτυξη Frontend
      • Backend Ανάπτυξη
    • Staff Augmentation
      • Frontend Developers
      • Backend Developers
      • Μηχανικοί δεδομένων
      • Μηχανικοί cloud
      • Μηχανικοί QA
      • Άλλα
    • Συμβουλευτική
      • Έλεγχος & Συμβουλευτική
  • Βιομηχανίες
    • Fintech & Τραπεζική
    • E-commerce
    • Adtech
    • Healthtech
    • Κατασκευή
    • Εφοδιαστική
    • Αυτοκίνητο
    • IOT
  • Αξία για
    • CEO
    • CTO
    • Διευθυντής παράδοσης
  • Η ομάδα μας
  • Case Studies
  • Μάθετε πώς
    • Blog
    • Συναντήσεις
    • Διαδικτυακά σεμινάρια
    • Πόροι
Καριέρα Ελάτε σε επαφή
  • Σχετικά με εμάς
  • Υπηρεσίες
    • Ανάπτυξη λογισμικού
      • Ανάπτυξη Frontend
      • Backend Ανάπτυξη
    • Staff Augmentation
      • Frontend Developers
      • Backend Developers
      • Μηχανικοί δεδομένων
      • Μηχανικοί cloud
      • Μηχανικοί QA
      • Άλλα
    • Συμβουλευτική
      • Έλεγχος & Συμβουλευτική
  • Αξία για
    • CEO
    • CTO
    • Διευθυντής παράδοσης
  • Η ομάδα μας
  • Case Studies
  • Μάθετε πώς
    • Blog
    • Συναντήσεις
    • Διαδικτυακά σεμινάρια
    • Πόροι
Καριέρα Ελάτε σε επαφή
Πίσω βέλος GO BACK
2019-03-08
Ανάπτυξη λογισμικού

Βελτιστοποίηση κώδικα με αντικείμενα ερωτήσεων

The Codest

Tomasz Szkaradek

Αρχιτέκτονας ανάπτυξης

Είναι πολύ πιθανό ότι στη δουλειά σας να έχετε αντιμετωπίσει πολλές φορές υπερφορτωμένα μοντέλα και τεράστιο αριθμό κλήσεων στους ελεγκτές. Με βάση τις γνώσεις στο περιβάλλον του Rails, σε αυτό το άρθρο, θα σας προτείνω μια απλή λύση σε αυτό το πρόβλημα.

Μια πολύ σημαντική πτυχή της εφαρμογής rails είναι η ελαχιστοποίηση του αριθμού των περιττών εξαρτήσεων, γι' αυτό και ολόκληρο το περιβάλλον Rails προωθεί πρόσφατα την προσέγγιση των αντικειμένων υπηρεσιών και τη χρήση της μεθόδου PORO (Pure Old Ruby Object). Μια περιγραφή του τρόπου χρήσης μιας τέτοιας λύσης θα βρείτε εδώ. Σε αυτό το άρθρο, θα λύσουμε την έννοια βήμα προς βήμα και θα την προσαρμόσουμε στο πρόβλημα.

Πρόβλημα

Σε μια υποθετική εφαρμογή, έχουμε να κάνουμε με ένα πολύπλοκο σύστημα συναλλαγών. Το μοντέλο μας, που αναπαριστά κάθε συναλλαγή, έχει ένα σύνολο από πεδία εφαρμογής, που σας βοηθούν να λάβετε δεδομένα. Είναι μια μεγάλη διευκόλυνση της εργασίας, καθώς μπορούν να βρεθούν σε ένα μέρος. Ωστόσο, αυτό δεν διαρκεί για πολύ. Με την ανάπτυξη της εφαρμογής, η έργο γίνεται όλο και πιο περίπλοκη. Τα πεδία εφαρμογής δεν έχουν πλέον απλές αναφορές "όπου", μας λείπουν δεδομένα και αρχίζουμε να φορτώνουμε σχέσεις. Μετά από λίγο, θυμίζει ένα περίπλοκο σύστημα καθρεφτών. Και, το χειρότερο, δεν ξέρουμε πώς να κάνουμε ένα lambda πολλαπλών γραμμών!

Παρακάτω, θα βρείτε ένα ήδη διευρυμένο μοντέλο εφαρμογής. Οι συναλλαγές του συστήματος πληρωμών αποθηκεύονται σε. Όπως μπορείτε να δείτε στο παρακάτω παράδειγμα:

class Συναλλαγή  { 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)
τέλος

Το μοντέλο είναι ένα πράγμα, αλλά καθώς η κλίμακα του έργου μας αυξάνεται, οι ελεγκτές αρχίζουν επίσης να διογκώνονται. Ας δούμε το παρακάτω παράδειγμα:

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 withdrawals ON withdrawals.id = withdrawal_items.withdrawal_id OR
 (withdrawals.id = source.resource_id AND source.resource_type = 'Withdrawal')")
                                   .order(:created_at)
                                   .page(params[:page])
                                   .per(params[:page])
    @transactions = apply_filters(@transactions)
  end
end

Εδώ μπορούμε να δούμε πολλές γραμμές αλυσιδωτών μεθόδων μαζί με πρόσθετες ενώσεις που δεν θέλουμε να εκτελέσουμε σε πολλά σημεία, μόνο σε αυτό το συγκεκριμένο. Τα συνημμένα δεδομένα χρησιμοποιούνται αργότερα από τη μέθοδο apply_filters, η οποία προσθέτει το κατάλληλο φιλτράρισμα των δεδομένων, με βάση τις παραμέτρους GET. Φυσικά, μπορούμε να μεταφέρουμε κάποιες από αυτές τις αναφορές στην εμβέλεια, αλλά αυτό δεν είναι το πρόβλημα που ουσιαστικά προσπαθούμε να επιλύσουμε;

Λύση

Εφόσον γνωρίζουμε ήδη ένα πρόβλημα που έχουμε, πρέπει να το λύσουμε. Με βάση την αναφορά στην εισαγωγή, θα χρησιμοποιήσουμε εδώ την προσέγγιση PORO. Σε αυτήν ακριβώς την περίπτωση, η προσέγγιση αυτή ονομάζεται αντικείμενο ερωτήματος, το οποίο αποτελεί εξέλιξη της έννοιας των αντικειμένων υπηρεσιών.

Ας δημιουργήσουμε έναν νέο κατάλογο με το όνομα "services", ο οποίος βρίσκεται στον κατάλογο apps του έργου μας. Εκεί θα δημιουργήσουμε μια κλάση με το όνομα TransactionsQuery.

class TransactionsQuery
end

Ως επόμενο βήμα, πρέπει να δημιουργήσουμε έναν αρχικοποιητή όπου θα δημιουργηθεί μια προεπιλεγμένη διαδρομή κλήσης για το αντικείμενό μας

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

Χάρη σε αυτό, θα είμαστε σε θέση να μεταφέρουμε τη σχέση από το ενεργό αρχείο στην εγκατάστασή μας. Τώρα μπορούμε να μεταφέρουμε όλα τα πεδία εφαρμογής μας στην κλάση, τα οποία χρειάζονται μόνο στον παρουσιαζόμενο ελεγκτή.

class 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("transactions.*")
         .joins(:account)
         .where("accounts.owner_type = 'Publisher'")
         .joins("JOIN publishers ON owner_id = publishers.id")
  end
end

Μας λείπει ακόμα το πιο σημαντικό μέρος, δηλαδή η συλλογή δεδομένων σε μια συμβολοσειρά και η δημοσιοποίηση της διεπαφής. Η μέθοδος όπου θα κολλήσουμε τα πάντα μαζί θα ονομάζεται "κλήση".

Αυτό που είναι πραγματικά σημαντικό είναι ότι θα χρησιμοποιήσουμε τη μεταβλητή @scope εκεί, όπου βρίσκεται η εμβέλεια της κλήσης μας.

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

  private
  ...
end

Ολόκληρη η τάξη παρουσιάζεται ως εξής:

class 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("transactions.*")
         .joins(:account)
         .where("accounts.owner_type = 'Publisher'")
         .joins("JOIN publishers ON owner_id = publishers.id")
  end
end

Μετά τον καθαρισμό μας, το μοντέλο φαίνεται σίγουρα πιο ελαφρύ. Εκεί εστιάζουμε μόνο στην επικύρωση των δεδομένων και στις σχέσεις μεταξύ άλλων μοντέλων.

class Συναλλαγή < ActiveRecord::Base
  belongs_to :account
  has_one :withdrawal_item
end

Ο ελεγκτής έχει ήδη υλοποιήσει τη λύση μας- έχουμε μεταφέρει όλα τα πρόσθετα ερωτήματα σε μια ξεχωριστή κλάση. Ωστόσο, οι κλήσεις, που δεν είχαμε στο μοντέλο, παραμένουν ένα άλυτο ζήτημα. Μετά από κάποιες αλλαγές, η ενέργεια ευρετηρίου μας μοιάζει ως εξής:

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 withdrawals ON withdrawals.id = withdrawal_items.withdrawal_id OR
 (withdrawals.id = source.resource_id AND source.resource_type = 'Withdrawal')")
                                     .order(:created_at)
                                     .page(params[:page])
                                     .per(params[:page])
    @transactions = apply_filters(@transactions)
  end
end

Λύση

Στην περίπτωση της εφαρμογής ορθών πρακτικών και συμβάσεων, μια καλή ιδέα μπορεί να είναι η αντικατάσταση όλων των παρόμοιων περιστατικών ενός συγκεκριμένου προβλήματος. Ως εκ τούτου, θα μεταφέρουμε το ερώτημα SQL από την ενέργεια ευρετηρίου στο ξεχωριστό αντικείμενο ερωτήματος. Θα το ονομάσουμε αυτό TransactionsFilterableQuery κατηγορία. Το ύφος, με το οποίο προετοιμάζουμε το μάθημα, θα είναι παρόμοιο με αυτό που παρουσιάζεται στο TransactionsQuery. Στο πλαίσιο του κωδικός αλλαγές, μια πιο διαισθητική καταγραφή των μεγάλων ερωτημάτων SQL θα γίνεται λαθραία, χρησιμοποιώντας συμβολοσειρές χαρακτήρων πολλών γραμμών που ονομάζονται heredoc. Τη διαθέσιμη λύση θα τη βρείτε παρακάτω:

class 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 withdrawals ON withdrawals.id = withdrawal_items.withdrawal_id OR
      (withdrawals.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

Σε περίπτωση αλλαγών στον ελεγκτή, μειώνουμε τη μάζα των γραμμών προσθέτοντας το αντικείμενο ερώτησης. Είναι σημαντικό να διαχωρίσουμε τα πάντα εκτός από το τμήμα που είναι υπεύθυνο για την σελιδοποίηση.

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

Περίληψη

Το αντικείμενο ερώτησης αλλάζει πολύ την προσέγγιση στη συγγραφή ερωτημάτων SQL. Στην ActiveRecord, είναι πολύ εύκολο να τοποθετήσετε όλη την επιχειρηματική λογική και τη λογική της βάσης δεδομένων στο μοντέλο, αφού όλα βρίσκονται σε ένα μέρος. Αυτό θα λειτουργήσει αρκετά καλά για μικρότερες εφαρμογές. Καθώς αυξάνεται η πολυπλοκότητα του έργου, τοποθετούμε τη λογική σε άλλα μέρη. Το ίδιο αντικείμενο ερωτήματος σας επιτρέπει να ομαδοποιείτε τα ερωτήματα των μελών σε ένα συγκεκριμένο πρόβλημα.

Χάρη σε αυτό, έχουμε μια εύκολη δυνατότητα μεταγενέστερης κληρονομικότητας του κώδικα και λόγω της τυποποίησης πάπιας, μπορείτε επίσης να χρησιμοποιήσετε αυτές τις λύσεις σε άλλα μοντέλα. Το μειονέκτημα αυτής της λύσης είναι η μεγαλύτερη ποσότητα κώδικα και ο κατακερματισμός της ευθύνης. Ωστόσο, το αν θέλουμε να αναλάβουμε μια τέτοια πρόκληση ή όχι, εξαρτάται από εμάς και από το πόσο πολύ μας ενοχλούν τα παχιά μοντέλα.

Σχετικά άρθρα

Ανάπτυξη λογισμικού

Κατασκευάστε μελλοντικά ασφαλείς εφαρμογές Web: γνώσεις από την ομάδα εμπειρογνωμόνων του The Codest

Ανακαλύψτε πώς η The Codest υπερέχει στη δημιουργία κλιμακούμενων, διαδραστικών εφαρμογών ιστού με τεχνολογίες αιχμής, παρέχοντας απρόσκοπτη εμπειρία χρήστη σε όλες τις πλατφόρμες. Μάθετε πώς η τεχνογνωσία μας οδηγεί στον ψηφιακό μετασχηματισμό και την επιχειρηματική...

THECODEST
Ανάπτυξη λογισμικού

Top 10 εταιρείες ανάπτυξης λογισμικού με έδρα τη Λετονία

Μάθετε για τις κορυφαίες εταιρείες ανάπτυξης λογισμικού της Λετονίας και τις καινοτόμες λύσεις τους στο τελευταίο μας άρθρο. Ανακαλύψτε πώς αυτοί οι τεχνολογικοί ηγέτες μπορούν να βοηθήσουν στην ανύψωση της επιχείρησής σας.

thecodest
Λύσεις Enterprise & Scaleups

Βασικά στοιχεία ανάπτυξης λογισμικού Java: Α Guide to Outsourcing Successfully (Οδηγός για την επιτυχή εξωτερική ανάθεση)

Εξερευνήστε αυτόν τον βασικό οδηγό για την επιτυχή ανάπτυξη λογισμικού outsourcing Java για να αυξήσετε την αποδοτικότητα, να αποκτήσετε πρόσβαση στην τεχνογνωσία και να οδηγήσετε την επιτυχία των έργων με The Codest.

thecodest
Ανάπτυξη λογισμικού

Ο απόλυτος οδηγός για το Outsourcing στην Πολωνία

Η έξαρση της outsourcing στην Πολωνία οφείλεται στις οικονομικές, εκπαιδευτικές και τεχνολογικές εξελίξεις, που ευνοούν την ανάπτυξη της πληροφορικής και το φιλικό προς τις επιχειρήσεις κλίμα.

TheCodest
Λύσεις Enterprise & Scaleups

Ο πλήρης οδηγός εργαλείων και τεχνικών ελέγχου πληροφορικής

Οι έλεγχοι ΤΠ διασφαλίζουν ασφαλή, αποτελεσματικά και συμβατά συστήματα. Μάθετε περισσότερα για τη σημασία τους διαβάζοντας ολόκληρο το άρθρο.

The Codest
Jakub Jakubowicz CTO & Συνιδρυτής

Εγγραφείτε στη βάση γνώσεών μας και μείνετε ενήμεροι για την τεχνογνωσία από τον τομέα της πληροφορικής.

    Σχετικά με εμάς

    The Codest - Διεθνής εταιρεία ανάπτυξης λογισμικού με κέντρα τεχνολογίας στην Πολωνία.

    Ηνωμένο Βασίλειο - Έδρα

    • Γραφείο 303B, 182-184 High Street North E6 2JA
      Λονδίνο, Αγγλία

    Πολωνία - Τοπικοί κόμβοι τεχνολογίας

    • Πάρκο γραφείων Fabryczna, Aleja
      Pokoju 18, 31-564 Κρακοβία
    • Πρεσβεία του εγκεφάλου, Konstruktorska
      11, 02-673 Βαρσοβία, Πολωνία

      The Codest

    • Αρχική σελίδα
    • Σχετικά με εμάς
    • Υπηρεσίες
    • Case Studies
    • Μάθετε πώς
    • Καριέρα
    • Λεξικό

      Υπηρεσίες

    • Συμβουλευτική
    • Ανάπτυξη λογισμικού
    • Backend Ανάπτυξη
    • Ανάπτυξη Frontend
    • Staff Augmentation
    • Backend Developers
    • Μηχανικοί cloud
    • Μηχανικοί δεδομένων
    • Άλλα
    • Μηχανικοί QA

      Πόροι

    • Γεγονότα και μύθοι σχετικά με τη συνεργασία με εξωτερικό συνεργάτη ανάπτυξης λογισμικού
    • Από τις ΗΠΑ στην Ευρώπη: Γιατί οι αμερικανικές νεοσύστατες επιχειρήσεις αποφασίζουν να μετεγκατασταθούν στην Ευρώπη
    • Σύγκριση υπεράκτιων κόμβων ανάπτυξης τεχνολογίας: Ευρώπη (Πολωνία), ASEAN (Φιλιππίνες), Ευρασία (Τουρκία)
    • Ποιες είναι οι κορυφαίες προκλήσεις των CTOs και των CIOs;
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Πνευματικά δικαιώματα © 2025 από The Codest. Όλα τα δικαιώματα διατηρούνται.

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