Jak separacja kodu i danych stała się praktyką?

29

Przeczytaj uważnie pytanie: pyta, jak , a nie dlaczego .

Ostatnio natknąłem się na tę odpowiedź , która sugeruje użycie bazy danych do przechowywania niezmiennych danych:

Wygląda na to, że wiele magicznych liczb, które opisujesz - szczególnie jeśli są zależne od części - to tak naprawdę dane, a nie kod. [...] Może to oznaczać bazę danych typu SQL lub po prostu sformatowany plik tekstowy.

Wydaje mi się, że jeśli masz dane, które są częścią tego, co robi twój program, to rzeczą do zrobienia jest umieszczenie ich w programie . Na przykład, jeśli funkcją twojego programu jest zliczanie samogłosek, co jest złego w tym, że się vowels = "aeiou"w nim znajduje? W końcu większość języków ma struktury danych zaprojektowane specjalnie do tego celu. Dlaczego zawracasz sobie głowę oddzielaniem danych , umieszczając je w „sformatowanym pliku tekstowym”, jak sugerowano powyżej? Dlaczego po prostu nie sformatować tego pliku tekstowego w wybranym języku programowania? Czy to jest baza danych? A może to kod?

Jestem pewien, że niektórzy uznają to za głupie pytanie, ale zadaję to z całą powagą. Wydaje mi się, że „oddzielny kod i dane” pojawiają się kulturowo jako pewna oczywista prawda, wraz z innymi oczywistymi rzeczami, takimi jak „nie podawaj swoim zmiennym mylących nazw” i „nie unikaj używania białych znaków tylko dlatego, że twój język bierze pod uwagę to nieistotne ”.

Weźmy na przykład ten artykuł: Problem z oddzielaniem danych od kodu lalkowego . Problem ? Jaki problem? Jeśli Puppet jest językiem opisującym moją infrastrukturę, dlaczego nie może również opisać, że serwer nazw to 8.8.8.8? Wydaje mi się, że problemem nie jest to, że kod i dane są pomieszane 1, ale że Puppet brakuje wystarczająco bogatych struktur danych i sposobów na komunikację z innymi rzeczami.

Uważam tę zmianę za niepokojącą. Programowanie zorientowane obiektowo mówiło „chcemy dowolnie bogate struktury danych”, a zatem obdarowaliśmy struktury danych mocami kodu. W rezultacie otrzymujesz enkapsulację i abstrakcję. Nawet bazy danych SQL mają procedury składowane. Gdy sekwestrujesz dane w YAML, plikach tekstowych lub głupich bazach danych, tak jakbyś usuwał guz z kodu, tracisz to wszystko.

Czy ktoś może wyjaśnić, jak powstała ta praktyka oddzielania danych od kodu i dokąd zmierza? Czy ktokolwiek może przytoczyć publikacje według źródeł lub podać odpowiednie dane, które pokazują „oddzielny kod od danych” jako nowe przykazanie i ilustrują jego pochodzenie?

1: jeśli można nawet dokonać takich rozróżnień. Patrzę na ciebie, programiści Lisp.

Phil Frost
źródło
5
Zachowaj swobodę zakopania wszystkich plików HTML i CSS w wybranym języku.
JeffO
3
Myślę, że autor cytatu miał na myśli to, że magiczne liczby nie są niezmienne.
Pieter B
4
Nie ma nic złego w kodowaniu samogłosek na stałe. Jeśli Twoja aplikacja będzie kiedykolwiek używana tylko do liczenia samogłosek w języku angielskim.
Michael Paulukonis
3
Głównym technicznym powodem oddzielania kodu i danych jest brak konieczności ponownej kompilacji kodu, gdy dane się zmieniają. Dlatego zastanawiałbym się, czy dotyczy to w takim samym stopniu języków skryptowych.
user16764
1
@MichaelPaulukonis: A umieszczenie go w bazie danych to fałszywe rozwiązanie. Czy potrzebne są zmiany w języku holenderskim? Zero (nawet bez zmiany DB). Czy potrzebne są zmiany w języku francuskim / niemieckim? Obsługa co najmniej ISO-8859-1. (Więcej niż DB). Czy potrzebne są zmiany w języku greckim / rosyjskim? Obsługa Unicode (więcej niż DB). W rzeczywistości nie mogę wymyślić żadnego języka, w którym ta baza danych byłaby pomocna.
MSalters

Odpowiedzi:

22

Istnieje wiele dobrych powodów, aby oddzielić dane od kodu, i kilka powodów, aby tego nie robić. Przychodzą mi na myśl następujące kwestie.

Aktualność. Kiedy znana jest wartość danych? Czy to jest w momencie pisania kodu, kiedy jest kompilowany, łączony, wydawany, licencjonowany, konfigurowany, uruchamiany lub uruchomiony. Na przykład liczba dni w tygodniu (7) jest znana wcześnie, ale kurs wymiany USD / AUD będzie znany dość późno.

