Rozdzielacz - program wspomagający różne zadania organizacyjne

Rozdzielacz - program wspomagający różne zadania organizacyjne
Manna5
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Kraków
  • Postów: 667
3

Przedstawiam mój program uzytkowy pn. Rozdzielacz napisany w C. Stanowi on pewnego rodzaju osobistą malutką bazę danych działającą na zasadzie przydzielania różnych nazwanych elementów między kilka zbiorów zwanych "szufladami". Działa w systemie MS Windows, ale dzięki przenośności języka programowania C może zostać szybko przeniesiony na inne systemy operacyjne lub nawet rekompilowany na nie bez zmian w kodzie C.

Testowałem go, dałem się także nim pobawić siostrze, naprawiłem wykryte błędy w działaniu i mam nadzieję, że to były wszystkie, ale będę wdzięczny za przetestowanie programu. Nie należy go kompilować jako C++, bo raczej się nie skompiluje.

Repozytorium na GitHubie: https://github.com/Jan-Mleczko/Rozdzielacz-app
Główny plik źródłowy to ROZDZIAL.C przy czym potrzeby jest także plik z funkcjami USERIO.C.

screenshot-20250701132927.png

Program może być pomocny zastępując ręczne notatki podczas zadań organizacyjnych sprowadzających się do rozdzielania:

  • przedmiotów na miejsca ich przechowywania albo drogi przewozu,
  • osób na zespoły,
  • zadań do wykonania na osoby,
  • zadań na kilka dni
  • itp.

Zaletą programu jest ładna semigraficzna prezentacja rozważanego podziału oraz możliwosć sprawnego przenoszenia elementów miedzy szufladami. Na papierze w tym celu trzeba by było albo wykreślać elementy z nieodpowiedniej szuflady albo wyciąć karteczki z zapisanym każdym elementem, które mogłyby się zsunąć z kartki.

W aktualnej wersji górna granica ilości szuflad wynosi 12, a elementów da się wprowadzić 99. Nazwa szuflady lub elementu może mieć do 15 znaków.

Ponadto Rozdzielacz uwzględnia samoczynne rozdzielanie elementów pomiędzy szuflady (możliwie) po równo albo pseudolosowo na Twoje żądanie. Później możesz dokonać ręcznych poprawek.

Jest oczywiście dostępny zapis stanu danych na dysku w wewnętrznym formacie programu jak również wytworzenie pliku tekstowego zawierającego opracowane informacje, który to będzie mógł oglądać każdy w dowolnym edytorze tekstu.

Jeszcze lepszą (w niektórych przypadkach) możliwością zewnętrznej prezentacji danych jest zapis jako dokument HTML (do przeglądania w przeglądarce internetowej) w jednym z 7 dostępnych styli:

  • Klasyczny, także w wariantach dostowanych do standardów HTML5 albo XHTML
  • Tabela
  • Upiększony klasyczny
  • Nowoczesny
  • Zielony ogród
  • Energiczny szaro-czerwony
  • Panele

Polskie znaki - jeśli występują w jakichkolwiek wprowadzonych nazwach - są przekodowywane z CP852 na kodowanie Unicode zapewniające ich poprawne wyświetlanie przez prawie każdą przeglądarkę.

Tak wyglądają przykładowe dane zapisane w stylu Zielony ogród:

screenshot-20250701132946.png

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
3

Moja uwaga bardzo prosta. 1300 linii kodu, 0 testów autmatycznych. No i może jeszcze commitowanie binarki do kontroli wersji jest trochę dziwne. Lepiej byłoby napisać skrypt budujący, wrzucić do żeby się odpalił w github actions i dodał jako binarka do release'a.

PS: 🤨 Ten kod jest sformatowany jakby był napisany w Fortranie.

screenshot-20250701140105.png

MI
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 96
2
Riddle napisał(a):

Moja uwaga bardzo prosta. 1300 linii kodu, 0 testów autmatycznych.

