Hallo, Ich möchte demnächst ein größeres Projekt gemeinsam mit einem Freund angehen. Wir haben uns vorgenommen dies mal absolut sauber und transparent sowie einfach wartbar zu programmieren. Programmiert wird mit der CoIDE ein STM32F415. Jetzt ein paar Fragen: 1. Gibts es ein gutes Tool mit dem man die Softwareversionen sauber dokumentieren kann (Versionsnummer, Änderungen, To-Do etc)? Excel evtl.? 2. Sind globale Variablen nötig bzw. lassen sie sich überhaupt vermeiden? Ich würde halt alles Modular aufbauen wollen, das heißt jeder Hardwareabchnitt bekommt ein eigenes Modul (Source-File) und die Daten werden über Pointer geändert bzw. ausgetauscht. 3. Was muss vereinbart werden wenn zwei Leute an einem Programm arbeiten? Codestyle? Und was noch? Ingo
Ingo schrieb: > 3. Was muss vereinbart werden wenn zwei Leute an einem Programm > arbeiten? Codestyle? Und was noch? Versionsverwaltung für den Sourcecode --> z.B. Git oder Subversion verwenden
Ingo schrieb: > Wir haben uns vorgenommen dies mal absolut sauber und > transparent sowie einfach wartbar zu programmieren Gute Idee zu 1. Ja gibt es. sieh hier: http://en.wikipedia.org/wiki/Comparison_of_revision_control_software Excel ist da eine sehr schlechte Idee. zu 2. Ohne Globale Variablen werdet ihr in den Modulen nicht auskommen. Aber die wenigsten werden über EXTERN den anderen Modulen bekannt gegeben. Pointer sind so ne Sachen. Dadurch werden solche Zugriffe über Module hinweg zwar einfach möglich, sie bieten aber auch ein Potenzial um Schaden anzurichten. zb, der Pointer zeigt auf ein Byte aber geschrieben wird ein Word. Meiner Meinung nach sind Funktionsaufrufe in diesem Fall besser. zb ein Modul bietet eine globale Funktion um einen Zähler zu setzen. void SetCounterValue(Uint16 Value) Diese Funktion ist Global verfügbar und jedes andere Modul ruft genau diese Funktion auf um den Zähler zu setzen. Damit ist sichergestellt das die Variablengrößen sauber zusammen passen. Genauso dann auch mit den Lesezugriffen verfahren. Also alle Variablen die von anderen Modulen gelesen oder geschrieben werde sollen werden in eigene Funktionen eingepackt. Das gleiche dann auch für Aktionen wie zb einen Pin setzen oder einen Timer starten. zu3. Codestyle, ja sicher. (Wie) Wer macht was und wann ? sonst kann es leicht passieren das Arbeiten doppelt gemacht werden, bzw gar nicht weil jeder denkt der andere macht es. Das heißt also eine Planung und Verteilung von Arbeitspaketen.
Ja, dass mit den Funktionsaufrufen hatte ich auch so ähnlich vor. Welches Programm für eine Versionsverwaltung ist denn zu empfehlen? Vielen Dank schonmal... Ingo
Ralph schrieb: > zu 2. > Ohne Globale Variablen werdet ihr in den Modulen nicht auskommen. Warum nicht? Im Idealfall kommt man ganz ohne globale Variablen aus. Das sollte man anstreben und es ist auch möglich. > Aber die wenigsten werden über EXTERN den anderen Modulen bekannt > gegeben. Diesen Satz verstehe ich nicht. Abhängigkeiten sollten die Module jedenfalls von außen (z.B. vom Aufrufer) übergeben bekommen, und sich nicht selbst suchen müssen. Du kannst dir auch einmal “testgetriebene Entwicklung“. Die hilft eine saubere Architektur aufzuziehen.
Ingo schrieb: > Welches Programm für eine Versionsverwaltung ist denn zu empfehlen? Die beiden verbreiteten sind SVN und Git. Git bietet für Fortgeschrittene mehr Möglichkeiten. Aber wenn ihr vorher noch nie mit Versionsverwaltung gearbeitet habt, tut ihr euch mit SVN wahrscheinlich leichter. > Sind globale Variablen nötig bzw. lassen sie sich überhaupt > vermeiden? Sie lassen sich komplett vermeiden. Schau mal in diesen Beitrag: Beitrag "Re: Sauber Programmieren mit Interrupts" Kurzfassung: Nur modul-globale Variablen (static) und in Funktionen lokale Stackvariablen verwenden. > Ich würde halt alles Modular aufbauen wollen, das heißt jeder > Hardwareabchnitt bekommt ein eigenes Modul (Source-File) Guter Ansatz. > und die Daten werden über Pointer geändert bzw. ausgetauscht. Nicht so gut, zumindest nicht als grundsätzliche Vorgehensweise. Für jede Variable bzw. jedes Datum sollte in jedem Programmzustand nur genau ein Modul zugriffsberichtigt sein. Das stellt man am einfachsten sicher, indem die Daten nach außen nur "by value" übergeben werden:
1 | static int counter; |
2 | |
3 | int get_counter(void) { |
4 | return counter; |
5 | }
|
6 | |
7 | void set_counter(int value) { |
8 | counter = value; |
9 | }
|
Ein anderes Modul hat auf die Weise keine Chance, die Variable counter unerwartet zu modifizieren. Man kann in die get- und set-Funktionen gegebenfalls zusätzliche Überprüfungen einbauen oder den Aufruf an ein anderes Modul bzw. Hardware delegieren. Man sollte allerdings hellhörig werden, wenn man auf eine Modulvariable sowohl per get- als auch per set-Funktion zugreifen kann. Oft wäre ein anderes Interface passender, hier zum Beispiel:
1 | static int counter; |
2 | |
3 | int get_counter(void) { |
4 | return counter; |
5 | }
|
6 | |
7 | void counter_increase(void) { |
8 | if (counter < INT_MAX) { |
9 | counter++; |
10 | }
|
11 | }
|
12 | |
13 | void counter_decrease(void) { |
14 | if (counter > INT_MIN) { |
15 | counter--; |
16 | }
|
17 | }
|
Das geht natürlich nur mit kleinen Datentypen. Größeren Strukturen by value übergeben wäre ineffizient, da kommt man um Zeiger nicht rum. Trotzdem sollte man festlegen, wer die Zuständigkeit über die Daten an dem Zeiger hat. Wenn beispielsweise Modul A einen Zeiger auf eine eigene Modulvariable a_x an das Modul B übergibt, wechselt die Zuständigkeit über a_x von Modul A nach B. Das heißt, Modul A darf nicht mehr auf a_x zugreifen, solange B an den Daten arbeitet:
1 | // Modul A
|
2 | |
3 | static int a_x; |
4 | |
5 | void eine_funktion(void) { |
6 | mach_etwas(&a_x); |
7 | }
|
1 | // Modul B
|
2 | |
3 | void mach_etwas(int* p) { |
4 | *p = 5; |
5 | }
|
Man muss also festlegen, wie lange B die Zuständigkeit behält. Sinnvollerweise beschränkt man sich auf die Dauer das Funktionsaufrufs. B darf also nur innerhalb der Funktion mach_etwas() auf die Daten des Zeigers zugreifen. B darf sich den Zeiger nicht irgendwo speichern und später wieder von alleine auf die Daten zugreifen. Das sollte in der Dokumentation zu mach_etwas() erwähnt werden oder als Standard im Projekt festgelegt werden. In anderen Fällen kann es sinnvoll sein, dass B die Zuständigkeit länger behält. B speichert sich also den Zeicher, bis es ihn über eine Callbackfunktion zurück gibt oder ihm der Zeiger über ein andere Funktion entzogen wird. Währenddessen darf kein anderes Modul (auch nicht A) etwas mit den Daten machen. Das gehört natürlich ebenfalls dokumentiert und muss eingehalten werden. > 3. Was muss vereinbart werden wenn zwei Leute an einem Programm > arbeiten? Codestyle? Und was noch? Das wichtigste ist, sich Gedanken um die Gesamtarchitektur und die Schnittstellen zwischen den Modulen zu machen. Stichwort: Lose Kopplung, starke Bindung. Was zusammen gehört, muss zusammengefasst und gekapselt sein. Die Schnittstelle eines Moduls gibt nur die Informationen bekannt, die der Programmierer braucht, um es zu benutzen. Die Schnittstelle ist so zu gestalten, dass die Benutzung des Moduls so klar und einfach wie möglich ist (und nicht etwa so, wie sich die Funktion innerhalb des Moduls am leichtesten programmieren lässt!). Außerdem klare Bezeichner wählen und sauber dokumentieren. Dem Benutzer des Moduls muss nach einem Blick ins Header-File klar sein, wie er das Modul zu benutzen hat, ohne den dazugehörigen Quellcode zu kennen. Wenn es sich nicht von alleine ergibt wäre es auch sinnvoll, Zuständigkeiten zu vereinbaren. Das heißt, für jedes Modul ist ein Entwickler federführend. Änderungen an dem Modul, abgesehen von offensichtlichen Bugfixes, müssen mit dem für das Modul Zuständigen abgesprochen werden. Derjenige kann dadurch verhindern, dass an das Modul mit der Zeit immer neue, kleine Hacks und Erweiterungen drangebastelt werden, die da eigentlich nicht hingehören. Außerdem müssen sich bei Schnittstellenänderungen immer alle Betroffenen absprechen oder zumindest informiert werden. Deshalb lohnt es sich, ordentlich Zeit in den Entwurf einer sauberen und stabilen Schnittstelle zu stecken, die man im Idealfall nie mehr ändern muss. Einen Codestyle zu vereinbaren ist auf jeden Fall sinnvoll, damit der Code einheitlich aussieht. Das ist nicht nur eine ästhetische Frage, sondern hilft auch Fehler leichter zu finden und zu vermeiden.
Ingo schrieb: > Hallo, > > > Jetzt ein paar Fragen: > 1. Gibts es ein gutes Tool mit dem man die Softwareversionen sauber > dokumentieren kann (Versionsnummer, Änderungen, To-Do etc)? Excel evtl.? > Meine Empfehlung ist git. Ich hatte mal ein wenig mit SVN (Subversion) gearbeit, Bin aber nacher auf git umgestiegen. Wenn zwei oder mehr Leute an einem Projekt arbeiten ist es mit SVN sehr schwierig die einzelnen Zweige (Test/Bugfix usw.9 wieder zusammen zu führen. Was bei git auch noch ein Vorteil ist, du branchst zum Arbeiten (commiten und Co.) kein Netzwerk, alles ist lokal auf deiner Platte. Erst wenn du es willst man du einen push und lädst die Sache auf deinen/euren Server hoch. > > 3. Was muss vereinbart werden wenn zwei Leute an einem Programm > arbeiten? Codestyle? Und was noch? > Schau mal im linux Quellcode unter Documentation/CodingStyle
Ingo schrieb: > Jetzt ein paar Fragen: > 1. Gibts es ein gutes Tool mit dem man die Softwareversionen sauber > dokumentieren kann (Versionsnummer, Änderungen, To-Do etc)? Excel evtl.? z.B. trac zusammen mit SVN.
@Fabian O. (xfr) Danke dir für den super Beitrag, so gut erklärt hat es mir bisher auch noch keiner!
Hallo Fabian, besten Dank für den ausführlichen Beitrag. Ich bin gespannt ob sich das alles so umsetzen lässt? Ich werde mir Git und SVN mal anschauen. Vielen Dank!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.