Serwer komunikatora. Wskazówki i ocena kodu.

Serwer komunikatora. Wskazówki i ocena kodu.
xeo545x39
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Kosmos
  • Postów:1571
0

Witam. Na wstępie chcę powiedzieć, że głównie chodzi mi o styl pisania takiej aplikacji i chciałbym usłyszeć główne zarzuty co do dotychczasowego kodu, aczkolwiek drobniejsze jakieś usterki, dziwactwa proszę również uwzględnić. Uprzedzam też o tym, że nie musisz tego sprawdzać jak ci się nie chcę, szukam kogoś kto miałby wolną chwilkę, bo dla Was ekspertów to 5 min, przeczytać ten opis, spojrzeć na kod i ocenić jego "poprawność".

No to do rzeczy. Od jakiegoś miesiąca zacząłem pisać komunikator (na razie serwer, na klienta przyjdzie czas oczywiście). Nie mogłem wymyślić nic innego, więc postanowiłem właśnie komunikator, dobre ćwiczenie na wielowątkowość, komunikacja sieciowa, bazy danych i przeróżne inności. Jestem na takim etapie, że przydałoby się przemyśleć jak takie działanie serwera ma wyglądać, żeby było szybko, z możliwością ciągłego rozwijania i ładny kod. Na razie wygląda to tak:

  • główny wątek - inicjalizacja, łączenie z bazą, itd.
  • wątek nasłuchiwania - nasłuchuje, jak jest nowy klient to go obsługuje: przyłącza tymczasowo; odbiera żądanie; wykonuje żądanie lub nie
  • wątek "pracy" - na razie tylko przelatuje wszystkich klientów online (tych przyłączonych do listy) i odbiera od nich żądania
  • lista klientów - przechowuje klientów online
  • klasa Account - odpowiedzialna za tworzenie kont, sprawdzanie itd.
  • klasa Utils - logi, obsługa bazy i inne
  • statyczna klasa Cmd - zawiera komendy swoje i klienta

Prócz tego zasada działania metod z różnych klas jest taka, że każda metoda zwraca mój enumError. Jest kilka stanów, w zależności od metody np. ta od tworzenia konta zwraca: ServerError (to w sumie każda zwraca, bo zawsze jakieś ryzyko błędu innego jest), AccountExists (nie można stworzyć II konta o takim samym loginie, [błąd bazy]), NoError (też prawie każda zwraca, gdy wszystko ok, czyli konto utworzone). Przy wywołaniu takiej metody mam switch'a i w zależności od wyniku wykonuje różne operacje.

Tyle opisu. Załączam w całości kod. Wiem, że opis duży, kodu w sumie nie wiele ~560 linii odjąć jak wiadomo usingi i wolne linie dla czytelnego kodu. Jeżeli ktoś na prawdę by miał czas popatrzeć na to, nie mówię już o dogłębnej analizie, tylko spojrzeć czy dobrze myślę i czy w pracy by mnie za taki kod nie wywalili :)

Miałem wrzucić do "Oceny i recenzje", ale chyba się nie nadaje, bo to nie gotowy projekt, jak to można nazwać. Ogólnie to pierwsza rzecz, którą chcę bardzo porządnie napisać i zapamiętać sobie czy nawet wejść w nawyk pisania dobrego takiej np. aplikacji. Wiem, że sposobów jest setka, ale każde są do siebie w jakiś sposób podobne. Proszę więc o pomoc i cenne wskazówki szanowni koledzy :) I tak na koniec, niech każdy powie ile facepalm'ów zaliczył czytając kod :D Na prawdę, możecie się śmiać, jak zaczynałem miałem tylko mniej-więcej pomysł jak napisać ogólnie, ale żeby tak fachowo i poprawnie to nie, bo nie wiem jak to się robi, właśnie piszę, żeby się dowiedzieć. Acha, no i kod jest otulony niezbędnymi komentarzami.

-- Kod --
http://xeosite.yoyo.pl/Download/XMServer.zip

Kurczę, dlaczego nie można zrobić drzewka z punktatorów? Jak dam niżej to jaja są totalne, a jak dam samo "-", to jest pusta linia przed właściwym punktem..


Co kurła debuguj ten kod i streszczaj się klientowi chce się fixa, a jak nie kurła to odpale visuala i ci pomoge a tego byś nie chciał
edytowany 3x, ostatnio: xeo545x39
xeo545x39
I raz dodania: błąd cookies; II raz: przekroczony czas, mimo to dodało się.
RE
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:11 miesięcy
1

Szczerze mówiąc? Dość przeciętnie. Słabe wykorzystanie .NET Frameworka (implementowanie własnego wyszukiwania na liście chociażby), o tym, że można tworzyć własne wyjątki w ogóle zapomniałeś. Niektórzy używają ich aż nadto (nie służą one do kontrolowania przepływu programu), ale jeden enum z błędami na cały program brzmi równie niedorzecznie. Brak dokumentacji, brak testów. Przedpotopowy sposób korzystania z baz danych (jedna funkcja w jakiejś ogólnej klasie pomocniczej?). Zaimplementowanie IEnumerable<T> nie służy po to, żeby ręcznie pobierać enumerator, tylko przejechać foreachem. Thread.Sleep(50); w przetwarzaniu asynchronicznym w języku wysokopoziomowym też średnio mi pasuje.

xeo545x39
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Kosmos
  • Postów:1571
0

