Wie wird man ein besserer Programmierer?



  • Hallo!

    Ich programmiere jetzt seit ein paar Jahren in C++, manchmal auch in C oder Lua.
    Ich habe als Einstieg das Buch von Breymann gelesen, dann als Steigerung den Stroustroup.
    Anschliessend noch Effective C++, ein bisschen Boost (irgendein einfuehrendes Buch) und momentan lese ich das Buch ueber Designpatterns der GoF.
    Darueberhinaus lese ich hier auch schon eine Weile mit, ich wuerde daher sagen, dass ich die typischen Fallstricke kenne, weiss, dass man keine globalen Variablen nutzen sollte, kein rohes new, immer schoen RAII, kein std::endl usw.

    Wenns aber ans konkrete Programmieren geht, stehe ich immer auf dem Schlauch. Ich will von Anfang an immer alles moeglichst elegant und wartbar schreiben, dabei komme ich aus dem Stadium des Kopfzerbrechens nicht heraus.

    Beispiel:
    Ich habe angefangen, an einem Programm fuer eine Verwaltung von verschiedenen Listen (Packlisten, Einkaufslisten, Todo-Listen usw.) zu schreiben.
    Dazu sollte es ein schoenes, interaktives Menu geben, am besten mit abkuerzbaren Befehlen, aehnlich gdb.
    Folgende Struktur verwende ich momentan:
    Es gibt eine klasse menu , die einen vector von menu_entry (ies) verwaltet. Ein Eintrag des Menues besteht aus einem string fuer den Namen des Befehls, wie print und einen Schluessel, um den Befehls auszufuehren (p). Ausserdem gibt es noch ein Prioritaet und einen Signal-Handler (als std::function), der ausgefuehrt wird, wenn der Eintrag ausgewaehlt wird.

    Menu ist aber auch ein Subjekt eines Observers-Patterns (realisiert ueber boost::signals2), da Befehle an die gesteuerten Elemente weitergegeben werden muessen.

    Ein Observer ist oben erwaehnte Liste, einfach ein Klasse, die eine Liste von Eintraegen (als Templateparameter) verwaltet.
    Ein Listen-Objekt erhaelt dann die eingegeben Befehle vom Menu.

    Hier ein wenig code dazu:

    class menu_entry
    {
    	public:
    		typedef unsigned int priority_type;
    
    		menu_entry();
    		menu_entry(const std::string& content, const std::string& key, menu_entry::priority_type priority = 0, std::function<void(menu&)> action = nullptr);
    
    		bool key_matches(const std::string& key);
    
    		std::string get_content() const { return content; }
    		std::string get_key() const { return key; }
    		menu_entry::priority_type get_priority() const { return priority; }
    
    		void take_action(menu&);
    
    		friend std::ostream& operator<<(std::ostream& stream, const menu_entry& me);
    
    		bool operator<(const menu_entry&) const;
    
    	private:
    		std::string content;
    		std::string key;
    		menu_entry::priority_type priority;
    		std::function<void(menu&)> action;
    };
    
    class menu
    {
    	public:
    
    		typedef boost::signals2::signal<void (const std::string&)> signal_t;
    		typedef signal_t::slot_type slot_t;
    		typedef boost::signals2::connection connection_t;
    
    		menu(const std::string& prompt = std::string()) : _prompt(prompt), _open(true) { }
    		menu(std::initializer_list<menu_entry> l, const std::string& prompt = std::string() ) : _entries(l), _prompt(prompt), _open(true) { check_collisions(); };
    
    		void insert(int index, const menu_entry& entry);
    		void append(const menu_entry& entry);
    
    		void handle_input(const std::string& input);
    
    		std::ostream& print_help(std::ostream&) const;
    
    		std::ostream& print_prompt(std::ostream& stream) const { return stream << _prompt; }
    		void set_prompt(const std::string&);
    
    		void quit();
    
    		operator bool() const;
    
    		connection_t connect(const slot_t& slot);
    
    	private:
    	public:
    		std::vector<menu_entry> check_matches(const std::string& input);
    
    		void check_collisions();
    
    		std::vector<menu_entry> _entries;
    		std::string _prompt;
    		bool _open;
    
    		signal_t _signal;
    };
    

    Ueber

    operator bool()
    

    kann getestet werden, ob das menu geschlossen worden ist, aehnlich wie bei Fensterbibliotheken mit is_open oder so.

    Die Klasse Liste sieht so aus:

    template <typename entry, typename container = std::vector<entry>>
    class list
    {
    	public:
    		// constructors
    
    		list() = default;
    
    		list(menu& m);
    		template <typename It>
    		list(It first, It last, menu& m) ;
    		list(std::initializer_list<entry> l, menu& m);
    
    		virtual ~list(); // deriving was planned
    
    		void load_from_file(const std::string& filename);
    		void save_to_file(const std::string& filename) const;
    
    		void insert(const entry& e, int pos = -1);
    
    		std::ostream& print(std::ostream& out);
    
    		void handle_command(const std::string& command)
    		{
    			if(command == "p")
    			{
    				print(std::cout);
    			}
    			if(command == "a")
    			{
    				entry e;
    				std::cout << "Entry ("<< entry::input_prompt() << ") : ";
    				e.read(std::cin);
    				std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    				insert(e);
    			}
    			if(command == "s")
    			{
    				const std::string filename = "list_content"; // temporarily for testing
    				save_to_file(filename);
    			}
    			if(command == "l")
    			{
    				const std::string filename = "list_content"; // temporarily for testing
    				load_from_file(filename);
    			}
    		}
    
    	private:
    		container _entries;
    
    		menu& _menu;
    		menu::connection_t _connection;
    };
    

    Und die Nutzung des Ganzen sieht folgendermassen aus:

    int main()
    {
    	menu m("command (h) for help: ");
    	m.append({ "print", "p" });
    	m.append({ "add", "a" });
    	m.append({ "load", "l" });
    	m.append({ "save", "s" });
    	m.append({ "help", "h", [] (menu& m) { m.print_help(std::cout); } });
    	m.append({ "quit", "q", [] (menu& m) { m.quit(); } });
    
    	list<packing_entry> l (m);
    
    	while(m)
    	{
    		m.print_prompt(std::cout);
    		std::string choice;
    		std::getline(std::cin, choice);
    
    		if(!std::cin)
    		{
    			break;
    		}
    
    		m.handle_input(choice);
    	}
    }
    

    Packing_entry ist eine Klasse bestehend aus einer Zahl (Anzahl) und einem String (Gegenstand).

    Prinzipiell gefaellt es mir ganz gut, es sind natuerlich ueberall Verbesserungsmoeglichkeiten. Menu sollte aus einer Datei geladen werden koennen, Befehle des Menus muesse Argumente annehmen usw.

    Aber was mir stark misfaellt, ist die relativ enge Kopplung zwischen Menu und List. Wenn ich den Namen eines Befehls wie print aendern moechte, muss ich den an zwei Stellen aendern.
    Auch schlecht ist, dass eine Mehrdeutigkeit der Befehle erst zur Laufzeit getestet wird. Wenn das ueber eine Datei geladen wird, geht es nicht anders, ok. Aber ein Check zur Kompilierzeit waere schoen.

    Meine Frage:
    Wie schafft man es, sich nicht endlos in Details zu versteigen, einfach mal was fertig machen und dabei trotzdem etwas halbwegs lesbares zu produzieren? Und zusaetzlich: Ist der Ansatz, wie ich es mache, eurer Meinung nach in Ordnung, oder wuerdet ihr das ganz anders machen?

    Vielen Dank fuer das Lesen von dich relativ viel Text!



  • Hyde++ schrieb:

    Hallo!

    Ich programmiere jetzt seit ein paar Jahren in C++, manchmal auch in C oder Lua.
    Ich habe als Einstieg das Buch von Breymann gelesen, dann als Steigerung den Stroustroup.
    Anschliessend noch Effective C++, ein bisschen Boost (irgendein einfuehrendes Buch) und momentan lese ich das Buch ueber Designpatterns der GoF.
    Darueberhinaus lese ich hier auch schon eine Weile mit, ich wuerde daher sagen, dass ich die typischen Fallstricke kenne, weiss, dass man keine globalen Variablen nutzen sollte, kein rohes new, immer schoen RAII, kein std::endl usw.

    Wenns aber ans konkrete Programmieren geht, stehe ich immer auf dem Schlauch. Ich will von Anfang an immer alles moeglichst elegant und wartbar schreiben, dabei komme ich aus dem Stadium des Kopfzerbrechens nicht heraus.

    Beispiel:
    Ich habe angefangen, an einem Programm fuer eine Verwaltung von verschiedenen Listen (Packlisten, Einkaufslisten, Todo-Listen usw.) zu schreiben.
    Dazu sollte es ein schoenes, interaktives Menu geben, am besten mit abkuerzbaren Befehlen, aehnlich gdb.
    Folgende Struktur verwende ich momentan:
    Es gibt eine klasse menu , die einen vector von menu_entry (ies) verwaltet. Ein Eintrag des Menues besteht aus einem string fuer den Namen des Befehls, wie print und einen Schluessel, um den Befehls auszufuehren (p). Ausserdem gibt es noch ein Prioritaet und einen Signal-Handler (als std::function), der ausgefuehrt wird, wenn der Eintrag ausgewaehlt wird.

    Menu ist aber auch ein Subjekt eines Observers-Patterns (realisiert ueber boost::signals2), da Befehle an die gesteuerten Elemente weitergegeben werden muessen.

    Ein Observer ist oben erwaehnte Liste, einfach ein Klasse, die eine Liste von Eintraegen (als Templateparameter) verwaltet.
    Ein Listen-Objekt erhaelt dann die eingegeben Befehle vom Menu.

    Hier ein wenig code dazu:

    class menu_entry
    {
    	public:
    		typedef unsigned int priority_type;
    
    		menu_entry();
    		menu_entry(const std::string& content, const std::string& key, menu_entry::priority_type priority = 0, std::function<void(menu&)> action = nullptr);
    
    		bool key_matches(const std::string& key);
    
    		std::string get_content() const { return content; }
    		std::string get_key() const { return key; }
    		menu_entry::priority_type get_priority() const { return priority; }
    
    		void take_action(menu&);
    
    		friend std::ostream& operator<<(std::ostream& stream, const menu_entry& me);
    
    		bool operator<(const menu_entry&) const;
    
    	private:
    		std::string content;
    		std::string key;
    		menu_entry::priority_type priority;
    		std::function<void(menu&)> action;
    };
    
    class menu
    {
    	public:
    
    		typedef boost::signals2::signal<void (const std::string&)> signal_t;
    		typedef signal_t::slot_type slot_t;
    		typedef boost::signals2::connection connection_t;
    
    		menu(const std::string& prompt = std::string()) : _prompt(prompt), _open(true) { }
    		menu(std::initializer_list<menu_entry> l, const std::string& prompt = std::string() ) : _entries(l), _prompt(prompt), _open(true) { check_collisions(); };
    
    		void insert(int index, const menu_entry& entry);
    		void append(const menu_entry& entry);
    
    		void handle_input(const std::string& input);
    
    		std::ostream& print_help(std::ostream&) const;
    
    		std::ostream& print_prompt(std::ostream& stream) const { return stream << _prompt; }
    		void set_prompt(const std::string&);
    
    		void quit();
    
    		operator bool() const;
    
    		connection_t connect(const slot_t& slot);
    
    	private:
    	public:
    		std::vector<menu_entry> check_matches(const std::string& input);
    		
    		void check_collisions();
    
    		std::vector<menu_entry> _entries;
    		std::string _prompt;
    		bool _open;
    
    		signal_t _signal;
    };
    

    Ueber

    operator bool()
    

    kann getestet werden, ob das menu geschlossen worden ist, aehnlich wie bei Fensterbibliotheken mit is_open oder so.

    Die Klasse Liste sieht so aus:

    template <typename entry, typename container = std::vector<entry>>
    class list
    {
    	public:
    		// constructors
    		
    		list() = default;
    
    		list(menu& m);
    		template <typename It>
    		list(It first, It last, menu& m) ;
    		list(std::initializer_list<entry> l, menu& m);
    
    		virtual ~list(); // deriving was planned
    
    		void load_from_file(const std::string& filename);
    		void save_to_file(const std::string& filename) const;
    
    		void insert(const entry& e, int pos = -1);
    
    		std::ostream& print(std::ostream& out);
    
    		void handle_command(const std::string& command)
    		{
    			if(command == "p")
    			{
    				print(std::cout);
    			}
    			if(command == "a")
    			{
    				entry e;
    				std::cout << "Entry ("<< entry::input_prompt() << ") : ";
    				e.read(std::cin);
    				std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    				insert(e);
    			}
    			if(command == "s")
    			{
    				const std::string filename = "list_content"; // temporarily for testing
    				save_to_file(filename);
    			}
    			if(command == "l")
    			{
    				const std::string filename = "list_content"; // temporarily for testing
    				load_from_file(filename);
    			}
    		}
    
    	private:
    		container _entries;
    
    		menu& _menu;
    		menu::connection_t _connection;
    };
    

    Und die Nutzung des Ganzen sieht folgendermassen aus:

    int main()
    {
    	menu m("command (h) for help: ");
    	m.append({ "print", "p" });
    	m.append({ "add", "a" });
    	m.append({ "load", "l" });
    	m.append({ "save", "s" });
    	m.append({ "help", "h", [] (menu& m) { m.print_help(std::cout); } });
    	m.append({ "quit", "q", [] (menu& m) { m.quit(); } });
    
    	list<packing_entry> l (m);
    
    	while(m)
    	{
    		m.print_prompt(std::cout);
    		std::string choice;
    		std::getline(std::cin, choice);
    
    		if(!std::cin)
    		{
    			break;
    		}
    
    		m.handle_input(choice);
    	}
    }
    

    Packing_entry ist eine Klasse bestehend aus einer Zahl (Anzahl) und einem String (Gegenstand).

    Prinzipiell gefaellt es mir ganz gut, es sind natuerlich ueberall Verbesserungsmoeglichkeiten. Menu sollte aus einer Datei geladen werden koennen, Befehle des Menus muesse Argumente annehmen usw.

    Aber was mir stark misfaellt, ist die relativ enge Kopplung zwischen Menu und List. Wenn ich den Namen eines Befehls wie print aendern moechte, muss ich den an zwei Stellen aendern.
    Auch schlecht ist, dass eine Mehrdeutigkeit der Befehle erst zur Laufzeit getestet wird. Wenn das ueber eine Datei geladen wird, geht es nicht anders, ok. Aber ein Check zur Kompilierzeit waere schoen.

    Meine Frage:
    Wie schafft man es, sich nicht endlos in Details zu versteigen, einfach mal was fertig machen und dabei trotzdem etwas halbwegs lesbares zu produzieren? Und zusaetzlich: Ist der Ansatz, wie ich es mache, eurer Meinung nach in Ordnung, oder wuerdet ihr das ganz anders machen?

    Vielen Dank fuer das Lesen von dich relativ viel Text!

    - vll ne blöde frage aber warum kein std::endl?

    - zu deiner frage:
    1.
    - ich mach das immer so, wenn ich ein neues Projekt beginne um mich nicht in deatils zu verlieren:
    - ich recherchiere über das thema, problem und evt. schon mir bekannte lösungsansätze...
    - dann fertige ich ein PAP an, um mich später beim coden direkt wieder darauf zurückzufinden falls ich mich "verliere im coden..."
    - bei manchen projekten kannst auch noch vorher überlegen was für objekte,variablen,konstanten du brauchst und nutzen möchtest... (zumindest so in etwa...)
    - diese punkte helfen mir ungemein mich an die problemstellung und meinen lösungsweg zu halten und auch darauf "zurückzufinden" sollte dies von nöten sein... -> außerdem macht man sich vorher schon ausführlich gedanken was mir sehr hilft mich nicht in details aufzuhalten... da ich schon einen klar definierten lösungsweg ausgearbeitet habe... 😉

    - ich würde deine "aufgabe" mit qt - "tableview" lösen... sofern deine "listen" als .csv oder .txt vorliegen...
    - einfach ne import funktion basteln, gui basteln(per drag & drop), alles zusammenbauen...
    - dann kann man da auch noch nen "filedialog"-hinzufügen ggf. auch andere dateiformate exportieren geht alles relativ einfach mit den qt-klassen...
    - außerdem hat man dann auch gleich eine schöne nutzeransprechende gui mit tabellen ansicht 😉
    - dies ist aber nur geschmackssache... aber meiner meinung nach wäre der code etwas übersichtlicher und kürzer was einfach besser lesbar ist... (später wartbar, erweiterbar)
    - ansonsten würde mir spontan nix einfallen... hab jetzt deinen code aber auch nur mal überflogen...
    - oder existieren in deinem code fehler die gefunden werden sollten?

    ps. hoffe ich hab deine frage richtig verstanden und entsprechend geantwortet...
    😃

    - hab eben noch gesehen... du hast i.wie keine fehlerbehandlung wenn ich es richtig gesehen habe... (bin mir nicht ganz sicher)
    also bei if(!std::cin){break;} geht das prog. aus aber keiner weiß warum?
    - ist vll nicht schön aber da kannst auch einfach nochn text ausgeben oder sowas... 😃



  • Mfg schrieb:

    - vll ne blöde frage aber warum kein std::endl?

    Naja, das war nur ein random Beispiel. Ich meinte, kein std::endl, wenn '\n' gemeint ist. Eben eine typische Anfaengersache.

    Mfg schrieb:

    - hab eben noch gesehen... du hast i.wie keine fehlerbehandlung wenn ich es richtig gesehen habe... (bin mir nicht ganz sicher)
    also bei if(!std::cin){break;} geht das prog. aus aber keiner weiß warum?
    - ist vll nicht schön aber da kannst auch einfach nochn text ausgeben oder sowas... 😃

    Da das ein Kommandozeilenprogramm werden soll, wird das Programm durch eingeben eines end-of-file (ctrl-D bzw. ctrl-z) beendet, das ist ein featuer 😉

    Vielen Dank fuer deine Antwort, aber das hilft mir nicht wirklich weiter. Mal davon abgesehen, dass ich das bewusst nicht als GUI auslegen moechte, deshalb also auch kein QT nutzen werde, ist der Rest etwas allgemein gehalten.
    Klar, ich denke auch darueber nach, was ich brauche, mache mir auch mal Struktogramme oder so was, wobei ich damit noch nicht so wirklich produktiv war.
    Ich dachte, moeglicherweise kann ich mir ein paar Tipps von erfahrenen Programmieren abholen, die dieses Problem kennen und gut verstehen. Dabei ist es verstaendlicherweise nicht einfach, das nicht zu theoretisch zu halten. Vielleicht kennt jemand ja auch ein fuer die Praxis ausgelegtes Buch oder ein gut dokumentiertes kleines Projekt, am besten mit einer dokumentierten Herangehensweise/Strategie.

    Auch der Blick in Open-Source-Projekte ist eher ernuechternd. Da wird doch haeufig genau das gemacht, von dem einem alle abraten (z.B. 40 globale Variablen verwenden).



  • @MfG: War das Fullquote denn nötig?



  • Hyde++ schrieb:

    Mfg schrieb:

    - vll ne blöde frage aber warum kein std::endl?

    Naja, das war nur ein random Beispiel. Ich meinte, kein std::endl, wenn '\n' gemeint ist. Eben eine typische Anfaengersache.

    Mfg schrieb:

    - hab eben noch gesehen... du hast i.wie keine fehlerbehandlung wenn ich es richtig gesehen habe... (bin mir nicht ganz sicher)
    also bei if(!std::cin){break;} geht das prog. aus aber keiner weiß warum?
    - ist vll nicht schön aber da kannst auch einfach nochn text ausgeben oder sowas... 😃

    Da das ein Kommandozeilenprogramm werden soll, wird das Programm durch eingeben eines end-of-file (ctrl-D bzw. ctrl-z) beendet, das ist ein featuer 😉

    Vielen Dank fuer deine Antwort, aber das hilft mir nicht wirklich weiter. Mal davon abgesehen, dass ich das bewusst nicht als GUI auslegen moechte, deshalb also auch kein QT nutzen werde, ist der Rest etwas allgemein gehalten.
    Klar, ich denke auch darueber nach, was ich brauche, mache mir auch mal Struktogramme oder so was, wobei ich damit noch nicht so wirklich produktiv war.
    Ich dachte, moeglicherweise kann ich mir ein paar Tipps von erfahrenen Programmieren abholen, die dieses Problem kennen und gut verstehen. Dabei ist es verstaendlicherweise nicht einfach, das nicht zu theoretisch zu halten. Vielleicht kennt jemand ja auch ein fuer die Praxis ausgelegtes Buch oder ein gut dokumentiertes kleines Projekt, am besten mit einer dokumentierten Herangehensweise/Strategie.

    Auch der Blick in Open-Source-Projekte ist eher ernuechternd. Da wird doch haeufig genau das gemacht, von dem einem alle abraten (z.B. 40 globale Variablen verwenden).

    - ach so...
    - joa man sollte kein std::endl anstatt \n nutzen , aber das ist doch auch allgemein?

    - naja eig sind diese "herangehsweisen" PAPs und alles mögliche was es da noch so gibt... -> ansonsten gibt es noch generell Entwicklungsmethoden (z.B. Scrum etc... )
    - eig machst du ja solche "vorüberlegungen" um "produktiver" zu sein... bzw. schneller zu coden und die Probleme schonmal vorher zu durch denken um später nicht erst auf probleme zu stoßen...

    - ist nat. etwas allgemein... aber ich hab keine zeit deinen code jetzt zeile für zeile durch zu gehen(hab ich oben auch geschrieben...) und dir dann alle schönheits markel aufzuzeigen (sofern überhaupt welche vorhanden)...

    - eigentlich hast du bei OpenSource eine Qualitätskontrolle... die lässt dich gar nicht "einchecken" wenns nich passt... außerdem achten die entwickler auch untereinander auf code-qualität... (gibt sicherlich auch ausnahmen) 😮

    - normalerweise werden dort außer es muss unbedingt sein keine globalenvariablen genutzt... und vom code-stil und so etwas ist opensource schon sehr gut... 🙄
    welches projekt /-e hast du dir angeschaut?

    - es gibt auch fälle da kann/sollte man globalevariablen nutzen(z.B. int _CRT_glob für Globbing einstellungen bei MinGW) ... 🙄

    - ok wenn es gezielt als konsolenanwendung gewünscht war ist ja ok...
    - wollte nur sagen das es mit den qt-klassen (gibts auch für konsolenanwendungen) evt. einfacher geht(schon vorhandene klassen, methoden gibt) und somit der code etwas kürzer wird... (was die leserlichkeit und wartbarkeit erhöht...) 🙄

    - und jetzt mal ganz blöd gefragt: warum willst du eig nicht eine schöne tabellenansicht, deiner Daten wenn du ein programm baust mit dem du listen verwaltest/bearbeitest oder einfach ausgibst? 😕

    na ja egal... ist nicht meine baustelle... 🙄



  • Sich endlos in Details zu verlieren ist häufig ein Zeichen dafür, das man das Problem und die Tools die man verwendet, doch noch nicht so richtig verstanden hat. Haufig hilft es einfach einen Schritt zurück zu gehen, Grundlagen zu lernen und sich nur darauf zu konzentrieren was man auch verstanden hat.

    Ansonsten spielt natürlich die Erfahrung immer eine große Rolle.



  • oenone schrieb:

    @MfG: War das Fullquote denn nötig?

    Ich wollte auch grad schreiben "Fullquote FTW!!! 🙄".
    Naja gut. Jetzt hab' ich's ja geschrieben 😃



  • Hyde++ schrieb:

    Wie schafft man es, sich nicht endlos in Details zu versteigen, einfach mal was fertig machen und dabei trotzdem etwas halbwegs lesbares zu produzieren?

    Das funktioniert zwar nicht immer, aber ich versteigere mich auch ziemlich selten in irgendwelche Details. Zum einen "braucht" man dafür Erfahrung. Ich habe einfach schon einen gewissen Stil und muss bei Kleinigkeiten nicht lang überlegen, wie ich das mache. Brauchen hab ich jetzt in Anführungszeichen geschrieben, weil das jetzt nicht heißt, dass man mit Erfahrung automatisch besseren Code schreibt. Ich weiß durchaus, dass mein Code meist bei weitem nicht optimal ist. Ich könnte mir gut vorstellen, dass mir die Lösung anderer Entwickler desselben Problems besser gefallen würde. Nur ist es auch so, dass ich meine Lösung auch eben gut genug finde und kein Bedürfnis empfinde, an denen ewig rumzufeilen. Und ich weiß aus Erfahrung auch, dass mein Code meist schon ganz brauchbar ist.
    Zum anderen interessieren mich Details mittlerweile auch weniger, als das große Ganze. Ich hab meist keine "Projekte" (zumindest das, was ich als Projekt bezeichnen würde, irgendwelche Kleinigkeiten zwischendurch muss man natürlich ständig machen), bei denen es um paar Klassen geht. Meist sind es größere Module, und da interessiert mich die Architektur mehr als Details. Ob eine Klasse dann perfekt ausgearbeitet ist, ist im Gesamtkonzept für mich meist irrelevant.



  • Mechanics schrieb:

    und da interessiert mich die Architektur mehr als Details. Ob eine Klasse dann perfekt ausgearbeitet ist, ist im Gesamtkonzept für mich meist irrelevant.

    finden Deine Auftrag-/Arbeitgeber das auch? 🙂



  • großbuchstaben schrieb:

    Mechanics schrieb:

    und da interessiert mich die Architektur mehr als Details. Ob eine Klasse dann perfekt ausgearbeitet ist, ist im Gesamtkonzept für mich meist irrelevant.

    finden Deine Auftrag-/Arbeitgeber das auch? 🙂

    Natürlich, die interessiert Details sowieso nicht. Für die ist das Gesamtkonzept sowieso viel wichtiger. Da geht es mehr um solche Punkte wie, wie gut skaliert das ganze, wenn man mit sehr vielen Daten umgehen muss, kommt das System mit mehreren Benutzern zu Recht, wie stabil und fehlertolerant ist es, wie gut ist es wartbar, wie schnell kann man neue Anforderungen umsetzen usw.
    Außerdem hab ich nie behauptet, dass die Details bei mir "schlecht" wären. Das würde fast automatisch dazu führen, dass das Gesamtsystem weniger stabil und wartbar wäre.



  • @Hyde: Es gibt bestimmt noch Dinge an deinem Code zu verbessern, aber das gibt es immer. Für mich sieht das so aus, als hättest du die Grundlagen sehr gut verstanden und leidest eher an analysis paralysis, also genau das Gegenteil von dem, was viele andere machen, nämlich einfach irgendwelchen Frickelcode rauszuhauen und nie auch nur drüber nachzudenken, wie man es sauberer lösen könnte. 😉

    Also ich könnte mir vorstellen, dass es dich weiter bringt, einfach mal ein paar größere Projekte fertigzustellen auch wenn der Code nicht perfekt ist. Manchmal ist es vernünftiger eine doofe Stelle im Code zu haben, die einem später eventuell Ärger für ein paar Tage macht als mit dem release wochenlang nicht voran zu kommen, bzw. irre Template-Akrobatik zu machen, nur um wirklich 100%ig DRY zu sein.



  • Hallo,

    lass dich von diesem Forum nicht abschrecken 😉

    In der Industrie habe ich einen interessanten Effekt festgestellt:
    da gibts Leute, die liefern echt miesen Code ab. Der macht Probleme, und da muss man auch nichts dazu sagen.
    Dann gibt es Leute, die verbringen Stunden und Tage nur um ein total simples Problem zu lösen, dafür ist der Code perfekt. Alles durchdacht, zig Templates sodass alles generisch ist. Teilweise ist der Code aber auch recht kompliziert, sodass andere sich damit schwertun.
    Und dann gibt es die wirklich produktiven Leute, die auch guten Code abliefern, sich dabei aber aufs Wesentliche konzentrieren. Die verwenden die praktischen Dinge von C++ wie RAII, Containerklassen, ...

    Ich kann dir nur empfehlen zu versuchen, C++ als Werkzeug zu sehen und dir ein paar praktische Dinge rauszusuchen die dir bei der Arbeit helfen. Dann nämlich bist du produktiv.
    Wenn du Spaß daran hast, deinen Code bis ins Unendliche zu perfektionieren, kannst du das natürlich auch gerne machen. Zumindest als Hobby.



  • fdsfsdfsf schrieb:

    Ich kann dir nur empfehlen zu versuchen, C++ als Werkzeug zu sehen und dir ein paar praktische Dinge rauszusuchen die dir bei der Arbeit helfen. Dann nämlich bist du produktiv.

    👍 Dem ist wenig hinzuzusetzen.

    Ein besserer Programmierer verwendet allein jene Dinge, die er voll beherrscht und
    eignet sich jene Dinge an, die er noch nicht voll beherrscht. Ansonsten steht immer
    die nachvollziehbare Realisierung einer Aufgabe im Vordergrund, die auch von anderen
    verstanden werden muss, also wartbar ist.



  • das hab ich doch schon gesagt! 🙂



  • Vielen Dank fuer die Antworten, ich werde versuchen, die Tips umzusetzen.



  • Nach 15 Jahren Erfahrung als Software-Entwickler kann ich nur sagen, dass beim Löwenanteil der Projekte, an denen ich mitgearbeitet habe, eben nur am Anfang etwas geplant wurden. Dann wechselten die Mitarbeiter, der Zeitdruck wurde größer und so weiter und so fort. Unter dem Strich muss eine Funktionalität in erster Linie fertig werden, ob es schöner Code ist ist in den allermeisten Fällen total unwichtig. Zeit für Planung, Testen usw vom Arbeitgeber zu bekommen ist nur in gewissen Maßen in Zeiten möglich wo nicht viel los ist.

    Schönen Code habe ich eigentlich nur privat und mit viel Zeit geschrieben. In der Praxis habe ich mich dem Codestil des Projektes versucht anzupassen und halt gesehen dass es irgendwie fertig wird. Die meiste Zeit ging immer dafür drauf überhaupt herauszufinden wie der Programmcode was macht. Oft gab es eine Doku, die mal Anfang gepflegt wurde, aber dann irgendwann, wieder aus Zeitnot, nur stiefmütterlich weitergeführt wurde. Dann hatte ich Projekte wo ich gar nichts hatte- Nicht mal einen technischen Ansprechpartner, der war nämlich von heute auf morgen ich dann.

    Ich habe immer nur davon gehört, dass es Firmen gibt die wirkliche Software-Entwicklung, wie aus den Fachbüchern, betreiben. Persönlich gesehen habe ich so etwas noch nie.

    Was solls, ich bin persönlich aus der Branche ausgestiegen, habe jetzt viel viel Freizeit und programmiere nur noch für mich. Ob ich je wieder als Software-Entwickler arbeiten will, ist fraglich. Es gibt einfach Stress, den muss ich nicht haben.



  • Aussteiger schrieb:

    Was solls, ich bin persönlich aus der Branche ausgestiegen, habe jetzt viel viel Freizeit und programmiere nur noch für mich. Ob ich je wieder als Software-Entwickler arbeiten will, ist fraglich. Es gibt einfach Stress, den muss ich nicht haben.

    Interessenfrage: Was machst du jetzt? 🙂



  • Erstmal ein Jahr Pause von allem mit Therapie zur Stressbewältigung und dann wahrscheinlich eine Berufsreha, wenn das nicht klappt dann Frührente. Also entweder anderen Job, oder gar nicht mehr arbeiten und den Rest meines Lebens das machen was mich interessiert. Geld ist kein Thema, ich brauche nicht viel.



  • Aussteiger schrieb:

    Unter dem Strich muss eine Funktionalität in erster Linie fertig werden, ob es schöner Code ist ist in den allermeisten Fällen total unwichtig.

    Ja, aber die Kunst dabei ist, trotzdem "fast" schönen Code abzuliefern. Mit etwas Erfahrung gelingt das auch ziemlich oft. Wenn man seinen eigenen Stil entwickelt hat, tüftelt man nicht mehr stundenlang jede Klasse aus. Und für Architekturüberlegungen kann man sich die Zeit meist schon nehmen. Vielleicht nicht immer so viel, wie man gern hätte, aber ich habs jedenfalls noch nie erlebt, dass ich selbst oder andere etwas total vermurkstes abliefern mussten, nur weil die Zeit für Planungen nicht gereicht hätte. Eher reicht die Zeit für die Implementierung, Feintuning und Tests nicht.



  • Ja klar, versucht man sein bestes, aber der Kunde zahlt nun einmal nicht für schönen Code, der ist nur da damit wir besser mit zurecht kommen können. Wenn der Chef Planung, Test, schönen Code und Doku mit in die Kostenkalkulation einbringen würde, dann könnten die meisten ihre Firma einfach dicht machen. Das sollte nicht so sein, ist aber leider oft so. Na jedenfalls war es in der vier Firmen, in denen ich gearbeitet, hatte so. Mal mehr mal weniger stark ausgeprägt. Was anderes ist es, wenn man an hauseigenen Produkten arbeitet, die über Jahre wachsen. Und nochmal anderes ist es, wenn der Chef selbst Entwickler ist.


Anmelden zum Antworten