Nie dziwi mnie to jakoś, 2500 linii kodu i 0 testów mam w swojej apce, która czeka na review w appstore. Pisanie kodu w chacie to nie enterprise

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
mitowski napisał(a):
Riddle napisał(a):

Moja uwaga bardzo prosta. 1300 linii kodu, 0 testów autmatycznych.

Nie dziwi mnie to jakoś, 2500 linii kodu i 0 testów mam w swojej apce, która czeka na review w appstore. Pisanie kodu w chacie to nie enterprise

Ja piszę test nawet jak robię tool na 10 linijek.

Z testami:

  1. 1 minuta pisania testu
  2. 1 minuta pisania kodu
  3. 1 minuta testowania automatycznego i fixy.

Total time: 3 min

Bez testów

  1. 1 minuta pisania kodu
  2. 4 minut testowania manualnego czy działa.

Total time: 5 min

I ta różnica rośnie wraz z ilością kodu.

PS: Przy okazji, może podzielę się innym źródłem niż moje doświadczenie: https://www.manning.com/books/the-art-of-unit-testing-second-edition

screenshot-20250701145009.png

obscurity
  • Rejestracja: dni
  • Ostatnio: dni
1
Manna5 napisał(a):

W aktualnej wersji górna granica ilości szuflad wynosi 12, a elementów da się wprowadzić 99. Nazwa szuflady lub elementu może mieć do 15 znaków.

a po co takie ograniczenia i czemu takie małe? Musiałeś się zmieścić w 17kB pamięci? Widzę że sam musisz używać kropek zamiast pełnych nazw...
Wydaje się że używanie "sticky notes" w windowsie lub nawet notatniku jest wygodniejsze niż to, żeby przenieść element z jednej "szuflady" do drugiej wystarczy wytnij-wklej, lub można nawet zaznaczyć linię i ją przenieść kursorem. Czy dobrze rozumiem że to jest cała funkcjonalność tego programu?

Pamiętam jak mój tata kiedyś używał do podobnego celu wbudowanego w windows 3.1 programu https://en.wikipedia.org/wiki/Cardfile
Potem nawet przenosił ten program z windows 95 do windows xp, 7 i 8. Nie wiem czy nadal używa na win11 ale miał tam pokaźną kartotekę różnych rzeczy

Manna5
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Kraków
  • Postów: 667
0

Dziękuję za dotychczasowe spostrzeżenia.

Riddle napisał(a):

PS: 🤨 Ten kod jest sformatowany jakby był napisany w Fortranie.

Formatowanie pliku USERIO.C jest mocno nietypowe. Nie widać tego na GitHubie, ale ten zestaw funkcji napisałem ok. 3 lata temu do użycia w różnych programach nie mając jeszcze nawet pomysłu na ten. Akurat wtedy byłem w trakcie próbowania różnych styli formatowania, w tym takich dziwnych i tamten plik taki został.

obscurity napisał(a):
Manna5 napisał(a):

W aktualnej wersji górna granica ilości szuflad wynosi 12, a elementów da się wprowadzić 99. Nazwa szuflady lub elementu może mieć do 15 znaków.

a po co takie ograniczenia i czemu takie małe? Musiałeś się zmieścić w 17kB pamięci? Widzę że sam musisz używać kropek zamiast pełnych nazw...
Wydaje się że używanie "sticky notes" w windowsie lub nawet notatniku jest wygodniejsze niż to, żeby przenieść element z jednej "szuflady" do drugiej wystarczy wytnij-wklej, lub można nawet zaznaczyć linię i ją przenieść kursorem. Czy dobrze rozumiem że to jest cała funkcjonalność tego programu?

