Praca w C++? czemu programiści nie lubią C++?

0

Myślę, że gdyby ktoś chciał zrobić te systemy w C++ to na debugowaniu straciłby tyle czasu i pieniędzy, że klient, czyli w tym przypadku rząd, by się 10x zmienił i wybrał inne rozwiązanie.

Co do zapotrzebowania na pamięć to myślę że Java jest kilka poziomów wyżej - widziałem już systemy dławiące się na 32 GB RAM.

Ciekawostka mi się przypomniała. Niedawno w firmie mieliśmy spotkanie z gościem szukającym programistów chcących programować w Q i Kdb+. Ich aplikacja wymagała trzech terabajtów RAMu do działania (tak, to nie pomyłka) na jednej maszynie, bo w RAMie trzymali dużą część bazy.

2
Wibowit napisał(a):

Myślę, że gdyby ktoś chciał zrobić te systemy w C++ to na debugowaniu straciłby tyle czasu i pieniędzy, że klient, czyli w tym przypadku rząd, by się 10x zmienił i wybrał inne rozwiązanie.

Mylisz się :). Gdybym dostał do napisania te systemy to biorąc za to kilkadziesiąt tysięcy złotych czułbym się jak oszust. A rzeczywiste koszty jakie poniosło państwo są wielokrotnie wyższe. Dlaczego? E-deklaracje to kpina. Wykorzystano adobe air, które nie ma wsparcia już dla linuksów. Zrobiono to tylko po to, żeby stworzyć system do wysyłania deklaracji podatkowych. I może nic bym nie mówił, gdyby nie to, że dało się to zrobić prostą stroną www. Co mamy w e-deklaracjach? NIE, to nie czary mary zaawansowane! To tylko system, który pozwala wybrać formularz, wypełnić go w acrobacie (nie ma kreatora, pojawia się taki sam formularz jak papierowy do ręcznego wypełniania, bez żadnych innych dodatków), a następnie wysłać go do urzędu. TAK, podatnicy musieli zapłacić za takie coś kupe kasy. Twierdzisz, że w C++ to byłoby drogie? Nie żartuj :). Zrobienie formularzy do wypełniania, wczytywanych np. z plików XML i wysyłanych w XMLu to nie jest poziom C++. Tutaj wystarczyłby C, albo Pascal :), a o html i js to w ogóle nie wspomnę, bo to mniej więcej ten poziom.

Klient JPK to jeszcze większa kpina i jeszcze głupszy pomysł. Ta aplikacja ma w sobie konwerter plików csv do xml! TAK! Państwo wydało kasę na konwerter czegoś, co mogłoby być skonwertowane po stronie serwera! Tak naprawdę wystarczyłaby prosta bramka internetowa, gdzie dajesz csv lub xml, potem wysyłasz/potwierdzasz, odbierasz akceptacje mailowo. A tu mamy szumnie, dumnie zrobioną aplikację, w której nie opisano prawidłowo błędów i ostrzeżeń w sposób czytelny.

Program płatnik to w głowie się nie mieści! Tutaj afera to dopiero była jak wydaliśmy kasę na program, którego kodu nie udostępniono a specyfikacja interfejsu była zastrzeżona i trzeba było lat i sądów aby wygrać prawo dostępu do dokumentacji. I co z tego, że nie pisano tego w javie, jak w kraju ktoś zadbał o wsparcie dla MS'a.

Platforma ZUSu to kolejny przykład kpiny i niedopracowania, mimo że to nie C++. Tam zrobiono stronę internetową. I co z tego, że już lata wiadomo, że flash idzie w odstawkę, a tam nikomu to nie przeszkadzało. Strona, która pozwala na wypełnianie formularzy została tak mądrze zrobiona, że potrzebuje HTML, JS i FLASH to poprawnego działania.

W kraju powstaje mnóstwo oprogramowania. Każdy nowy program ma pisaną specyfikację tak, żeby w przyszłości można było go rozwijać na wszystkie inne dziedziny życia urzędniczego. A potem jak przychodzi co do czego, to nowy program, który powstaje ma się nijak do poprzedniego i ma całkiem nową specyfikację. Dlatego w kraju powstaje taki syf, że szkoda gadać, bo wszystko zaczynają a niczego nie kończą.

Inny przykład to webowe rozwiązania. Znany portal aukcyjny i jego "WebAPI". Wystaw tam aukcje bez "wewnętrznego błędu". Powodzenia. Musiałem zmienić limity powtórnych prób z 5 na 10, bo okazało się, że 5x pod rząd potrafiło wywalić internal error.