Struktura. Czy jest to pojedynczy zestaw danych zgodnie z jednym rozważaniem, czy może być dziedziczony lub stanowić część większej kolekcji przedmiotów? Języki takie jak YAML i JSON umożliwiają łączenie wartości z wielu źródeł. Być może niektóre rzeczy, które początkowo wydają się niezmienne, są lepiej dostępne jako właściwości w menedżerze konfiguracji.

Miejscowość. Jeśli wszystkie elementy danych są przechowywane w ograniczonej liczbie miejsc, znacznie łatwiej nimi zarządzać, szczególnie jeśli niektóre mogą wymagać zmiany na nowe (niezmienne) wartości. Edycja kodu źródłowego tylko w celu zmiany wartości danych wprowadza ryzyko nieumyślnych zmian i błędów.

Rozdzielenie obaw. Poprawne działanie algorytmów najlepiej jest oddzielić od rozważenia, jakich wartości danych należy użyć. Dane są potrzebne do testowania algorytmów, a nie do bycia ich częścią. Zobacz także http://c2.com/cgi/wiki?ZeroOneInfinityRule .

W odpowiedzi na twoje pytanie nie jest to nic nowego. Podstawowe zasady nie uległy zmianie od ponad 30 lat i o tym wielokrotnie pisano w tym czasie. Nie mogę sobie przypomnieć żadnych dużych publikacji na ten temat, ponieważ na ogół nie jest to uważane za kontrowersyjne, a jedynie coś, co można wyjaśnić nowicjuszom. Tutaj jest trochę więcej: http://c2.com/cgi/wiki?SeparationOfDataAndCode .

Z mojego osobistego doświadczenia wynika, że ​​znaczenie tego rozdziału w danym oprogramowaniu staje się z czasem coraz większe. Wartości, które zostały zakodowane na stałe, są przenoszone do plików nagłówkowych, wartości wkompilowane są przenoszone do plików konfiguracyjnych, proste wartości stają się częścią struktur hierarchicznych i zarządzanych.

Co do trendów, nie widziałem żadnych poważnych zmian w nastawieniu wśród profesjonalnych programistów (10+ lat), ale branża jest coraz bardziej pełna młodych ludzi i wiele rzeczy, o których myślałem, że są znane i postanowiłem, że wciąż czekają na mnie wyzwania i nowe pomysły, czasem nowe wgląd, ale czasem z niewiedzy.

david.pfx
źródło
2
Czy mógłbyś rozwinąć historię i trend tej praktyki? Gdyby wszyscy zastanowili się nad tym, nie zadałbym tego pytania. Założeniem tego pytania jest to, że ludzie nie zastanawiają się dokładnie, dokąd powinny iść ich dane (skompilowane stałe, zewnętrzne bazy danych, YAML ...), a raczej myślą: „KOD I DANE MIESZANE ZŁO! HULK SMASH!” Dlaczego lub kiedy to się stało?
Phil Frost
To nie jest część mojego doświadczenia, więc nie mogę ci powiedzieć. Do mojej odpowiedzi dodałem kilka parasoli.
david.pfx
Myślę, że „napływ młodzieży” jest słusznym wyjaśnieniem, ale wstrzymuję się z akceptacją, ponieważ chciałbym usłyszeć od niektórych z tych młodych ludzi, aby dowiedzieć się, skąd pomysł. Najwyraźniej mają część „oddzielny kod i dane”, ale nie sądzę, że dostali resztę. Czy przeczytali to w poście na blogu? Książka? Gdzie i kiedy?
Phil Frost
Zawsze dostaniesz „_____ BAD! HULK SMASH!” - to nie znaczy, że to prawda. Często tego rodzaju rzeczy (np. „GOTO” BAD! HULK SMASH! ”) Uczy się początkujących, nie ucząc ich, dlaczego i jakie są wyjątki.
AMADANON Inc.,
Localitydziała również w odwrotnym kierunku: skończyliśmy z rodzajem systemu wtyczek ze względu na niestandardowe wymagania dla różnych klientów, a przez kilka lat prób i błędów nauczyliśmy się utrzymywać stałe (nawet tabele, za pomocą list nagrań) bazy danych i kodu. Zarówno dlatego, że użycie go w dowolnym miejscu innym niż ta „wtyczka” jest nieprawidłowe, jak i dlatego, że zmiany są automatycznie wersjonowane po ich wprowadzeniu.
Izkata
8

Dane skalują się znacznie lepiej i można je o wiele łatwiej wyszukiwać i modyfikować, gdy są oddzielone od kodu. Nawet jeśli Twoje dane mają charakter kodyfikacyjny - na przykład dane reprezentują reguły lub polecenia - jeśli możesz przechowywać reprezentują ten kod jako dane ustrukturyzowane, możesz cieszyć się korzyściami z osobnego przechowywania:

uprawnienia

Jeśli dane są zakodowane na stałe, musisz edytować plik źródłowy w celu edycji tych danych. Oznacza to, że albo:

  • Tylko programiści mogą edytować dane. To źle - wprowadzanie danych nie wymaga umiejętności i wiedzy programisty.

  • Osoby niebędące programistami mogą edytować plik źródłowy. To źle - mogą spieprzyć plik źródłowy, nawet o tym nie wiedząc!

  • Dane są zakodowane na stałe w osobnych plikach źródłowych, a nie-programiści mają dostęp tylko do tych plików. Ale to się tak naprawdę nie liczy - teraz dane są oddzielone od kodu i przechowywane we własnych plikach ...

redagowanie

Jeśli chodzi o to, kto może edytować dane, najlepiej przechowywać je osobno. Co powiesz na to, jak będą edytować dane? Jeśli masz dużo danych, ręczne wpisywanie ich jest żmudne i przycina błędy. Posiadanie do tego trochę interfejsu użytkownika jest znacznie lepsze! Nawet jeśli nadal musisz pisać wszystko, nie musisz wpisywać płyty kotła formatu, więc jest mniejsze prawdopodobieństwo, że zepsujesz format i spieprzysz cały plik!

Jeśli dane są zakodowane na stałe, utworzenie tego interfejsu użytkownika będzie oznaczało, że zautomatyzowane narzędzie będzie edytować ręcznie pisane pliki źródłowe. Niech to zatopi się - zautomatyzowane narzędzie otworzy pliki źródłowe, spróbuje znaleźć dane i zmodyfikować ten kod. Brrr ... Microsoft wprowadził częściowe klasy do C #, aby uniknąć tych rzeczy ...

Jeśli dane są osobne, Twoje zautomatyzowane narzędzie będzie musiało po prostu edytować pliki danych. Wolę wierzyć, że programy komputerowe edytujące pliki danych nie są obecnie tak rzadkie ...

skalowanie

Kod i dane skalują się bardzo różnie. Gdy twój kod rośnie, chcesz podzielić go na kolejne klasy i metody (lub struktury danych i funkcje), ale twoje dane - bez względu na to, jak bardzo rosną - chcesz przechowywać w jednym miejscu. Nawet jeśli musisz rozdzielić je na wiele plików, chcesz jakoś spakować te pliki, aby łatwiej było uzyskać dostęp do tych danych z kodu.

Wyobraź sobie, że masz tysiące linii danych w pliku źródłowym. Kompilator / interpreter musi przechodzić przez wszystkie te dane za każdym razem, gdy czyta plik, i analizować go za pomocą drogiego leksykonu i analizatora składni - nawet jeśli nie masz dostępu do tych danych w tym konkretnym uruchomieniu programu. Ponadto, gdy edytujesz rzeczywisty kod w tym pliku, musisz obejść dane, co utrudnia cały proces. Pliki danych można również indeksować. Zakodowane dane? Nie tak bardzo...

badawczy

Masz mnóstwo danych - to naturalne, że będziesz chciał je przeszukać.

  • Jeśli przechowujesz go w bazie danych - możesz użyć języka zapytań do bazy danych.

  • Jeśli przechowujesz go w pliku XML - możesz użyć XPath.

  • Jeśli przechowujesz go w JSON / YAML - możesz załadować go do REPL swojego ulubionego języka skryptowego i wyszukać.

  • Nawet jeśli przechowujesz go w zwykłym starym pliku tekstowym, ponieważ ma on strukturę, którą program może rozpoznać, możesz użyć grep / sed / awk do jego przeszukiwania.

Chociaż prawdą jest, że możesz również grep / sed / awk poprzez dane zakodowane na stałe w pliku źródłowym, nie działa to również dobrze, ponieważ twoje zapytanie może pasować do innych, niepowiązanych wierszy lub pominąć wiersze, które zostały napisane inaczej, ponieważ pozwala na to składnia reprezentacji danych języka programowania.

Istnieją narzędzia do przeszukiwania kodu, ale są one przydatne do wyszukiwania deklaracji, a nie danych zakodowanych na stałe.

Biorąc to pod uwagę ...

Bardzo ważne jest, aby odróżnić dane od kodu. To, że coś jest napisane jako kod, nie oznacza, że ​​nie mogą to być dane. I tylko dlatego, że coś jest napisane z reprezentacją danych, nie oznacza, że ​​tak naprawdę nie jest to kod.

Miałem klasę, kiedy mieliśmy bardzo surowe zasady dotyczące „magicznych liczb” - nie mogliśmy mieć żadnych cyfr w naszym kodzie. Oznacza to, że musieliśmy robić takie rzeczy jak:

