Posts Tagged ‘bazy danych’
Praktyki – Dzień 1 – Git, bazy danych, migracje
Choć moje praktyki już minęły to forma notek opartych o każdy dzień mojej pracy będzie dla mnie (i może dla Was) wygodna dlatego też najbliższe notki będą się trzymały takiej formy.
Pierwszy dzień mojej pracy rozpoczął się od ustalenia moich obowiązków i obowiązujących zasad. Ponieważ był to krótki wstęp to zaraz po nim można było przystąpić do działania. Na początek zapoznałem się z rozproszonym systemem kotroli wersji o nazwie Git. Pomimo wielu bardzo znanych konkurentów w postaci CVS czy SVN Git zdobywa coraz większą popularność. Więcej na jego temat możecie przeczytać -> TU <-. Dla tych co znają SVS może się przydać lektura -> TEJ <- strony. Jeżeli nie chce Wam się czytać możecie obejrzeć -> TO <-.
Po zapoznaniu się z Git-em, czyli czymś z czym było mi dane pracować przeszedłem do projektowania bazy danych przyszłej aplikacji (do tego czasu już wiedziałem jaką aplikację będę robił). Wybór padł na PostgreSQL choć równie dobrze mógł to być MySQL czy też SQLite 3 ponieważ Ruby on Rails wspiera wszystkie te systemy baz danych. To który system relacyjnych baz danych jest lepszy jest kwestią osobistych preferencji więc nie będę tutaj wywyższać żadnego z nich Dla tyc co nie mają o różnicach pojęcia przedstawię Wam niewielkie i bardzo ograniczone porównanie tych systemów -> TU <-.
Jakież było moje zaskoczenie gdy szef zabronił mi tworzyć tabele w już utworzonej bazie, ale przyznaję że miał rację. Jeżeli pracujecie w Ruby on Rails to zapomnijcie o własnoręcznym modyfikowaniu bazy! Zainteresujcie się za to migracjami będącymi podstawowym elementem aplikacji w Ruby on Rails. Czym jest migracja? Tak z grubsza można powiedzieć że migracja to plik opisujący jakie kolumny w danej tabeli należy utworzyć, usunąć lub zmodyfikować. Czas pokazać troche przykładowego kodu:
class AddSystemSettings < ActiveRecord::Migration
def self.up
create_table :system_settings do |t|
t.string :name
t.string :label
t.text :value
t.string :type
t.integer :position
end
SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
end
def self.down
drop_table :system_settings
end
end
Omówmy to co mamy powyżej:
-
class AddSystemSettings < ActiveRecord::Migration - podana tu nazwa klasy to nazwa naszej migracji (już bez symboli _),nazwa ta jest ważna, bo powinna ewidentnie wskazywać na to co robi dana migracja. Nazwy typu "DodajKolumne" nie mają najmniejszego sensu. Dlaczego? Po pierwsze jaką kolumnę, a po drugie do czego ją dodajesz? Nazwa "DodajKolumnęHasloDoUzytkownika" sprawdza się o wiele lepiej. Nie muszę Wam chyba pisać, że najlepiej używać angielskiego?
-
def self.up - oznacza że wszystko co będzie zawarte po tym, a przed odpowiednim "end" będzie wykonywane podczas migrowania "w górę". Na czym polega migrowanie w górę i w dół powiemy sobie za chwilę.
-
create_table :system_settings do |t| - utworzy w bazie danych tabelę o nazwie "system_settings", a następnie dla niej wykonana wszystkie polecenia podane poniżej
-
t.string :name - już wiecie po co było "do |t|" ? po to żeby Rails wiedział o którą tabele nam chodzi. W ten sposób dodajemy kolumnę "name" typu string do tabeli "system_settings". Typ string w bazie to VARCHAR. Można ograniczyć ilość znaków dopisując w tej samej linii, po przecinku ":limit => X" gdzie X to liczba znaków. Możecie się spotkać z zapisem "t.column :name, :string", to jest stary zapis używany w Rails 1.2.X. Nie stosujcie go, już wyszedł z użytku, choć zapewne go spotkacie w wielu tutorialach czy książkach.
-
Pozostałe wiersze tworzą jak widzicie odpowiednie kolumny w naszej tabeli
-
SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1 - tutaj tworzymy przykładowe dane, którymi zostanie wypełniona nasza tabela. W którymś z nadchodzących postów wyjaśnię Wam jak to zrobić lepiej.
-
def self.down - analogicznie do punktu 3 z tym, że teraz dla migracji w dół
-
drop_table :system_settings - usuń naszą tabelę
Taka migracja będzie zapisana w pliku o nazwie np. 20080707103005_add_system_settings.rb. Wszystkie migracje umieszcza się w odpowiednim do tego katalogu “db” a dokładne w jego podkatalogu “migrate”. No dobrze, ale skąd ten dziwny ciąg cyfr przed nazwą? Jest to dokładny czas utworzenia pliku migracji. Migracje z tak utworzonymi nazwami będą odpowiednio posortowane w stosunku do swoich kolegów co oznacza że zostaną wykonane w odpowiedniej kolejności. Wyobraźcie sobie sytację w której jedna migracja to add_column.rb która dodaje kolumną city do tabeli users (bo wcześniej zapomnieliśmy dodać tego pola) zaś druga do create_table.rb która tworzy tabelę users. Co zostanie wykonane pierwsze? Niestety add_column.rb ponieważ będzie pierwsza na liście po posortowaniu według nazw. Oznacza to że Rails będzie próbował dodać kolumnę do nieistniejącej tabeli co oczywiście spowoduje błąd. Dlatego bardzo ważne jest zapewnienie odpowiedniego posortowania migracji a robimy to przez dodawanie na początku ich nazw właśnie tak sformatowanego czasu.
Co zyskujemy dzięki migracjom? Mnóstwo czasu i nerwów. Po pierwsze migracje są praktycznie niezależne od użytego systemu baz danych. Oznacza to że mogę sie przestawić na MySQL a moje migracje tego nie zauważą i odpowiednio utworzą wszystkie tabele oraz kolumny. Widzicie jaka wygoda? Nie muszę się zastanawiać jakich poleceń używa się w MySQL a jakich w PostgreSQ, po prostu tworzę migrację a ona robi resztę za mnie. Po drugie przenośność aplikacji. Wyobraźcie sobie sytuację w której postanawiasz zmienić strukturę bazy danych w aplikacji, np. uznajesz że użytkownik powinien mieć w bazie pole “photo” w którym umieszcza link do swojego zdjęcia. Ponieważ nie wiesz czym są migracje modyfikujesz z poziomu np. konsoli istniejącą bazę danych i dodajesz kolumnę. Następnie zanosisz aplikację szefowi i próbuje on dodać zdjęcie do użytkownika. Co się dzieje? W najlepszym wypadku zdjęcie się nie pojawia w najgorszym masz mnóstwo błędów na ekranie. Ano tak! Szef nie modyfikował swojej bazy danych! Kolega któremu zaraz będziesz chciał pokazać swój program też nie, klient również… O rany, to znaczy że każdemu z nich muszę wprowadzić te same zmiany ręcznie… To tylko jedna kolumna, ale jak postanowisz dodać 5 nowych tabel i kompletnie przebudować stare? Będziesz u każdego siedział 2h żeby doprowadzić bazę do takiego stanu w jakim jest u Ciebie w domu? Nie! Wystareczy żebyś wszystkie zmiany jakich dokonujesz umieszczał w odpowiednich migrajcach. Potem zanosisz apliakcję znajomemu, każesz railsowi wykonać migrację albo przetworzyć bazę od podstaw i już! I teraz ważna uwaga. Pewnie będzie Cię kusiło żeby zrobić tak:
- Masz migrację tworzącą tabelę “users” z odpwowiednimi kolumnani jak “name“, “password” itp.
- Po dwóch dniach pracy zdajesz sobie sprawę że użytkownik mógłby wstawiać do bazy link do swojego zdjęcia
- Do migracji tworzącej tabelę “users” dopisujesz poprostu dodanie nowej kolumny “photo“
Nie rób tak! Zamiast dopisywać coś do istniejącej już migracji stwórz zupełnie nowy plik z migracją która zajmie się dodaniem tego brakującego pola. Dzięki temu przy pracy np. z repozytorium Twoi znajomi nie będą mieli problemów z dodawaniem zmian do istniejących plików migracji, po prostu skopiują nowy plik z dodatkową migracją i już. I pamiętaj o tworzeniu nazw które odzwierciedlają działanie migracji.
Podczas opisywania migracji stwierdziłem że powiem coś o migrowaniu w górę i w dół. Chodzi o to że migraja w górę to jest wykonanie następnej, nowszej migracji. Może to być migracja o jeden krok lub też o wszystkie nowsze. Migracja w dół to wracanie do migracji o niższych numerach (datach). To znaczy że kiedy migrujemy w gorę Rails otwiera plik z migracją o nowszej niż ostatnio wykoana dacie i wykonuje to co jest w bloku “def self.up … end”. Migracja w dół powoduje że Rails najpierw wykona polecenie “def self.down … end” a następnie oznaczy starszą migrację jako aktualną. W ten sposób możemy się cofnąć do postaci bazy danych z dowolnego etapu tworzenia aplikacji. Możemy też szybko zaimplementować wszelkie zmiany jakie nastąpiły w jej dalszych etapach.
Ufff, na dzisiaj wystarczy… Jeżeli znaleźliście jakieś błędy to bądźcie tak mili i napiszcie o nich w komentarzach.