Następny to Java. Chciałem w javie napisać aplikację wykorzystującą Google Maps. Padło na Jave z wbudowanym okienkiem przeglądarki. I co? I zrezygnowałem z tego, bo jakość tej "przeglądarki" była porażką. Całość siadała po 3-5s pracy. Dałem sobie spokój. Napisałem całość w html+js, bo to mi wystarczyło :).

Wniosek z powyższego? Prosty! Nie ważne język! Liczy się programista. Możesz pisać w Javie, ale jak nie ma pojęcia o tym co robisz, to nie robisz nic dobrego.

1
vpiotr napisał(a):

W C++ można zrobić łatwiej bugi wynikające z nieznajomości języka, chociaż jak wspomniano wyżej, kody w nowszych standardach są bardziej niezawodne. C++ to nie jest język dla kogoś po bootcampie kto miał być politologiem, ale mu nie wyszło i postanowił kosić kasę w korpo. Aby programować w C++ trzeba wiedzieć co się robi, albo codziennie będziesz generował kolejne bugi. Mało którego pracodawcę na to stać.

Zarówno na studiach, jak i na większości bootcampów (ale nie wszystkich) nauczają złych praktyk w C++.
Już lepiej zainwestować w jakieś dobre kursy udemy, jak np.
https://www.udemy.com/beg-modern-cpp/
https://www.udemy.com/modern-cpp-concurrency-in-depth/

W komentarzach tych kursów można znaleźć wypowiedzi studentów, którzy sobie chwalą te kursy... a co niektórzy krytykują swoje studia ;D więc nie tylko w Polsce jest tak źle na studiach informatycznych.

0

A mógłby wypowiedzieć się ktoś kto pracował w 2 branżach i podzieli się swoimi doświadczeniami z pracy? czyli w C++ i webie. @zarazek
Jak z komfortem i warunkami pracy w tych technologiach. W Polsce zarobki są wyższe w webie, ale już zagranicą są porównywalne.

0
Wibowit napisał(a):

Wektory funkcyjne to osobny temat, który w C++ oczywiście jest do zrealizowania.
Ivan Cukic w "Functional Programming in C++" opisuje jak to zrobić (drzewo wektorów) - patrz niżej.

Wielokrotnie wspominałem o wielowątkowości. Czy te struktury można używać z wielu wątków jednocześnie? Trwałe struktury danych, których nie można używać wielowątkowo są dość mało atrakcyjne.

Nie implementowałem tych struktur, ale hasła które wymienia autor tej książki wskazują na to, że nie ma przeciwwskazań żeby używać jej w aplikacji wielowątkowej:

  • Immutable vector-like data structure
  • Copy-on-write (COW)

Przy czym jest to rozwiązanie wydajne, ponieważ nie kopiuje całości struktury w trakcie modyfikacji, a tylko jej małą część.

0

Copy-on-write (COW)

COW kojarzy mi się z CopyOnWriteArrayList z Javy. To rozwiązanie (tzn COWAL) w zdecydowanej większości przypadków jest mocno niewydajne. Nadaje się tylko wtedy, gdy ilość modyfikacji listy jest bardzo mała w porównaniu do operacji, które jej nie modyfikują.

Przy czym jest to rozwiązanie wydajne, ponieważ nie kopiuje całości struktury w trakcie modyfikacji, a tylko jej małą część.

No ale teraz pytanie w jaki sposób się wątki synchronizują jeśli używamy sprytnych wskaźników do automatycznej dealokacji?

0
Wibowit napisał(a):

Chyba jedyną trudnością tego języka jest nauczenie się wskaźników i zarządzania pamięcią

Nauczenie się wskaźników to względnie prosta sprawa, ale bolesne jest kopanie się z losowymi segfaultami i dziwacznym zachowaniem programu, gdy pomylisz się w obsłudze wskaźników. Po co tracić życie na coś takiego zamiast implementować jakiś fajny ficzer? Nie każdy odczuwa przyjemność z obcowania ze wskaźnikami.

Żonglerka wskaźnikami to bułka z masłem w C. W C++ to makabra, pot, łzy i rzucanie jednostką centralną po openspace ze względu na dziwaczne monolityczne twory tego języka połączone z "pięknymi abstrakcjami obiektowymi" z których każda wykorzystuje swój wybrany podzbiór elementów C++. Często sadząc przy tym sążnistymi zorientowanymi obiektowo drabiniastymi błędami propagującymi się na lewo i prawo tylko przy określonej fazie księżyca albo akurat gdy twoja dziewczyna ma okres.

1

Dużo onanizmu technologicznego w tym wątku. A kiedy ktoś z was ostatnio tego używał/potrzebował? Dla mnie sprawa wygląda tak:
W C++ są 2 rodzaje projektów:

  • embedded: tutaj nawet bardziej niż z projektem jako takim walczy się z narzędziami, sprzętem, środowiskiem.
  • legacy: góra sphagetti wytwarzana przez ostatnie 25 lat, ciała twoich poprzedników robią za klopsiki.

