Build Dumb, Refactor Smart: Ruby on Rails Kodundan Sorunlara Nasıl Masaj Yapılır?

Yayınlanan: 2022-03-11
Daniel Lewis, 4 yılı aşkın süredir profesyonel bir Ruby on Rails geliştiricisidir ve çoğu Toptal aracılığıyla olmak üzere yaklaşık bir düzine yüksek trafikli web uygulaması üzerinde çalışmaktadır.

Bazen müşteriler bize gerçekten sevmediğimiz özellik istekleri verir. Müşterilerimizi sevmediğimizden değil, müşterilerimizi seviyoruz. Bu özelliği beğenmediğimizden değil—müşteri tarafından talep edilen çoğu özellik, iş hedefleri ve gelirleriyle mükemmel bir şekilde uyumludur.

Bazen bir özellik isteğini sevmeyiz çünkü onu çözmenin en kolay yolu kötü kod yazmaktır ve aklımıza şık bir çözüm gelmiyor. Bu, çoğumuz Rails geliştiricilerini RubyToolbox, GitHub, geliştirici blogları ve StackOverflow aracılığıyla sonuçsuz aramalara göndererek kendimizi daha iyi hissetmemizi sağlayacak bir mücevher veya eklenti veya örnek kod arıyor.

Bazen bir özellik isteğini sevmeyiz çünkü onu çözmenin en kolay yolu bozuk kod yazmaktır.
Cıvıldamak

Refactor Ruby on Rails Kodu

Pekala, size şunu söylemek için buradayım: Kötü kod yazmakta sorun yok. Bazen, kötü Rails kodunun güzel koda yeniden düzenlenmesi, zaman sıkıntısı altında uygulanan kötü düşünülmüş bir çözümden daha kolaydır.

Bu, korkunç yara bandı çözümlerimdeki sorunları çözerken izlemeyi sevdiğim Rails yeniden düzenleme sürecidir:

Bu Ruby on Rails yeniden düzenleme süreci, Rails sorunlarını çözmek için takip ettiğim süreç.

Alternatif bir bakış açısı için, adım adım yeniden düzenlenen bir özelliğin Git taahhüt günlüğü:

Bu günlük, adım adım yapılan bir Rails yeniden düzenleyicisini gösterir.

Ve işte Toptal ağındaki bir meslektaşımdan büyük ölçekli yeniden düzenleme hakkında ilginç bir makale daha.

Nasıl yapıldığını görelim.

Görünümler

Adım 1. Görünümlerde Başlayın

Diyelim ki yeni bir özellik için bilet almaya başlıyoruz. Müşteri bize şunu söylüyor: "Ziyaretçiler, karşılama sayfasında aktif Projelerin bir listesini görebilmelidir."

Bu bilet görünür bir değişiklik gerektiriyor, bu nedenle işe başlamak için makul bir yer Görünümler'de olacaktır. Sorun basit ve hepimizin defalarca çözmek için eğitildiği bir sorun. Bunu Yanlış Yolda çözeceğim ve çözümümü uygun alanlara nasıl yeniden yansıtacağımı göstereceğim. Bir Problemi Çözmek Yanlış Yol , doğru çözümü bilmemenin yarattığı sıkıntıdan kurtulmamıza yardımcı olabilir.

Başlamak için, active adlı bir boole özniteliğine sahip Project adlı bir modelimiz olduğunu varsayalım. Active'in true'ya eşit olduğu tüm Projects bir listesini almak istiyoruz, böylece Project.where(active: true) active true each blokla bunun üzerinde dolaşabiliriz.

 app/views/pages/welcome.haml: %ul.projects - Project.where(active: true).each do |project| %li.project= link_to project_path(project), project.name

Ne dediğinizi biliyorum: "Bu asla bir kod incelemesinden geçemez" veya "Müvekkilim kesinlikle bunun için beni kovar." Evet, bu çözüm Model-Görünüm-Denetleyici endişe ayrımını bozar, izlenmesi zor olan başıboş veritabanı çağrılarına neden olabilir ve gelecekte bakımı zor olabilir. Ama bunu yapmanın değerini bir düşünün Yanlış Yol :

  1. Bu değişikliği sahnelemede 15 dakikadan kısa sürede elde edebilirsiniz.
  2. İçeride bırakılırsa, bu bloğun önbelleğe alınması kolaydır.
  3. Bu Rails sorununu düzeltmek basittir (küçük bir geliştiriciye verilebilir).