Historia tych ograniczeń jest inna niż po prostu mała ilość pamięci. Zacząłem pisać ten program 4 dni temu mając w planie tylko jego podstawową część, bez funkcjonalności z podmenu Inne opcje ani nawet zapisywania. Za szerokość interfejsu przyjąłem tradycyjne 80 znaków, a więc wychodzi 19 znaków na kolumnę chcąc mieć 4 kolumny czymś rozdzielane. Odjąłem jeszcze przestrzeń na wypisanie numerów elementów i wyszła mi sensowna długość równa 15 znaków. Dopiero dodanie eksportu uczyniło przechowywanie pełnych nazw sensownym. 99 elementów też wzięło się z interfejsu użytkownika, żeby ich numery, które są wyświetlane pozostału dwucyfrowe. Do tego format zapisu na dysku będący blisko prostego odbicia struktury danych programu powodowałby wzrost rozmiaru pliku zależnie od możliwej ilości elementów lub szuflad. Uściślając, trzy kropki są dodawane automatycznie w przypadku wpisania czegoś zbyt długiego.

To wszystko jest do poprawy, jednak nie w trywialny sposób, a w najbliższym czasie wyjeżdżam i chciałem zamknąć przed tym jakąś działającą wersję do ew. późniejszego rozwoju. Przygotowałem się na to zaopatrując format pliku w sygnaturę, która pozwoli odróżnić przyszły format od obecnego.

Poza eksportem oraz funkcjonalnościami podziału losowego albo możliwie równego to jest cała funkcjonalność. Rewolucyjna biznesowo ta aplikacja niestety nie jest i zdaję sobie z tego sprawę. Z drugiej strony edytorem tekstu można na siłę zastąpić wiele programów, a ten jest specjalizowany i można go wzbogacić o jeszcze więcej specjalizowanych funkcjonalności.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
obscurity napisał(a):

ale testy automatyczne nie zastępują testowania manualnego, testy manualne to nagroda, fajnie zobaczyć jak coś co pisaliśmy działa. No chyba że to tylko jakieś api to w sumie testy to już cała prezentacja

Jak chcesz, to napisz mi wszystkie swoje obawy i uwagi odn. tego czemu testowanie manualne jest według Ciebie niezbędne, to Ci nagram filmik jak pracuję, w którym będzie się dało zobaczyć jak to zrobić bez manualnego.

SL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1020
0

Polecam spróbować clang-format. Jest to standard jeśli chodzi o C/C++. Do tego można go dowolnie skonfigurować, więc argument a bo nie jest po mojemu odpada. Inne języki często mają ogólne zasady co do formatowania (Java, Python) lub nawet konkretne rozwiązania, których używa każdy (go fmt, rustfmt), więc warto nauczyć się tego skilla

obscurity
  • Rejestracja: dni
  • Ostatnio: dni
0
Manna5 napisał(a):

Za szerokość interfejsu przyjąłem tradycyjne 80 znaków, a więc wychodzi 19 znaków na kolumnę chcąc mieć 4 kolumny czymś rozdzielane. Odjąłem jeszcze przestrzeń na wypisanie numerów elementów i wyszła mi sensowna długość równa 15 znaków.

To trochę kiepskie podejście, rozmiar konsoli można zmieniać i konfigurować. Mógłbyś też zaimplementować przewijanie dłuższych tekstów w komórkach

Riddle napisał(a):

Jak chcesz, to napisz mi wszystkie swoje obawy i uwagi odn. tego czemu testowanie manualne jest według Ciebie niezbędne, to Ci nagram filmik jak pracuję, w którym będzie się dało zobaczyć jak to zrobić bez manualnego.

Nie chodzi mi o to że jest niezbędne tylko że zobaczenie efektu końcowego zwłaszcza w pracy na froncie to często jedyna "nagroda" z pracy. Więc to trochę idealizowane że z testem jest szybciej bo w optymistycznym wypadku bez testu jest szybciej, a w pesymistycznym gdy popełnimy błąd jest oczywiście wolniej, natomiast po napisaniu testu i tak zazwyczaj chce się zobaczyć efekt końcowy i poklikać, a po trzeciej iteracji poprawiania błędów bez testów i tak każdy w końcu napisze test żeby nie testować tego samego w kółko, więc zazwyczaj bez testów jest szybciej lub tylko minimalnie wolniej (max dwie sesje ręcznego testowania).