Może być też embedded-legacy :)

Zalety dą takie: brak cargo-cult praktyk, wzorców, architektur i testów do testów, wystarczy że działa i wszyscy się cieszą. Mało kto chce tego dotykać, więc masz job security. No i program najczęściej coś robi, a nie tylko wkłada i wyjmuje z bazy danych.

Java: Znacznie przyjemniejsze środowisko pracy (Idea vs vim/emacs). Mnóstwo cargo-cult praktyk i ideologii (nawet nie przypuszczałem, ile ideologii można dołożyć do wkładania i wyjmowania z bazy). Dużo niepotrzebnej komplikacji. W wyniku tego pisze się mnóstwo niepotrzebnego, powtarzalnego kodu. Żartowałem niedawno, że z programowaniem w Javie jest jak z robieniem na drutach: kiedy się człowiek wprawi, to ręce chodzą same, można równocześnie rozmawiać albo oglądać film. Tutaj też: przy odrobinie wprawy ręce po klawiaturze chodzą, testy się piszą, a ty w tym czasie możesz rozmawiać o polityce albo piłce nożnej z kolegami.

Pick your poison.

0

Dużo onanizmu technologicznego w tym wątku. A kiedy ktoś z was ostatnio tego używał/potrzebował?

W Scali praktycznie każdy na bieżąco programuje wielowątkowo z użyciem trwałych struktur danych i zwykle nie przejmuje się takimi rzeczami jak synchronized, atomic, volatile, etc Chciałem się dowiedzieć czy w C++ da się programować w tym samym stylu, ale jak na razie konkretnych przykładów nie było. Napisałem "zwykle", bo jednak sporadycznie gdzieś tam się zrobi mutowalny stan widoczny z wielu wątków.

0
Wibowit napisał(a):

Przy czym jest to rozwiązanie wydajne, ponieważ nie kopiuje całości struktury w trakcie modyfikacji, a tylko jej małą część.

No ale teraz pytanie w jaki sposób się wątki synchronizują jeśli używamy sprytnych wskaźników do automatycznej dealokacji?

To dobre pytanie. Rozwiązaniem jest std::atomic(std::shared_ptr) który będzie dostępny "już od" C++20:
http://en.cppreference.com/w/cpp/memory/shared_ptr/atomic2

Tu trochę więcej o tym: http://www.modernescpp.com/index.php/atomic-smart-pointers

4

@Wibowit:
Można zaimplementować w C++ persistent data structures, tylko nie sądzę żeby ktoś tego w praktyce używał. Problem polega na tym, że PDS de facto wymagają użycia gc, dla którego wsparcie w C++ jest bardzo szczątkowe (więc trzeba by używać zewnętrzego gc/pisać własne gc).
Inne (jedyne?) rozwiązanie to reference counting via std::shared_ptr/std::weak_ptr. Tutaj z kolei problemem będzie koszt operacji atomowych. Jeśli chcesz poczytać, o tym jak można pisać taki kod w C++ to znajdziesz kilka artów w tym temacie na blogu Bartosza Milewskiego (tylko podkreślam to jest bardziej ciekawostka niż coś czego warto używać w C++):

W "produkcyjnym" kodzie pisanym w C++ używa się raczej concurent/(lock/wait-free) struktur. Rzuć okiem dla przykładu na Intel Thread Building Blocks.

Ze swojej strony dodam, że w silnikach gier obecnie używa się głównie fibers zamiast threadów. Poza tym, że minimalizuje to narzut związany z context switchingiem, to przy tym właściwie całkowicie odpada konieczność synchronizacji, bo mamy pełną kontrolę nad tym kiedy dany fiber zwróci sterowanie/zostanie wznowiony. Ponownie, jeśli chciałbyś dowiedzieć się więcej w tym temacie to odsyłam do bardzo dobrej prezentacji Christiana Gyrlinga z Naughty Dog (to ci od The Last of Us, czy serii Uncharted): http://www.gdcvault.com/play/1022186/Parallelizing-the-Naughty-Dog-Engine

Komentarzy o tym, że "weak_ptr nie są przeznaczone do powszechnego użycia", "odśmiecanie pamięci przez gc jest znacznie wygodniejsze i kompletne", czy też to, że "nadchodzące gc o niskich opóźnieniach" deklarują, że pauzy nie będą dłuższe niż 10ms(!) nie będę nawet komentować ;>

1
satirev napisał(a):

