Mam silne doświadczenie w Javie / Groovy i zostałem przydzielony do zespołu, który utrzymuje dość dużą bazę kodu C dla oprogramowania administracyjnego.
Niektóre problemy, takie jak radzenie sobie z kroplami w bazie danych lub generowanie raportów w plikach PDF i Excel, zostały przeniesione na zewnętrzną usługę Java.
Jednak jako programista Java jestem nieco zdezorientowany niektórymi aspektami kodu:
- jest pełny (szczególnie w przypadku „wyjątku”)
- istnieje wiele ogromnych metod (wiele ponad 2000 metod linii)
- nie ma zaawansowanych struktur danych (bardzo tęsknię za Listą, Setem i Mapą)
- brak rozdzielenia problemów (SQL jest z radością mieszany w całym kodzie)
W rezultacie czuję, że biznes jest ukryty w tonach kodu technicznego, a mój mózg, w kształcie Object Oriented i szczypta programowania funkcjonalnego, nie jest spokojny.
Dobrą stroną projektu jest to, że kod jest prosty: nie ma frameworka, nie ma manipulacji kodem bajtowym w czasie wykonywania, nie ma AOP. A serwer może jednocześnie odpowiadać ponad 10000 użytkownikom za pomocą jednego komputera, zużywając mniej pamięci niż java musi wypluć „witaj świecie”.
Chcę nauczyć się pisać kod C zgodnie z powszechnie przyjętymi nowoczesnymi zasadami. Czy istnieją powszechnie akceptowane zasady dotyczące pisania i struktury nowoczesnego języka C?
Coś trochę jak odpowiednik książki „Effective Java”, ale dla C.
Edytuj w świetle odpowiedzi i komentarzy:
- Spróbuję dostosować mój sposób myślenia do kodu C i nie będę próbował kopiować go do OOP.
- Zacząłem czytać i czytać zalecane przewodniki po stylach kodowania z komentarza (Standardy kodowania GNU i Styl kodowania jądra systemu Linux).
- Spróbuję następnie zaproponować ten styl kodu moim współpracownikom. Najtrudniejszą częścią może być przekonanie współpracowników, że ogromną metodę można podzielić na mniejsze części i że powtórzenie tych samych 4 wierszy kodu obsługi błędów można uniknąć za pomocą metody.
źródło
Odpowiedzi:
Mogę odczytać z twojego pytania, że problemem nie jest to, że kod jest stary C, ale po prostu złe programowanie. Większość problemów, o których wspominałeś, takich jak gadatliwość, ogromne funkcje linii 2000+ lub brak rozdzielenia problemów dotyczy wszystkich języków, C i Javy.
O szczegółowości wspomniano w kontekście obsługi błędów. Nie podałeś żadnego przykładu, więc mogę jedynie przypomnieć, że kod obsługi błędów to także kod . Nie ma usprawiedliwienia dla powtarzających się fragmentów kodu płyty kotłowej. Rozłóż to; albo do funkcji, albo (jeśli nie warto tworzyć osobnej funkcji) wykonaj
goto Error;
wzorzec i przenieś obsługę błędów i czyszczenie zasobów doError:
sekcji na dole funkcji.Jeśli przekazanie błędu w górę łańcucha połączeń wydaje się być problemem, zadaj sobie pytanie: czy funkcja tam naprawdę musi wiedzieć, że jakiś mały facet tutaj miał problem? Mechanizmy wyjątków wbudowane w język ułatwiają to, ale generalnie lepiej jest obsługiwać wyjątki wcześniej (w dowolnym języku), aby warunek błędu nie zanieczyszczał logiki kodu wysokiego poziomu. A jeśli funkcja tam naprawdę musi wiedzieć, istnieją sposoby naśladowania wyjątków za pomocą
setjmp
ilongjmp
.Myślę, że jedynym wspomnianym problemem związanym z C jest brak standardowych pojemników. Chociaż
Set
ogólnie można go zastąpić posortowaną tablicą iMap
(w przeważającej części) tablicą par lubstruct
(jeśli znasz zestaw kluczy,map[key] = value
zmienia się ws.key = value
), ale faktem jest, że nie ma dynamicznego kontenera tablic w standardzie biblioteka. W C99 możesz przynajmniej zadeklarować tablicę o zmiennej długości na stosie (int array[len]
), ale musiszlen
wcześniej obliczyć (zwykle nie trudne) i oczywiście nie możesz zwrócić jej jako dowolnego obiektu przydzielonego do stosu. Większość projektów kończy się pisaniem własnego kontenera z dynamiczną tablicą lub przyjmowaniem kontenera typu open source.Na zakończenie chciałbym zaznaczyć, że tam byłem. Byłem programistą Java, który przeniósł się do C ++ i czystego C. Chciałbym poradzić „przeczytaj książkę X, aby nauczyć się dobrego C”, ale nie ma czegoś takiego jak Java. Drogą do przodu jest wchłonięcie wszystkich zawiłości języka i standardowej biblioteki; google dużo, dużo czytam, a kod sporo aż zaczniesz myśleć w C. próbuje pisać rzeczy w C, tak jak w Javie jest tak frustrujące, jak próbuje napisać zdanie w języku obcym ze słowami bezpośrednio tłumaczone z matką język; zarówno ty, jak i czytelnik skulicie się. Dobra wiadomość jest taka, że nauka dobrego programowania jest powolna, ale nauka innego języka jest szybka. więc jeśli napiszesz porządny kod w Javie,
źródło
setjmp()
/longjmp()
jako ważnego narzędzia: nawet nie próbuje wykonać żadnego czyszczenia. Wszelkie alokacje zostaną ujawnione, blokada wstrzymana nie zostanie zwolniona, żaden otwarty plik nie zostanie zamknięty, a wszelkie przejściowe niespójności danych staną się trwałe. IMHO, ta para funkcji jest w zasadzie najgorszym hakiem, jaki kiedykolwiek wymyślono, z jedynym uzasadnieniem, że można ją wdrożyć. W końcu istnieje tylko jeden prawidłowy sposób obsługi błędów w C: jawne kody błędów.setjmp/longjmp
wyglądam jak ryba z wody w C i nigdy ich nie użyłem. Czułem się zmuszony do włączenia ich tylko z powodu licznych samouczków / bibliotek w Internecie naśladujących wyjątki, więc pomyślałem, że są ludzie, którzy faktycznie z niego korzystają.Polecam ostrożność, czy warto poświęcić swój czas i pieniądze firmy, by wydać zasoby na „modernizację” działającego oprogramowania o niskiej złożoności kodu i który osiąga dobre wyniki. Istnieje duże prawdopodobieństwo, że sam wprowadzisz nowe błędy, zwłaszcza że wydaje się, że jest to system, którego nie znasz.
Jeśli nadal chcesz zejść tą drogą, proponuję następujące:
W tym momencie zdecydujesz, czy warto to zbadać. Jeśli kultura Twojej firmy nie nagradza porażki, zdobądź zielone światło od wyższej osoby lub od menedżera.
Myślę, że to dość dobra mapa drogowa i zabierze Cię tam, gdzie potrzebujesz. Bez znajomości specyfiki tego projektu trudno ci bardzo pomóc. Proszę nie odrzucać mojego wyłączenia odpowiedzialności jako nadmiernie alarmującego. Mnóstwo doskonałych programistów pobiło proch, próbując przepisać istniejący projekt na swój ulubiony język lub używając „nowoczesnych” narzędzi. Jest to decyzja, którą należy dokładnie przemyśleć i wzywam was, abyście nie oszukali się i nie zrobili tego samodzielnie bez wsparcia kierownictwa lub pomocy ze strony swoich kolegów.
źródło
Jeśli wolisz język wyższego poziomu, istnieje kilka języków, takich jak C ++ lub Objective-C, które można łatwo mieszać z kodem C.
Alternatywnie, C i C ++ są w miarę kompatybilne. Być może będziesz w stanie skompilować całą bazę kodu jako C ++ z kilkoma zmianami - będziesz mieć od czasu do czasu zmienną o nazwie „klasa” lub „szablon”, której nazwę musisz zmienić, ale w praktyce to wszystko. (sizeof („a”) jest inny w C i C ++, ale nie sądzę, żebym kiedykolwiek tego używał).
Jeśli pójdziesz tą drogą, weź pod uwagę, że następny opiekun może nie być zbyt biegły w C ++. Nie daj się ponieść emocjom. Skorzystaj z C ++, ale tylko do tego stopnia, że programista C może go łatwo zrozumieć.
źródło
malloc
) są uważane za złą praktykę w C. Znaczenieconst
iinline
jest również bardzo różne między C i C ++, i oczywiście C ++ nie rozumie__restrict
. Nie traktuj języków jako wymiennych, nawet w podzbiorze źródeł, które kompilują się w obu.Zasadniczo pisanie dobrego kodu C jest tak samo jak pisanie dobrego kodu C ++ lub Java: Chcesz mieć klasę, użyj
struct
. Chcesz dziedziczenia, dołącz bazęstruct
jako pierwszy bezimienny członek. Chcesz funkcji wirtualnych, dodaj wskaźnik do statycznegostruct
wskaźnika funkcji. I tak dalej itd. To jest dokładnie to, co C ++ robi pod maską, jedyną różnicą jest to, że jest to jawne w C. W ten sposób możesz robić doskonale zorientowane obiektowo programowanie w C, wygląda to po prostu nieco inaczej i bardziej kocio niż na to, co robisz są używane do.Chodzi o to, że dobre programowanie dotyczy paradygmatów, a nie funkcji językowych. To prawda, że zawsze dobrze jest, jeśli funkcje językowe zapewniają dobre wsparcie dla paradygmatów, których chcesz użyć, ale funkcje językowe nie są wymagane. Kiedy sobie to uświadomisz, możesz napisać dobry kod w prawie dowolnym języku (poza niektórymi językami ezoterycznymi, takimi jak pieprzenie mózgu lub INTERCAL).
Oczywiście pozostaje problem, że standardowa biblioteka C nie zawiera żadnej z tych fajnych klas kontenerów, do których jesteś przyzwyczajony. Niestety oznacza to, że będziesz musiał albo użyć własnego, albo obejść ten brak, korzystając z dynamicznie przydzielanych tablic. Ale założę się, że wkrótce się przekonasz, że wszystko, czego naprawdę potrzebujesz, to dynamiczne tablice (
malloc()
) i powiązane listy / drzewa, które są implementowane za pośrednictwem elementów wskaźnika w twoich klasach.źródło