Ja testy bardziej traktuję bardziej jako taki egzoszkielet wspierający napisany kod żeby mi go ktoś w przyszłości nie popsuł, nie powiedziałbym żeby zrobienie pojedynczego taska było szybsze z testami, zalety widać raczej dopiero na dłuższą metę.

Manna5
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Kraków
  • Postów: 667
1

@Riddle Co do testów automatycznych:

Ten program przy komunikacji z użytkownikiem korzysta tylko ze standardowego wejścia i wyjścia (a nie np. z funkcji z conio.h) poza jednym wyjątkiem jakim jest czyszczenie konsoli, więc zauważyłem możliwość łatwego dokonywania testów automatycznych za pomocą przekierowań. Nawet przed opublikowaniem tej wersji tak naprawdę wykonałem półautomatyczny test polegający na dobiciu do ograniczeń ilości szuflad i elementów za pomocą opcji Wklej wiersza poleceń Windows, ponieważ był to ważny test, a czasochłonny przy ręcznym wykonaniu.

Dzisiaj rozpocząłem tworzenie procedury testowania automatycznego, bo sprowadzającego się do wywołania jednego programu wsadowego. Piszę "rozpocząłem", ponieważ na razie przygotowałem niewiele przypadków testowych. Przypadek składa sie z pliku Tnnnn.IN zawierajacego jednym ciągiem jakiś scenariusz odpowiedzi użytkownika pisany ręcznie (ale tylko raz) oraz pliku Tnnnn.OUT z oczekiwanymi danymi wypisanymi przez program. Ten drugi plik już w przypadku prostego testu reakcji na nieprawidłowe opcje ma 8 KB i na razie jest generowany przez testowany program, więc nie może zostać automatycznie wykryty żaden błąd, ale to się zmieni, gdy zacznę tworzyć ulepszoną wersję 1.1. Wtedy zmienię w plikach oczekiwanego wyjścia tylko to, co świadomie zmieniam w działaniu programu, a niezamierzone działania będą szybko wykrywane.

Dzięki temu nie muszę restrukturyzować kodu pod testy automatyczne. Jedyna zmiana w kodzie to dodanie trybu kompilacji do testów automatycznych, w którym zamiast czyszczenia konsoli wyprowadzany jest znak Form Feed, aby akt wyczyszczenia konsoli także był uwzględniony w testach (i żeby nie czyściło mi konsoli podczas testowania). Zablokowane jest także samoczynne uruchamianie Notatnika lub przeglądarki po eksporcie i to tyle.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
1
Manna5 napisał(a):

Ten program przy komunikacji z użytkownikiem korzysta tylko ze standardowego wejścia i wyjścia (a nie np. z funkcji z conio.h) poza jednym wyjątkiem jakim jest czyszczenie konsoli, więc zauważyłem możliwość łatwego dokonywania testów automatycznych za pomocą przekierowań. Nawet przed opublikowaniem tej wersji tak naprawdę wykonałem półautomatyczny test polegający na dobiciu do ograniczeń ilości szuflad i elementów za pomocą opcji Wklej wiersza poleceń Windows, ponieważ był to ważny test, a czasochłonny przy ręcznym wykonaniu.

To może mógłbyś go dodać do kontroli wersji, tak żeby dało się to włączyć jednym poleceniem, bez ręcznego klikania "Wklej"? 🤔

Manna5 napisał(a):