@Wibowit:
Można zaimplementować w C++ persistent data structures, tylko nie sądzę żeby ktoś tego w praktyce używał. Problem polega na tym, że PDS de facto wymagają użycia gc

Dzięki za potwierdzenie moich przypuszczeń :) Poza tym PDS są podstawą wydajnego programowania funkcyjnego. COW ma kiepską wydajność w większości zastosowań. Ja na przykład nie przypominam sobie, by ktoś używał klasy CopyOnWriteArrayList w Javce (mimo iż ta struktura nawet nie jest jeszcze funkcyjna).

o tym jak można pisać taki kod w C++ to znajdziesz kilka artów w tym temacie na blogu Bartosza Milewskiego (tylko podkreślam to jest bardziej ciekawostka niż coś czego warto używać w C++):

Dzięki za linki! Nie przeczytałem jeszcze do końca, ale już znalazłem ciekawe fragmenty:

A little digression about memory management is in order. Allocating Items from a garbage-collected heap would likely be more efficient, because then persistent objects would really require zero synchronization, especially if we had separate per-processor heaps. It’s been known for some time that the tradeoff between automated garbage collection (GC) and reference counting (RC) is far from obvious. David Bacon et. al. showed that, rather than there being one most efficient approach, there is a whole spectrum of solutions between GC and RC, each with their own performance tradeoffs.

There is a popular belief that GC always leads to long unexpected pauses in the execution of the program. This used to be true in the old times, but now we have incremental concurrent garbage collectors that either never “stop the world” or stop it for short bounded periods of time (just do the internet search for “parallel incremental garbage collection”). On the other hand, manual memory management a la C++ has latency problems of its own. Data structures that use bulk allocation, like vectors, have to occasionally double their size and copy all elements. In a multithreaded environment, this not only blocks the current thread from making progress but, if the vector is shared, may block other threads as well.

The use of shared_ptr in the implementation of containers may also result in arbitrarily long and quite unpredictable slowdowns. A destruction of a single shared_ptr might occasionally lead to a cascade of dereferences that deallocate large portions of a data structure, which may in turn trigger a bout of free list compactions within the heap (this is more evident in tree-like, branching, data structures). It’s important to keep these facts in mind when talking about performance tradeoffs, and use actual timings in choosing implementations.

.

Komentarzy o tym, że "weak_ptr nie są przeznaczone do powszechnego użycia", "odśmiecanie pamięci przez gc jest znacznie wygodniejsze i kompletne", czy też to, że "nadchodzące gc o niskich opóźnieniach" deklarują, że pauzy nie będą dłuższe niż 10ms(!) nie będę nawet komentować ;>

ZGC jest w planach do wydania razem z Javą 11 jeszcze w tym roku!!! http://openjdk.java.net/projects/jdk/11/
JEP do ZGC jest tutaj: http://openjdk.java.net/jeps/333
Zawiera takie dane:

Performance
Regular performance measurements have been done using SPECjbb® 2015 [1]. Performance is looking good, both from a throughput and latency point of view. Below are typical benchmark scores (in percent, normalized against ZGC's max-jOPS), comparing ZGC and G1, in composite mode using a 128G heap.

(Higher is better)

ZGC
       max-jOPS: 100%
  critical-jOPS: 76.1%

G1
       max-jOPS: 91.2%
  critical-jOPS: 54.7%

Below are typical GC pause times from the same benchmark. ZGC manages to stay well below the 10ms goal. Note that exact numbers can vary (both up and down, but not significantly) depending on the exact machine and setup used.

(Lower is better)

ZGC
                avg: 1.091ms (+/-0.215ms)
    95th percentile: 1.380ms
    99th percentile: 1.512ms
  99.9th percentile: 1.663ms
 99.99th percentile: 1.681ms
                max: 1.681ms

G1
                avg: 156.806ms (+/-71.126ms)
    95th percentile: 316.672ms
    99th percentile: 428.095ms
  99.9th percentile: 543.846ms
 99.99th percentile: 543.846ms
                max: 543.846ms

Maksymalna pauza 1.7ms dla sterty o rozmiarze 128 GiB to chyba akceptowalna wartość, czyż nie? To jest standardowy biznesowy benchmark (SPECjbb® 2015), ale w szeregu innych zastosowań ZGC też powinien działać równie sprawnie.

0

Zwróć uwagę że Bartosz Milewski pisał o FP w kontekście C++ jakiś czas temu (2013).
Teraz raczej siedzi w Haskell-u. Przypadek? Nie sądzę ;-)

0

Pewnie dał sobie spokój z żonglowaniem (niepełno?) sprytnymi wskaźnikami. Haskell ma tracing GC i można programować funkcyjnie jak normalny człowiek.

1 użytkowników online, w tym zalogowanych: 0, gości: 1