"Brak dokumentacji, brak testów" - wydaje mi się, że na tym etapie mi to nie potrzebne, testować testuję, jak możliwie najdokładniej wszystkie funkcje. Bardzo dobrze, że dość przeciętnie nie oczekiwałem ocen nie wiadomo jakich. Zdaję sobie sprawę, że kod nie jest dobry, bo jak wspomniałem, uczę się jak każdy, wiadomo nikt od razu kodu zajebistego nie napisał. Co do sposobu korzystania z bazy, jak mam go rozszerzyć? W sensie takim, że jeszcze oddzielna klasa i tam metody typu: SelectRow, CreateTable itd.? A jak inaczej z IEnumerable zrobić, by mieć dostęp do wszystkich elementów w liście, która jest z kolei w mojej klasie, z zewnątrz? To miałem na myśli. No i ostatni Thread.Sleep(50);, dałem dlatego, bo podczas ciągłego debugowania, jakby tak te pętle napierd**** to niezbyt by se podebugował :) Ale w sumie i tak po co akurat takie małemu serwerowi napierdzielanie tak co chwila? Dziękuję ci za odpowiedź, tylko żebyś jeszcze mi na tego posta odpowiedział. Liczę też dalej na innych :)

EDIT: Co do IEnumerable...aaa chodzi ci o ten w 'work' threadzie? Tak, racja, lepiej użyć foreacha, ale wtedy nie mam możliwości usunięcia z listy klienta, który chce się odłączyć. Miałem plan dodawać do kolejnej listy usunięte klienty i przed następną pętlą wyrzucić z listy właśnie te, ale wydało mi się lepszy rozwiązaniem zadeklarować iterator.


Co kurła debuguj ten kod i streszczaj się klientowi chce się fixa, a jak nie kurła to odpale visuala i ci pomoge a tego byś nie chciał
edytowany 2x, ostatnio: xeo545x39
RE
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:11 miesięcy
1

Dokumentację na poziomie kodu lepiej pisać razem z nim (masz dokumentację xml w komentarzach). Mam nadzieję, że wiesz, że testowanie funkcji / klas to nie jest stworzenie jej instancji w main, wywołanie dwóch metod, skompilowanie i wywalenie kodu. Pisz testy jednostkowe, które będziesz okresowo uruchamiał. TDD w ogóle polega na tym, żeby najpierw napisać testy, a później kod. Czym projekt robi się większy, tym więcej zależności pomiędzy poszczególnymi komponentami, testowanie robi się trudniejsze. Stosuj interfejsy, spójrz na zagadnienia takie jak depedency injection, mockup objects. Z dobrymi testami nie będziesz musiał wstawiać jakiś sztucznych Thread.Sleep.
Nie musisz pisać własnego ORM, ale tworzenie zapytań przez StringBuilder to zły pomysł. Spójrz na dostępne rozwiązania.

A jak inaczej z IEnumerable zrobić, by mieć dostęp do wszystkich elementów w liście, która jest z kolei w mojej klasie, z zewnątrz?

foreach

xeo545x39
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Kosmos
  • Postów:1571
0

Ok. To co proponowałbyś zamiast zwracania przez metody enumów? Wyjątki będą lepszym rozwiązaniem? Wtedy switch'e odpadną, ale dojdą try...catch.


Co kurła debuguj ten kod i streszczaj się klientowi chce się fixa, a jak nie kurła to odpale visuala i ci pomoge a tego byś nie chciał
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 godziny
1

Całe to ClientList jest kompletnie niepotrzebne, lepiej dać Dictionary<string,Client> albo Hashmap.

Zawsze gdy piszesz tego typu kod

Kopiuj
        public void Add(Client client)
        {
            clients.Add(client);
        }
        public void Remove(Client client)
        {
            clients.Remove(client);
        }

powinna ci się zaświecić czerwona lampka, że tworzysz WTF.

Ten sam efekt uzyskasz dziedzicząc po List<Client> i dodając jedną funkcję:

Kopiuj
    class ClientList : List<Client>
    {
        public Client this[string login]
        {
            // return client if there exists a client with that login
            // else return null
            get
            {
                foreach (Client client in this)
                    if (client.Login == login)
                        return client;
                return null;
            }
        }
    }

ale, jak już powiedziałem, lepiej używać gotowych kontenerów.

xeo545x39
Ależ ja głupi (!) 2 miechy temu właśnie przeciążałem listę w taki sposób... Ale słownik lub hashmapa będzie lepsza, thx.
xeo545x39
Dobra, przerobione na Dictionary, ale co dalej z foreachem? Nie mogę go użyć, bo modyfikuje elementy, a sam for i client[i] chamsko wygląda, czyż nie? Może tak zostawić? EDIT: Wait, jeszcze inaczej, bo przy forze, podaję key'a a nie index :|
RE
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:11 miesięcy
1
xeo545x39 napisał(a)

Ok. To co proponowałbyś zamiast zwracania przez metody enumów? Wyjątki będą lepszym rozwiązaniem? Wtedy switch'e odpadną, ale dojdą try...catch.

Tak, będą lepszym rozwiązaniem, bo do tego właśnie zostały stworzone. Enumy niosą o wiele mniej informacji o błędzie, możesz gdzieś o sprawdzeniu błędu w ogóle zapomnieć, gdzieś ci umknie, wykonywanie kodu nastąpi dalej i będziesz to debugował kilka godzin.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)