Adım 2. Kısmi kısımlar

Bunu The Wrong Way yaptıktan sonra kendim hakkında kötü hissediyorum ve kötü kodumu izole etmek istiyorum. Bu değişiklik açıkça yalnızca Görünüm katmanının bir endişesi olsaydı, utancımı kısmi olarak yeniden değerlendirebilirdim.

 app/views/pages/welcome.haml: = render :partial => 'shared/projects_list' app/views/shared/projects_list.haml: %ul.projects - Project.where(active: true).each do |project| %li.project= link_to project_path(project), project.name

Bu biraz daha iyi. Açıkçası, hala bir Görünümde Model sorgusu hatası yapıyoruz, ancak en azından bir bakıcı daha sonra geldiğinde ve benim korkunç kısmi durumumu gördüğünde, özellikle bu Rails kodu sorununu çözmenin basit bir yoluna sahip olacaklar. Aptalca bir şeyi düzeltmek, kötü uygulanmış, hatalı bir soyutlamayı düzeltmekten her zaman daha kolaydır.

Aptalca bir şeyi düzeltmek, kötü uygulanmış, hatalı bir soyutlamayı düzeltmekten her zaman daha kolaydır.
Cıvıldamak

Adım 3. Yardımcılar

Rails'deki Yardımcılar, Görünümlerinizin bir bölümü için bir DSL (Etki Alanına Özgü Dil) oluşturmanın bir yoludur. Haml veya HTML yerine content_tag'leri kullanarak kodunuzu yeniden yazmanız gerekir, ancak diğer geliştiricilerin 15 satır yazdırılmayan Görünüm kodu için size dik dik bakmalarına gerek kalmadan veri yapılarını değiştirmeye izin verme avantajına sahip olursunuz.

Burada yardımcıları kullanacak olsaydım, muhtemelen li etiketini yeniden düzenlerdim.

 app/views/shared/projects_list.haml: %ul.projects - Project.where(active: true).each do |project| = project_list_item(project) app/helpers/projects_helper.rb: def project_list_item(project) content_tag(:li, :class => 'project') do link_to project_path(project), project.name end end

Kontrolörler

Adım 4. Kontrolörlere Taşıyın

Belki de korkunç kodunuz sadece bir Görünüm endişesi değildir. Kodunuz hala kokuyorsa, Görünümlerden Denetleyicilere geçiş yapabileceğiniz sorguları arayın.

 app/views/shared/projects_list.haml: %ul.projects - @projects_list.each do |project| = project_list_item(project) app/controllers/pages_controller.rb: def welcome @projects = Project.where(active: true) end

Adım 5. Denetleyici Filtreleri

Kodu bir Denetleyiciye before_filter veya after_filter taşımak için en belirgin neden, birden çok Denetleyici eyleminde çoğalttığınız kod içindir. Denetleyici eyleminin amacını görünümlerinizin gereksinimlerinden ayırmak istiyorsanız, kodu Denetleyici filtresine de taşıyabilirsiniz.

 app/controllers/pages_controller.rb: before_filter :projects_list def welcome end def projects_list @projects = Project.where(active:true) end

Adım 6. Uygulama Denetleyicisi

Her sayfada görünmesi için kodunuza ihtiyacınız olduğunu varsayalım veya Denetleyici yardımcı işlevlerini tüm denetleyiciler için kullanılabilir hale getirmek istiyorsanız, işlevinizi ApplicationController'a taşıyabilirsiniz. Değişiklikler genel ise, uygulama düzeninizi de değiştirmek isteyebilirsiniz.

 app/controllers/pages_controller.rb: def welcome end app/views/layouts/application.haml: %ul.projects - projects_list.each do |project| = project_list_item(project) app/controllers/application_controller.rb: before_filter :projects_list def projects_list @projects = Project.where(active: true) end

Modeller

Adım 7. Modeli Yeniden Düzenleme