#define THE_NUMBER_ZERO 0
//....
for(int i=THE_NUMBER_ZERO;i<cout;++i){
//....

co jest wręcz absurdalne! Tak, 0technicznie są to „dane”, ale są one tak samo częścią kodu jak reszta forpętli! Więc mimo, że może reprezentować go danych i oddzielenie go od kodu, to nie znaczy, że powinniśmy . Nie dlatego, że chcemy zostawić dane w kodzie, ale dlatego, że tak naprawdę nie są to dane - nie więcej niż reszta kodu, który jest również kompilowany do zer i jedynek ...

Idan Arye
źródło
7

Myślę, że dzieje się trochę zamieszania. Mieszacie dwie rzeczy razem: „Oddzielanie kodu i danych” oraz „Wyrażanie zachowania programu jako danych”.

W twoim przypadku martwisz się o drugi i wmieszasz w to pierwszy. Wyrażenie zachowania programu jako danych ułatwia rozszerzenie. W twoim przykładzie vowels = "aeiou"dodanie nowej samogłoski jest tak proste, jak dodanie znaku. Jeśli masz te dane zewnętrznie, możesz zmienić to zachowanie bez konieczności ponownej kompilacji programu.

A kiedy się nad tym zastanowić, OOP jest przedłużeniem tego myślenia. Powiązanie danych i zachowania razem pozwoli Ci zmienić zachowanie programu na podstawie danych programu.

Euforyk
źródło
2
Bo oczywiście lista samogłosek się zmieni.
cHao
13
@cHao Gdy tylko i18n wkracza, jest.
Przywróć Monikę
2
i18n może złamać ci głowę - zobacz kilka perwersyjnych przykładów w Javie na javaspecialists.eu/archive/Issue209.html
Rory Hunter
2
@Angew: Jak tylko wkroczy i18n, i tak jesteś skończony . Potrzebujesz do tego kodu; naiwne rozwiązanie nie jest w stanie obsłużyć każdej sprawy, nawet w języku angielskim. (Zapomnij ïna chwilę; rozmowa o LET'S yi w!) Przesuwanie listy się do bazy danych nie będzie to naprawić, a jest wręcz szkodliwe - to złożoność że będzie bezwartościowy jeśli zawinił, ale nie będzie nawet wiedzieć, co „złe” jest chyba jesteś projektowania dla i18n od podstaw. W tym momencie zdajesz sobie sprawę, że lista samogłosek i tak po prostu nie zamierza jej przeciąć.
cHao
1
@BenLee: Właściwie nie byłbym trochę zaskoczony. Obecnie pracuję nad zmianą takiego kodu w trakcie rozmowy. Ale outsourcing wszystkiego do bazy danych to przepowiadanie przyszłości. Jeśli jeszcze nie wiesz, czy coś będzie wymagało modyfikacji - a co ważniejsze, jeśli jeszcze nie wiesz, jak to będzie musiało zostać zmodyfikowane - wtedy IMO lepiej poczekać, aż będziesz potrzebować tej elastyczności, zanim ją dodasz .
cHao
5

Na przykład, jeśli funkcją twojego programu jest zliczanie samogłosek, co jest złego w tym, że masz w nim samogłosek = "aeiou"?

Zewnętrzne przechowywanie konfiguracji umożliwia posiadanie jednej wersji kodu, która powinna działać z wieloma konfiguracjami, alternatywą jest utrzymanie wielu wersji oprogramowania, które różnią się tylko konfiguracją.

Wspominacie samogłoski = „aeiou”, co jeśli czasami chcę „y”, czy powinienem przebudować cały program? Czy mogę łatwo aktualizować wersje teraz, gdy zmodyfikowałem kod? Jeśli wystąpił błąd, czy go spowodowałem, czy program jest uszkodzony?

Jeśli jest to w twoim programie, oznacza to, że twój program nie oczekuje, że użytkownicy zmienią definicję samogłosek bez zeskanowania kodu, aby zobaczyć możliwe skutki uboczne. Jeśli definicja jest przechowywana na zewnątrz, oznacza to, że program nie powinien przerwać żadnej rozsądnej wartości ustawionej w konfiguracji.

Podczas sekwestrowania danych w YAML lub plikach tekstowych lub głupich bazach danych, tak jakbyś usuwał guz z kodu

Niektórzy uważają, że jest odwrotnie, to znaczy usuwasz guz kodu z cennych danych, patrz: cytat Torvaldsa na temat dobrego programisty

FMJaguar
źródło
4
Cytat Torvaldsa odnosi się do struktur danych, a nie danych.
user949300
OP stwierdza: „Programowanie obiektowe mówiło:„ chcemy dowolnie bogatych struktur danych ”, a zatem obdarowaliśmy struktury danych mocami kodu”.
FMJaguar,
1
Jeśli dokonasz zasadniczej zmiany w definicji samogłoski, będziesz musiał ponownie uruchomić wszystkie testy automatyczne. Systemy rzadko, jeśli w ogóle, mają możliwość ponownego uruchomienia testów po zmianie pliku konfiguracyjnego we wdrożonym systemie. Tak więc takie definicje muszą być wbudowane w system; być może jako dwa zestawy kodowane na stałe z opcją konfiguracji do wyboru między nimi.
soru
+1 za cytat Torvaldsa. Zgadzam się z tym sentymentem: myślę, że w przykładzie marionetki problem polega na tym, że marionetka nie ma dobrej struktury danych do reprezentowania informacji, które ludzie chcą w niej umieścić. Zamiast naprawiać struktury danych, twórcy marionetek stwierdzili, że problem stanowi „dane w kodzie” (dlaczego? To jest pytanie!), I opracowali hiera , którą widzę jako coś więcej niż przeniesienie problemu gdzie indziej, a dodatkowo uniemożliwiając kojarzyć zachowanie z danymi.
Phil Frost
2

Byłem przy jednym projekcie, w którym kierownik nalegał na umieszczenie danych referencyjnych w małych tabelach i pomyślałem, że to głupie. Ponieważ jednak mieliśmy już skonfigurowaną infrastrukturę trwałości i łączność, skończyło się to dość niskim kosztem w porównaniu z innymi operacjami trwałości, które przeprowadzaliśmy.

Nadal uważam, że była to głupia decyzja, a gdyby nie dysponowaliśmy infrastrukturą, po prostu bym tego nie zrobił.

Ale niektóre argumenty na korzyść, które widzę, to:

  • Jeśli masz nastawienie do bazy danych, to umieszczenie danych referencyjnych w bazie danych SQL pozwala dołączyć do niej w celu raportowania.
  • Jeśli masz narzędzie administracyjne lub dostęp do bazy danych, możesz dostosować wartości w czasie wykonywania. (Chociaż może to grać z ogniem.)

Czasami zasady utrudniają praktyki kodowania. Na przykład pracowałem w kilku sklepach, w których wypychanie pliku .xml jest OK, a dotknięcie linii w kodzie wymaga pełnego cyklu regresji, a może testu obciążenia. Byłem więc w jednym zespole, w którym moje pliki .xml dla projektu były wyjątkowo bogate (i być może -heh- mógł zawierać jakiś kod).

Zawsze zadaję sobie pytanie, czy czerpię przyjemność z wypychania danych z kodu do zewnętrznego magazynu danych, nawet jeśli jest to tylko plik tekstowy, ale pracowałem z ludźmi, którzy po prostu postrzegają to w ten sposób jako swój pierwszy impuls.

Obrabować
źródło
3
Dobry komentarz na temat procedur sklepowych, w których edytowanie XML jest „ok”, ale edytowanie tego samego w kodzie jest dużym problemem.
user949300
pracował w jednym sklepie, w którym wszystko było w bazie danych, które mogło być, aż do tekstu na ekranie. Oprócz kodu interfejsu użytkownika jedyne, czego nie ma w bazie danych, to lokalizacja bazy danych i poświadczenia ...
jwenting
3
zawsze brzmi to głupio, dopóki pewnego dnia ktoś nie zapyta „czy możemy to zmienić dla użytkownika X, który tego wymaga”, a potem wcale nie wydaje się to takie głupie. Cholerni klienci :)
gbjbaanb
2
... a jeśli ten dzień jest „nigdy”, to długo nie czuję się głupio
Rob
2

Pozwól, że zadam ci całkowicie poważne pytanie przeciwne: jaka według ciebie jest różnica między „danymi” a „kodem”?

Kiedy słyszę słowo „dane”, myślę „stan”. Dane są z definicji rzeczą, którą sama aplikacja jest przeznaczona do zarządzania, a zatem tą samą rzeczą, o której aplikacja nie może wiedzieć w czasie kompilacji. Nie można na stałe zakodować danych, ponieważ zaraz po ich zakodowaniu staje się to zachowanie - nie dane.

Rodzaj danych różni się w zależności od aplikacji; komercyjny system fakturowania może przechowywać informacje o klientach i zamówieniach w bazie danych SQL, a program do grafiki wektorowej może przechowywać dane geometryczne i metadane w pliku binarnym. W obu tych przypadkach i pomiędzy nimi istnieje wyraźny i niezłomny podział między kodem a danymi. Dane należą do użytkownika , a nie do programisty, więc nigdy nie mogą być zakodowane na stałe.

Chodzi o to, aby mówić o najdokładniejszym technicznie opisie dostępnym dla mojego obecnego słownictwa: informacje dotyczące zachowania programu, które nie są zapisane w podstawowym języku programowania używanym do opracowania większości aplikacji.

Nawet ta definicja, która jest znacznie mniej niejednoznaczna niż samo słowo „dane”, ma kilka problemów. Na przykład, co jeśli znaczna część programu jest napisana w różnych językach? Osobiście pracowałem nad kilkoma projektami, które mają około 50% C # i 50% JavaScript. Czy kod JavaScript to „dane”? Większość ludzi powiedziałaby „nie”. A co z HTMLem, czy to „dane”? Większość ludzi nadal powiedziałaby „nie”.

Co z CSS? Czy to dane lub kod? Jeśli uważamy, że kod jest czymś, co kontroluje zachowanie programu, CSS tak naprawdę nie jest kodem, ponieważ tylko (głównie) wpływa na wygląd, a nie zachowanie. Ale tak naprawdę to nie są dane; użytkownik nie jest właścicielem, nawet aplikacja nie jest jej właścicielem. Jest to odpowiednik kodu dla projektanta interfejsu użytkownika. Jest podobny do kodu , ale nie do końca.

Mogę nazwać CSS rodzajem konfiguracji, ale bardziej praktyczną definicją jest to, że jest to po prostu kod w języku specyficznym dla domeny . To właśnie reprezentują Twój XML, YAML i inne „sformatowane pliki”. Powodem dla którego używamy języka specyficznego dla domeny jest to, że ogólnie mówiąc, jest on jednocześnie bardziej zwięzły i bardziej wyrazisty w swojej konkretnej domenie niż kodowanie tych samych informacji w języku programowania ogólnego przeznaczenia, takim jak C lub C # lub Java.

Czy rozpoznajesz następujący format?

{
    name: 'Jane Doe',
    age: 27,
    interests: ['cats', 'shoes']
}

Jestem pewien, że większość ludzi; to JSON . A oto ciekawa rzecz w JSON: w JavaScript jest to wyraźnie kod, aw każdym innym języku, to wyraźnie sformatowane dane. Prawie każdy główny język programowania ma co najmniej jedną bibliotekę do „parsowania” JSON.

Jeśli użyjemy tej samej składni w funkcji w pliku JavaScript, nie może to być nic innego niż kod. A jednak, jeśli weźmiemy ten JSON, wepchniemy go do .jsonpliku i przeanalizujemy w aplikacji Java, nagle będzie to „dane”. Czy to naprawdę ma sens?

Twierdzę, że „dane”, „konfiguracja” lub „kod” są nieodłączne od tego, co jest opisywane, a nie jak to jest opisywane.

Jeśli twój program potrzebuje słownika o wartości 1 miliona słów, aby np. Wygenerować losowe hasło, czy chcesz go zakodować w następujący sposób:

var words = new List<string>();
words.Add("aa");
words.Add("aah");
words.Add("ahhed");
// snip 172836 more lines
words.Add("zyzzyva");
words.Add("zyzzyvas");

A może po prostu wepchniesz wszystkie te słowa do pliku tekstowego rozdzielanego liniami i powiesz programowi, aby z niego czytał? Tak naprawdę nie ma znaczenia, czy lista słów nigdy się nie zmienia, nie jest to kwestia tego, czy kodujesz na stałe, czy na miękko (które wielu słusznie uważa za anty-wzór, gdy jest niewłaściwie stosowane), to po prostu kwestia jaki format jest najbardziej wydajny i sprawia, że ​​najłatwiej jest opisać „rzeczy”, bez względu na „rzeczy”. Nie ma znaczenia, czy nazywasz to kodem, czy danymi; są to informacje wymagane przez program do uruchomienia, a format pliku płaskiego jest najwygodniejszym sposobem zarządzania nim i zarządzania nim.

Zakładając, że przestrzegasz odpowiednich praktyk, wszystkie te rzeczy i tak podlegają kontroli źródła, więc równie dobrze możesz nazwać to kodem, po prostu kod w innym i być może bardzo minimalistycznym formacie. Możesz też nazwać go konfiguracją, ale jedyną rzeczą, która naprawdę odróżnia kod od konfiguracji, jest to, czy udokumentujesz go i powiesz użytkownikom, jak go zmienić. Być może mógłbyś wymyślić jakiś fałszywy argument o interpretacji konfiguracji podczas uruchamiania lub w czasie wykonywania, a nie w czasie kompilacji, ale wtedy zacząłbyś opisywać kilka dynamicznie pisanych języków i prawie na pewno wszystko z wbudowanym silnikiem skryptowym (np. większość gier). Kod i konfiguracja to wszystko, co postanowisz nazwać je niczym, niczym więcej, niczym innym.

Teraz nie jest zagrożeniem dla uzewnętrzniania informacje, które są rzeczywiście bezpieczne modyfikować (patrz odnośnik „miękkiego kodowania” powyżej). Jeśli uzewnętrznisz tablicę samogłoskową w pliku konfiguracyjnym i udokumentujesz ją jako plik konfiguracyjny dla użytkowników końcowych, dajesz im niemal niezawodny sposób na natychmiastowe zerwanie aplikacji, na przykład poprzez umieszczenie „q” jako samogłoski. Ale to nie jest podstawowy problem z „separacją kodu i danych”, to po prostu zły sens projektowy.

Mówię młodszym deweloperom, że powinni zawsze uzewnętrzniać ustawienia, których zmiany oczekują w zależności od środowiska. Obejmuje to między innymi parametry połączenia, nazwy użytkowników, klucze API, ścieżki do katalogów i tak dalej. Oni mogą być takie same na polu dev i produkcji, ale chyba nie, a administratorzy będą decydować, jak chcą go szukać w produkcji, a nie deweloperów. Potrzebny jest więc sposób zastosowania jednej grupy ustawień na niektórych komputerach i innych ustawień na innych komputerach - ergo, zewnętrznych plików konfiguracyjnych (lub ustawień w bazie danych itp.)

Podkreślam jednak, że po prostu umieszczenie niektórych „danych” w „pliku” nie jest tym samym, co przekazanie go na zewnątrz jako konfiguracji. Umieszczenie słownika słów w pliku tekstowym nie oznacza, że ​​chcesz, aby użytkownicy (lub dział IT) go zmienili, to tylko sposób na ułatwienie programistom zrozumienia, co się dzieje, do diabła, i, w razie potrzeby, ułatwienie sporadyczne zmiany. Podobnie, umieszczenie tych samych informacji w tabeli bazy danych niekoniecznie liczy się jako eksternalizacja zachowania, jeśli tabela jest tylko do odczytu i / lub DBA są instruowane, aby nigdy jej nie przekręcać. Konfiguracja oznacza, że ​​dane są zmienne, ale w rzeczywistości jest to określane przez proces i obowiązki, a nie przez wybór formatu.

Podsumowując:

  • „Kod” nie jest terminem ściśle zdefiniowanym. Jeśli rozszerzysz swoją definicję o języki specyficzne dla domeny i wszystko inne, co wpływa na zachowanie, wiele z tych pozornych tarć po prostu zniknie i wszystko to będzie miało sens. Możesz mieć nieskompilowany „kod” DSL w pliku płaskim.

  • „Dane” oznaczają informacje, które są własnością użytkownika (użytkowników) lub przynajmniej osoby innej niż programiści i nie są ogólnie dostępne w czasie projektowania. Nie można go zakodować na stałe, nawet jeśli chcesz to zrobić. Z możliwym wyjątkiem kodu samodmodyfikującego , oddzielenie kodu od danych jest kwestią definicji, a nie osobistych preferencji.

  • „Miękkie kodowanie” może być okropną praktyką w przypadku nadmiernego zastosowania, ale nie każdy przypadek eksternalizacji koniecznie stanowi miękkie kodowanie, a wiele przypadków przechowywania informacji w „płaskich plikach” niekoniecznie jest prawdziwą próbą eksternalizacji.

  • Konfiguracja to specjalny rodzaj miękkiego kodowania, który jest konieczny ze względu na wiedzę, że aplikacja może wymagać działania w różnych środowiskach. Wdrożenie osobnego pliku konfiguracyjnego wraz z aplikacją jest znacznie mniej pracochłonne (i znacznie mniej niebezpieczne) niż wdrożenie innej wersji kodu w każdym środowisku. Tak więc niektóre rodzaje miękkiego kodowania są faktycznie przydatne.

Aaronaught
źródło
1

Proponuję przeczytać ten klasyczny artykuł Orena Einiego (alias Ayende Rahien)

http://ayende.com/blog/3545/enabling-change-by-hard-coding-everything-the-smart-way

Moim własnym podejściem jest skupienie się na prostocie i czytelności. Może to oznaczać, że rzeczy, których konfiguracja jest mało prawdopodobna, najlepiej pozostawić na stałe (czytelnie). Pozwala to na użycie pełnej składni języka programowania do wyrażenia parametrów, a także na uzyskanie korzystnych efektów ubocznych, takich jak uzupełnianie kodu i błędy kompilatora w przypadku niewłaściwego użycia.

W ten sposób potencjalnie unikniesz złożoności parsowania / interpretacji („ale ktoś analizuje mój YAML / JSON” - mapowanie przeanalizowanego tekstu na określone wywołania API może być formą interpretacji) i unikniesz złożoności kolejnego kroku między „danymi” ”i jego zastosowanie.

Niektóre przypadki mogą wyrażać się w danych nawet w takim scenariuszu: na przykład określenie tysięcy punktów w przestrzeni 3D może lepiej pasować do pliku tekstowego niż do kodu, chociaż w niektórych językach, w tym w języku C przy użyciu inicjatorów struktur, kodu może być odpowiedni nawet do tego.

orip
źródło
1

Ok, załóżmy, że chcesz napisać jakiś program c ++ dla twojego wypoczynku. Wiesz dokładnie, co musi zrobić i czego nigdy nie będzie musiał robić. Teraz weź dowolną książkę o „nowoczesnym projektowaniu oprogramowania”. Oto zasada gry: dla każdej klasy w twoim projekcie i każdej nawet tak małej obudowie musisz wdrożyć każdy fantazyjny wzór opisany w tej książce, aby uczynić kod „czystym projektem”. Cóż, „zastrzyk zależności” będzie wystarczający dla wielu osób. (To c ++, nie java!) Programowanie uczy się z coraz bardziej teoretycznego punktu widzenia. Nie wystarczy, że wykonasz zadanie, musisz napisać kod, który jest łatwy w utrzymaniu, głupcy udowodnią ... wszystko w porządku. Problem zaczyna się, gdy ppl. przestańcie myśleć o prawdziwym celu, wymyślono wzorce projektowe i stać się dogmatami.

Pozwól, że przestanę pisać twoje narzędzie do liczenia listów (nad) przy użyciu jednej prostej zasady designe: kiedy piszesz kod, który wykonuje określone zadanie na danych wejściowych określonego typu, upewnij się, że jest on w stanie wykonać to zadanie dla dowolnego wejścia dane tego typu. - Jeśli chcesz napisać narzędzie do liczenia liter, warto je napisać w taki sposób, aby nie tylko mógł liczyć samogłoski, ale także „dowolną literę”. - Ponieważ możesz nie wiedzieć, czym właściwie jest analizowany korpus, możesz równie dobrze wybrać bardzo ogólne kodowanie (UTF-16) i obejmować większość (wszystkich?) Języków pisanych i ich symboli.

Do tego momentu mamy funkcję z dwoma argumentami (korpus i litery do zliczenia). Chcemy jedynie znaleźć dość ogólny „typ” lub „klasę”, do której należą również litery: z pewnością możemy zrobić coś lepszego niż symbole ASCII!

Wejdź do demona posługującego się „uogólnieniem i możliwością ponownego użycia” -dogma: - Dlaczego nie policzyć żadnego symbolu dowolnej klasy w strumieniu wejściowym tej klasy? (streszczenie od liter do sekwencji bitów o dowolnej, ale skończonej długości, ponieważ jest to najbardziej ogólny sposób, jaki można uzyskać za pomocą komputera ...) - Czekaj, nawet wtedy wciąż liczymy liczby naturalne. Jednak zliczanie można uogólnić jako odwzorowanie z zestawu policzalnego na sam spełniający aksjomaty ... [masz pomysł]

Teraz ten przykład może być głupi, ale jeśli weźmiesz pod uwagę bardziej złożone zadania projektowe niż narzędzie do liczenia, możesz znaleźć wszelkie możliwości wprowadzenia dodatkowej abstrakcji wymaganej zgodnie z pewnym wzorcem projektowym znalezionym w książce.

Rozdzielenie „danych” i „kodu” prawdopodobnie będzie albo trywialne (argumenty funkcji), albo będziesz traktować niezmienniki jako zmienne („dane”).

W przypadku jakichkolwiek nieporozumień istnieje prawdopodobieństwo, że „interfejsy” i „usługi” oraz wszystkie specyfiki klas (np. Typy) będą nagle „danymi”, to znaczy zależności, które należy wprowadzić z zewnątrz. Uważam, że kursy informatyczne prowadzone na uniwersytetach stały się bardzo podobne do wykładów z filozofii i jest mniej czasu na prawdziwe projekty, aby studenci mogli zdobyć doświadczenie w tworzeniu oprogramowania, które działa. Jeśli kiedykolwiek zastanawiasz się, dlaczego musisz zastosować szalenie skomplikowany wzór zamiast oczywistego rozwiązania, ten rozwój jest (prawdopodobnie) sposobem, w jaki wymóg ten został „stworzony” ...

Do konkretnego problemu: Jeśli mógłbyś 1.) napisać program z maksymalną ilością twardego kodu dla konkretnego przypadku, a następnie 2.) uogólnić na podstawie tego kodu w prosty sposób, np. wprowadzając więcej argumentów funkcyjnych i używając innych „trywialnych wzorców” możesz być pewien, że oddzielasz kod i dane, w oczywisty sposób, tak jak to zrobiono od czasu wynalezienia programowania funkcjonalnego. (często pomijasz 1. i robisz 2. natychmiast ...)

Wszystko, co nieoczywiste tutaj, jest prawdopodobnie przypadkiem „impasu teorii”: jak pisanie interfejsu odnoszącego się do interfejsu i jeszcze innego interfejsu ... a na końcu masz schludny mały plik xml, aby skonfigurować wszystkie te interfejsy i zależności, które należy wstrzyknąć do swojego bałaganu interfejsu klasy.

Miejmy nadzieję, że parser xml, którego potrzebujesz, nie potrzebuje konfiguracji xml, aby działać ...

bhak
źródło