Dzisiaj rozpocząłem tworzenie procedury testowania automatycznego, bo sprowadzającego się do wywołania jednego programu wsadowego. Piszę "rozpocząłem", ponieważ na razie przygotowałem niewiele przypadków testowych. Przypadek składa sie z pliku Tnnnn.IN zawierajacego jednym ciągiem jakiś scenariusz odpowiedzi użytkownika pisany ręcznie (ale tylko raz) oraz pliku Tnnnn.OUT z oczekiwanymi danymi wypisanymi przez program. Ten drugi plik już w przypadku prostego testu reakcji na nieprawidłowe opcje ma 8 KB i na razie jest generowany przez testowany program, więc nie może zostać automatycznie wykryty żaden błąd, ale to się zmieni, gdy zacznę tworzyć ulepszoną wersję 1.1. Wtedy zmienię w plikach oczekiwanego wyjścia tylko to, co świadomie zmieniam w działaniu programu, a niezamierzone działania będą szybko wykrywane.

No jest to dobry pomysł. Ja nazwałbm to testem akceptacyjnym, z uwagi na to że wsadzasz cały input i cały output. Jest to moim zdaniem dobry start, chociaż w przyszłości dobrze byłoby dodać testy które są bardziej granularne. Nie koniecznie muszą działać na skompilowanej binarce/pliku wsadowym. Taki test to może być drugi plik C/C++, który includuje Twój kod produkcyjny i woła poszczególne metody. Wtedy uniknąłbyś dużego pliku wejściowego do testów.

Manna5 napisał(a):

Dzięki temu nie muszę restrukturyzować kodu pod testy automatyczne. Jedyna zmiana w kodzie to dodanie trybu kompilacji do testów automatycznych, w którym zamiast czyszczenia konsoli wyprowadzany jest znak Form Feed, aby akt wyczyszczenia konsoli także był uwzględniony w testach (i żeby nie czyściło mi konsoli podczas testowania). Zablokowane jest także samoczynne uruchamianie Notatnika lub przeglądarki po eksporcie i to tyle.

Faktycznie, jest to łatwiejsze do dodania na początek.

Aczkolwiek może warto dodać - ta "zmiana" którą trzeba zrobić pod testy, bardzo często ma pozytywny efekt. Tzn. kod który da się łatwo testować, z reguły jest też po prostu dużo lepiej zaprojektowany (staje się przez to bardziej reużywalny).

KS
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 708
1

Źle używasz assert

Manna5
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Kraków
  • Postów: 667
0
ksh napisał(a):

Źle używasz assert

Tak jak @cerrato napisał w komentarzu, nie wiem, o które asercje chodzi i dlaczego są one złe, a byłbym ciekawy. Starałem się stosować w tym programie asercje jako środek wykrywania błędów i wyłapywać za ich pomocą jak najwięcej niedozwolonych sytuacji (chociaż mógłbym jeszcze więcej niż jest, gdybym poświęcił na to więcej czasu). Wydawało mi się, że rozumiem sens asercji w tym znaczeniu, że służą one sprawdzaniu pewników, które nigdy nie powinny być naruszone, nawet w przypadku np. nieudanego otwarcia plików. To spostrzeżenie mnie zaskoczyło i chętnie dowiedziałbym się, co dokładnie zrobiłem źle z tymi asercjami.

KS
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 708
2

Weźmy sobie ten kawałek

Kopiuj
zajmij (char *tablica) {
	char *poczatek;
	
	poczatek = tablica;
	while (*tablica)
		++tablica;
	assert (*tablica == 0);
	*tablica = TAK;
	return tablica - poczatek;
	}

Po pierwsze. Wchodzimy do * tablicy i badamy w pętli czy jest zero. Następnie przeskakujemy na następną pozycję jak nie zero.
Zamiast przekazać wielkość tablicy to radośnie lecimy do nieskończoności, aż złapiemy zero. wychodzimy i gwarantujemy, że złapaliśmy zero.
Kompletnie bez sensu.

Po drugie char *początek nie ma sensu. Zamiast przekazywać tą zmienną do funkcji powinno się ją tworzyć w funkcji.

Wreszcie ostatnia sprawa, jak powinno się tu użyć assert.
Na samym początku:

Kopiuj
assert( talica != NULL );

Dalej mi się nie chce czytać, na dodatek polskie nazewnictwo, wtf.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.