MVC'nin sloganı şu şekildedir: Fat Model, Skinny Controllers ve Dumb Views . Modelde elimizden gelen her şeyi yeniden düzenlememiz bekleniyor ve çoğu karmaşık işlevselliğin sonunda model ilişkilendirmeleri ve model yöntemleri haline geleceği doğrudur. Modelde her zaman biçimlendirme/görüntüleme yapmaktan kaçınmalıyız, ancak verileri diğer veri türlerine dönüştürmeye izin verilir. Bu durumda, Model'e yeniden yansıtmak için en iyi şey, bir kapsam haline getirebileceğimiz where(active: true) yan tümcesi olacaktır. Kapsam kullanmak yalnızca çağrının daha güzel görünmesini sağladığı için değerli değildir, ayrıca delete veya outdated gibi bir öznitelik eklemeye karar verirsek, tüm where yan tümcelerimizi aramak yerine bu kapsamı değiştirebiliriz.

 app/controllers/application_controller.rb: before_filter :projects_list def projects_list @projects = Project.active end app/models/project.rb: scope :active, where(active: true)

Adım 8. Model Filtreleri

Bu durumda bir Modelin before_save veya after_save after_save filters için özel bir kullanımımız yok, ancak genellikle attığım sonraki adım, işlevselliği Kontrolörler ve Model yöntemlerinden Model filtrelerine taşımak.

Diyelim ki başka bir özelliğimiz var, num_views . num_views > 50 ise, Proje devre dışı kalır. Bu sorunu Görünümde çözebiliriz, ancak bir Görünümde veritabanı değişiklikleri yapmak uygun değildir. Bunu Denetleyicide çözebiliriz, ancak Denetleyicilerimiz mümkün olduğunca ince olmalıdır! Modelde kolayca çözebiliriz.

 app/models/project.rb: before_save :deactivate_if_over_num_views def deactivate_if_over_num_views if num_views > 50 self.active = false fi end

Not: Bir Model filtresinde self.save çağrısı yapmaktan kaçınmalısınız, çünkü bu özyinelemeli kaydetme olaylarına neden olur ve uygulamanızın veritabanı manipülasyon katmanı yine de Controller olmalıdır.

Adım 9. Kitaplıklar

Bazen, özelliğiniz kendi kitaplığını garanti edebilecek kadar büyüktür. Pek çok yerde yeniden kullanıldığından veya üzerinde ayrı ayrı geliştirme yapmak isteyeceğiniz kadar büyük olduğundan onu bir kitaplık dosyasına taşımak isteyebilirsiniz.

Kitaplık dosyalarını lib/ dizininde depolamak iyidir, ancak büyüdükçe onları gerçek bir RubyGem'e aktarabilirsiniz! Kodunuzu bir kitaplığa taşımanın büyük bir avantajı, kitaplığı modelinizden ayrı olarak test edebilmenizdir.

Her neyse, bir Proje Listesi durumunda, scope :active çağrısını Project modelinden bir kitaplık dosyasına taşımayı ve onu Ruby'ye geri getirmeyi haklı gösterebiliriz:

 app/models/project.rb: class Project < ActiveRecord::Base include Activeable before_filter :deactivate_if_over_num_views end lib/activeable.rb: module Activeable def self.included(k) k.scope :active, k.where(active: true) end def deactivate_if_over_num_views if num_views > 50 self.active = false end end end

Not: bir Rails Model sınıfı yüklendiğinde ve sınıf kapsamında k değişkeni olarak geçtiğinde self.included yöntemi çağrılır.

Çözüm

Bu Ruby on Rails yeniden düzenleme eğitiminde 15 dakikadan kısa bir süreyi aldık ve bir çözüm uyguladık ve bunu özellik setine kabul edilmeye veya kaldırılmaya hazır olarak kullanıcı testi için hazırlamaya koyduk. Yeniden düzenleme sürecinin sonunda, listelenebilir, etkinleştirilebilir öğeleri birden çok Modelde uygulamak için bir çerçeve ortaya koyan ve en katı inceleme sürecini bile geçecek bir kod parçasına sahibiz.

Kendi Rails yeniden düzenleme işleminizde, bundan eminseniz ardışık düzende birkaç adımı atlamaktan çekinmeyin (örneğin, Görünümden Denetleyiciye veya Denetleyiciden Modele atlayın). Kod akışının Görünümden Modele olduğunu unutmayın.

Aptal görünmekten korkma. Modern dilleri eski CGI şablon oluşturma uygulamalarından ayıran şey, her seferinde her şeyi Doğru Şekilde yapmamız değil; yeniden düzenleme, yeniden kullanma ve çabalarımızı paylaşma zamanımızı ayırmamızdır.

İlgili: Zaman Damgası Kesmesi: Bir Ruby on Rails ActiveRecord Öyküsü