Clanintern Clanintern Clanintern

Forum

Öffentliche Foren
FORUM: Allgemeines THEMA: Leerzeilen in Computercode
AUTOR BEITRAG
Ho(r)st

RANG Sucker

#1 - 25.03 17:33

Habe gerade diese Diskussion mit Kollegen: Gehoeren massive Mengen an Leerzeilen in guten Programmcode?

Ich bin der Meinung nein. Mache mich damit unbeliebt...
Allanon // alex

CI-Chef

RANG Deckschrubber

#2 - 25.03 22:37

Was meinst du mit "massive Mengen"?
Prinzipiell gibt es "best practices" was Codekonventionen angeht, aber im Speziellen ist hier immer im Team ein Konsens zu finden und das beinhaltet auch für den ein oder anderen Kompromisse.

Ein möglicherweise passendes Beispiel in einem Team bei uns ist der ternäre Operator anstatt von einfachen if-else-Konstrukturen
(condition) ? statement1 : statement2;
code


Einige Mitglieder im Team meinten, dass dadurch das Lesen vom Code schwerer wird. Tatsächlich werden die wohl teilweise auch nicht verstanden...
Konsens: wir setzen sie nun nicht ein und schreiben halt statt der einen Zeile nun 5
if (condition) {
    statement1
} else {
    statement2
}
code


Und ja, man könnte sich die Klammern sparen, aber das widerspricht wieder einer anderen Konvention :-D
fezie

RANG Deckschrubber

#3 - 26.03 07:32

Also Leerzeilen benutz ich recht sparsam
Wirklich notwendig finde ich das nicht, dass man die massig einfügen sollte
Allanon // alex

CI-Chef

RANG Deckschrubber

#4 - 26.03 08:46

ah ich hab auf die eigentliche Frage nicht beantwortet :-)
Leerzeilen finde ich teilweise schon sinnvoll, wenn sie z.B. logische Einheiten trennen. Genau in einem solchem Fall ist dann aber zu prüfen ob man nicht direkt besser modularisieren kann.

Sofern mit "massiv" aber gemeint ist, dass z.b. ein immer so
if (condition) {
    statements
}
code

statt
if (condition) {statements}
code

geschrieben wird, bin ich klar PRO Zeilen :-) aber das sind ja keine Leerzeilen.

Mit ist nicht ganz klar, was in der Frage genau gemeint ist.
fezie

RANG Deckschrubber

#5 - 26.03 13:28

Jo. Für Zeilenumbrüche bin ich natürlich auch.
Aber wie gesagt öfters eine komplette leere Zeile brauch ich nicht
ZB am Anfang einer Funktion zur Trennung von den Variablen und dem eigentlichen Code mach ich immer eine leere Zeile
Ho(r)st

RANG Sucker

#6 - 27.03 19:47

Sowas zum Beispiel würd ich für massiven Einsatz halten bzw. für vertikale Platzverschwendung:

float function( int a, int b )
{

    // this stores a variable
    float var1;
    // this stores the result
    float result;

    int N = FINAL;

    for( int i = 0; i < N; i++ )
    {

       (iteration)

    }

    // the function ends here

    return result;

}
code


Ist zugegebenermaßen ein übertriebenes Beispiel

Aber ich hab manchmal das Gefühl dass Leute gerne überflüssige Kommentare in den Code machen und "Luft lassen". Ich mags dann lieber so:

float function( int usefulname1, int usefulname2 )
{
    float usefulname3, result;
    int N = FINAL;

    for( int i = 0; i < N; i++ ){
       (iteration)
    }
    return result;
}
code


Sind aber Studenten bei uns und keine Profis, von daher wohl verzeihbar
Allanon // alex

CI-Chef

RANG Deckschrubber

#7 - 27.03 20:37

Bin hier voll auf deiner Seite, wobei du gleich zwei Sachen optimiert hast. Zum Einen die Leerzeilen, die auf jeden Fall übertrieben und überflüssig sind. In deiner Version hast du noch eine zwischen Deklarationen und eigentlichem Methodenrumpf stehn lassen, die ich auch für sehr sinnvoll halte und wohl allgemein akzeptiert wird. Alle anderen hätte ich auch gestrichen. In meinem aktuellen Projekt war anfangs auch die Diskussion ob man nicht immer die erste Zeile einer Methode immer eine leere sein soll. Einigung: nein :-)

Zum Anderen hast du aber gleichzeitig einige Kommentare entfernt, die ohne Frage sowieso überflüssig waren. Wie heißt es so schön im CCD

Unnötige oder gar falsche Kommentare halten beim Lesen auf. Der Code sollte so klar und deutlich sein, dass er möglichst ohne Kommentare auskommt.

quote of Clean-Code-Development - Orangener Grad
Und da stehe ich auch voll dahinter. Kommentare auf Methodenebene sind ein muss. In einer Methode erklären sie bei mir aber maximal eine verstecke Magic oder spezielle Seiteneffekte die nicht offensichtlich sind. Und wenn man anfangt durch Kommentare einzelne Bereiche innerhalb von Methoden abzugrenzen ist das ein eindeutiges Indiz dafür, dass die Methode geteilt werden muss.
Ho(r)st

RANG Sucker

#8 - 27.03 23:15

Ist CCD ein Handbuch? Das interessiert mich.

Du hast sicherlich um einiges mehr Erfahrung als ich.
Bin Physiker und bei uns wird programmieren oft mehr als Mittel zum Zweck gesehen und "on the fly" gelernt, was oft zu unschönem Code führt. Seit einiger Zeit hab ich mir zum Ziel gesetzt auf Stil zu achten. Bin gerade dabei in mühsamer Arbeit einen seit vier Jahren "gewachsenen" Code zu überarbeiten. Konnte ihn schon von ca. 50k auf ca. 43k Zeilen kürzen.

Was stehst du zu Variablen- und Methodennamen? In unserem Projekt gibt es natürlich kein einheitliches Schema aber ich überlege alle Methoden in lower Camelcase zu benennen, mit möglichst aussagekräftigen Namen z.B. sowas wie:
 dumpMemoryWhenInvalid( const float );
code

(schreibt den Inhalt einiger wichtiger Arrays in eine Datei falls die eingegebene Zahl inf oder nan ist)
Allanon // alex

CI-Chef

RANG Deckschrubber

#9 - 29.03 12:24

CCD steht für clean-code-developer und ist kein klassisches Handbuch, sondern umfasst viele Prinzipien und Praktiken die einem auf dem Weg zu professioneller Softwareentwicklung helfen und den Code eben "schöner" und "sauberer" machen.
Alle Infos zu CCD findest du auf http://www.clean-code-developer.de/

Zu der Frage mit den Methodenamen:
Ob Camelcase oder mit Unterstrichen ist letzendlich egal, dies reiht sich in die Codekonventionen und ist einfach im Team abzustimmen und dann im Projekt einheitlich umzusetzen. Tatsächlich hat sich meiner Erfahrung nach (zumindest in Java) die Camelcase-Variante durchgesetzt.
Das wichtigste an den Methodennamen ist aber, das es unmissverständlich das beschreiben, was sie auch macht. Man soll in der Lage sein, "nur" den Namen zu lesen und soll dann wissen was passiert. Bewährt hat sich auch hier, dass zu Beginn ein Verb steht, wie du es mit "dump" eh schon gemacht hast.
Ho(r)st

RANG Sucker

#10 - 30.03 10:36

Die Seite ist cool! Vielleicht kauf ich mir sogar bei Gelegenheit mal das Buch.
TheCze

RANG Prophet of Clanintern

#11 - 30.03 17:26

Jetzt sollte der Typ nur noch wissen wie man ne Website clean und übersichtlich gestaltet....
Allanon // alex

CI-Chef

RANG Deckschrubber

#12 - 30.03 17:34

CCD sagt (leider?) nichts über Design oder Usability aus..
TheCze

RANG Prophet of Clanintern

#13 - 30.03 20:26

Um was zum Thema beizutragen: akzeptabler Gebrauch von Leerzeilen

public class Obstacle : MonoBehaviour {

	Vector2 speed=new Vector2(-4,0);
	Rigidbody2D rb2d;
	bool scored=false;
	public Plane p;

	void Start () {
		rb2d=GetComponent<Rigidbody2D>();
		rb2d.velocity=speed;
		float posy=rb2d.position.y+Random.Range(-4f,0);
		rb2d.MovePosition(new Vector2(rb2d.position.x,posy));
	}
	
	void Update () {
		if(transform.position.x<-40){
			Object.Destroy(this.gameObject);
		}

		if(transform.position.x<0&&!scored){
			scored=true;
			GameObject.Find("Score").SendMessage("ScoreOne");
		}
	}
	public void Crash(){
	
		rb2d.velocity=Vector2.zero;
	}
}
code
Ho(r)st

RANG Sucker

#14 - 31.03 07:31

Ich meinte im übrigen das Buch von Robert C. Martin dass dort erwähnt ist.

@TheCze:

Consistenterweise hätte ich entweder die Leerzeilen vor
"void Update()" weggelassen oder vor "public void Crash()" eine eingefügt.

Ausserdem jeweils die Leerzeilen vor "if(transform.position.x<0&&!scored){" und "rb2d.velocity=Vector2.zero;" hätte ich weggelassen.

Also z.B. so
public class Obstacle : MonoBehaviour {

	Vector2 speed=new Vector2(-4,0);
	Rigidbody2D rb2d;
	bool scored=false;
	public Plane p;

	void Start () {
		rb2d=GetComponent<Rigidbody2D>();
		rb2d.velocity=speed;
		float posy=rb2d.position.y+Random.Range(-4f,0);
		rb2d.MovePosition(new Vector2(rb2d.position.x,posy));
	}
	
	void Update () {
		if(transform.position.x<-40){
			Object.Destroy(this.gameObject);
		}
		if(transform.position.x<0&&!scored){
			scored=true;
			GameObject.Find("Score").SendMessage("ScoreOne");
		}
	}

	public void Crash(){
		rb2d.velocity=Vector2.zero;
	}
}
code


oder sogar so

public class Obstacle : MonoBehaviour {

	Vector2 speed=new Vector2(-4,0);
	Rigidbody2D rb2d;
	bool scored=false;
	public Plane p;

	void Start () {
		rb2d=GetComponent<Rigidbody2D>();
		rb2d.velocity=speed;
		float posy=rb2d.position.y+Random.Range(-4f,0);
		rb2d.MovePosition(new Vector2(rb2d.position.x,posy));
	}
	void Update () {
		if(transform.position.x<-40){
			Object.Destroy(this.gameObject);
		}
		if(transform.position.x<0&&!scored){
			scored=true;
			GameObject.Find("Score").SendMessage("ScoreOne");
		}
	}
	public void Crash(){
		rb2d.velocity=Vector2.zero;
	}
}
code
TheCze

RANG Prophet of Clanintern

#15 - 31.03 15:35

Stimmt die Leerzeile vor rb2d.velocity=Vector2.zero; macht wenig Sinn ^^

Meine Leerzeilen habe ich gerne zwischen Funktionen und auch zwischen einzelnen Abschnitten im Code. In einem so kleinen Stückchen ist die zwischen den beiden Teilen von void Update() womöglich übertrieben, aber so ist halt die Gewohnheit
Ho(r)st

RANG Sucker

#16 - 01.04 11:11

@Allanon: Mal eine andere Frage, wie ist deine Meinung zu static methods? Manche Leute scheinen das ja abzulehnen weil das Objekt Orientierung zerstoert oder sowas. Sollte man das prinzipiell vermeiden?

Grob gesagt, ich habe eine Klasse die auf Kommando Fehlermeldungen ausgibt, ueber eine "throw thisclass" Anweisung. Ich moechte die nun um eine Funktion erweitern die testet ob eine Fehler aufgetreten ist.

Wuerde das so als static public member implementieren
 thisclass::getLastError(){ <if error throw thisclass> } 
code
Allanon // alex

CI-Chef

RANG Deckschrubber

#17 - 01.04 20:34

Static ist in manchen Fällen (in Kombination mit Sprachen) unausweichlich. Ein typisches Beispiel ist das Singleton-Pattern, wenn man es selbst umsetzt.
class Single {
    // privater Konstruktor, um normale Instanzierung zu vermeiden
    private Single(){}
    
    private static Single instance;  // Singleton Instanz

    // liefert die einzige Instanz; falls keine vorhanden, wird diese erzeugt.
    public static Single getInstance() {
        if (instance == null) instance = new Single();
        return instance;
    }
}
code

Es mag z.B. in Java Annotations geben, mit denen man das faktisch ohne das Schlüsselwort static umsetzen kann, letztlich steckt aber nichts anders dahinter.

Andere Beispiele sind, wie bei dir, querschnittliche Themen wie Logging oder Security. Häufig verwendete Aufgaben für die man nicht immer eigene Instanzen erstellen will und man zentral einmal wo ablegt und von überall nutzen will. Sofern darin nun keine komplexe Logik, sondern ausschließlich die angesprochene querschnittliche Aufgabe umgesetzt ist, spricht da aus meiner Sicht nichts dagegen. Häufig läuft das aber aus dem Ruder und alles was nicht mehr 100%ig in die vorhandenen Objekte und deren Beziehungen passt, aber von mehreren Stellen genutzt werden soll, landet dann viel zu schnell in sogenannten Helper- oder Utility-Klassen. Abgesehen von einer Datum-UtilityKlasse, die leider in fast allen Sprachen notwendig ist, sind alle diese Klassen ein sicheres Anzeichen dafür, dass im (Domain-)Model etwas nicht passt.

Prinzipiell muss man aber zugeben, dass statische Klassen/Methoden tatsächlich OOP brechen. Es geht dabei ja um Objekte und deren Zustände. Genau der ändert sich aber nicht beim Einsatz von static.
Auch für die Vererbung ist es wichtig, denn je Sprache werden diese Elemente nicht mitvererbt.

Ich verteufle static also nicht generell, rate aber zum sparsamen Einsatz (und Besinnung zurück auf Objekte, aber das ist wieder ein anderes Thema).

Nochmal zu deiner Frage zurück:
So ganz verstanden hab ich deinen Fall nicht. Eine Klasse die auf Kommando Fehlermeldungen ausgibt??
Du schmeißt doch bereits Exceptions/Throwables. Normalerweise wird dadurch der Programmfluss an die Aufrufer zurückgegeben, bis irgendwann der catch kommt. Wozu also eine Methode die prüft ob ein Fehler vorliegt um dann eine Exception zu schmeißen? Da fehlt mir definitiv der Kontext.
Ho(r)st

RANG Sucker

#18 - 02.04 19:45

Danke fürs Input. Muss mir das ganze nochmal durch den Kopf gehen lassen.

Habe mein Beispiel tatsächlich nicht wirklich gut erklärt...

Also hier ganz konkret: Ich hab ein Programm das in der Sprache CUDA geschrieben ist. Diese Sprache hat einen Datentyp genannt "cudaError_t" in welchem Fehlercodes gespeichert werden können. Diese werden beim Aufrufen von CUDA Befehlen erzeugt, z.b:

cudaError_t cudaErr;
cudaErr = cudaSetDevice( ... );
code

cudaErr wird in diesem Fall gleich null sein falls der Befehl erfolgreich war, andernfalls mit einem Fehlercode gefüllt sein. Nun haben wir eine eigene Klasse Namens CudaError die diese Errorcodes verwalten soll. Sieht so aus:

class CudaError{
	public:
		CudaError( cudaError_t err );
		CudaError( const char* warn, cudaError_t err );
		cudaError_t getError( );
		const char* getErrorMessage( );
	private:
		cudaError_t cudaErr;
};

CudaError::CudaError( cudaError_t err ) : cudaErr( err ){
	std::cerr << "A CUDA error occured: " << getErrorMessage() << std::endl;
}
CudaError::CudaError( const char* warn, cudaError_t err ) : cudaErr( err ){
	std::cerr << warn << ": " << getErrorMessage() << std::endl;
}
cudaError_t CudaError::getError( ){
	return cudaErr;
}
const char* CudaError::getErrorMessage( ){
	return cudaGetErrorString( getError() );
}
code

Der typische Einsatz der Klasse sieht in etwa wie folgt aus:

const cudaError_t cudaErr = cudaGetLastError();
if( cudaErr ){ 
	throw CudaError( "An error has occured", cudaErr ); exit(-1);
} 
code


Da diese Sequenz im Code sehr häufig vorkommt hab ich mir überlegt das in eine statische Funktion zu packen, d.h. sowas wie

CudaError::checkForCudaError( char* message  ){
	const cudaError_t cudaErr = cudaGetLastError();
	if( cudaErr ){ 
		throw CudaError( message , cudaErr ); exit(-1); 
	}
}
code

(natürlich als static deklariert in der Klasse). Macht also eigenlich nichts ausser ein Objekt zu erzeugen und dann das Programm abzubrechen. Vereinfacht den Syntax ein kleines bisschen. Typischerweise spart man sich eine oder maximal zwei Zeilen pro Aufruf.
Allanon // alex

CI-Chef

RANG Deckschrubber

#19 - 02.04 20:59

Ah jetz isses klar was du machen willst :-) Ich kenne Cuda nicht wirklich, weiß nur, dass es für GPU Programmierung verwendet wird.

Erstmal was anders: bitte spar dir vor jeder Methode oder in Klassennamen das "Cuda". Ich hoffe die Sprache schreibt das nicht vor? In Java würdest die Klasse auch nicht JavaError nennen oder? Sieh für mich nach nem richtigem "bad code smell" aus :-)

So zurück zum Errorhandling: so richtig gefällts mir nicht, aber scheinbar ist das der "cuda way of life". Wenn die Rückgabe der Fehlercode ist, muss der natürlich bei jedem Methodenaufruf gecheckt werden. Das ist sehr oft, also muss es modularisiert werden. Dein Ansatz ist nicht schlecht, auf Anhier fällt mir da auch nicht anders ein.

Hab kurz das große Internetorakel befragt und kam wie üblich bei IT-Problemen bei Stackoverflow raus
scheinbar gibt es eine breit akzeptierte Lösung für genau dein Problem: http://stackoverflow.com/questions/14038589/what-is-the-canonical-way-to-check-for-errors-using-the-cuda-runtime-api
Schau dir das mal an, dort wird das Ganze mit einem Makro gelöst und spart dir somit auch deine statische Lösung
Ho(r)st

RANG Sucker

#20 - 03.04 11:27

Danke, werd mir das anschauen. Hätte natürlich auch google fragen können aber war ja auch prinzipiell an deiner Meinung zu unserem Codebeispiel interessiert.

Bzgl. Methoden-/Classennamen mit "Cuda" vorne:

Zunächst mal ist es so, dass Cuda keine vollständige Programmiersprache ist. Es funktioniert grob gesagt so: Man hat ein "Host" Programm welches ganz stink normal auf einer CPU läuft und in einer Reihe von Programmiersprachen geschrieben sein kann (C, C++ und Fortran sind auf jeden fall unterstützt, vermutlich auch Java und weitere). Cuda besteht nun im wesentlichen aus einem Satz von Libraries welche die Sprache um einen Satz von Befehlen erweitert mit welchem die Grafikkarten (genannt "Device" ) angesteuert werden können. Dazu gibt es noch einen eigenen Kompiler.

Oft macht es in der Praxis nun Sinn die Klassen die sich auf Devices beziehen speziell als solche zu kennzeichnen. Das macht das ganze etwas übersichtlicher (manchmal will man eben nur bestimmte Programmabschnitte eines existierenden Codes mittels der GPU beschleunigen). Die CudaError Klasse zum Beispiel kann eben nur Errors auslesen die durch das Device erzeugt wurden, aber keine "normalen" Errors die der CPU erzeugt. Wir testen auf Cuda Errors nach jedem Aufruf einer Device Methode.

Dazu kommt dass viele der Befehle aus den Cuda Libraries das Wort "Cuda" beinhalten. cudaSetDevice(), cudaError_t und cudaGetLastError() sind solche Beispiele (oder cudaMalloc() welches im Vergleich zu malloc() Speicher auf der GPU reserviert). Die Namen sind nicht von uns gewählt. Nvidia ist sehr aggressiv bezüglich Marketing .

Hab gerade mal in das Beispiel auf stackoverflow geschaut. Ich will eigendlich nicht nach jedem Cuda Befehlt auf Errorcodes checken, sondern eher am Ende von Methoden. Jedes cudaMalloc() auf Korrektheit zu prüfen erscheint mir exzessiv. An so ein Macro hatte ich auch schon gedacht aber dabei kommen ja wieder ein Preprozessor und eine globale Methode zum Einsatz was ja mitunter auch wieder "Code smell" ist... ("don't use the preprocessor to do things that your language provides solutions for" )
Allanon // alex

CI-Chef

RANG Deckschrubber

#21 - 03.04 15:44

Ah okay verstehe. Bin hier IT und Interessentechnisch zu weit weg :-) Hardwarenahe Progammierung interessiert mich null, bin da eher der (Web-)Applikationstyp. :-D

Wie gesagt dein Code ist eh schon recht nah an dem Makro dran und ich persönlich verteufle statische Methoden auch nicht. Mein Rat ist halt ein sparsamer Einsatz und Konzentration auf Objekte, statt in "alte Muster" der prozeduralen Entwicklung zu verfallen.

Zum Codesmell: Okay, wenn das so mehr oder weniger vorgegeben ist, oder zumindest Sinn macht, weil vieles unveränderlich schon so heißt, seis drum Du sprichst dabei aber von Kennzeichnung von Klassen. Zumindest in Java macht man das eher mit packages und schafft auf diesem Weg logische Einheiten. Mir fehlt hier aber der Kontext in deinem Fall und ist auch nicht weiter wichtig :-)
Codesmells im Allgemeinen sind wieder ein Thema für sich, das sich meiner Meinung nach am besten durch Erfahrung und Austausch mit anderen vermeiden lässt. In meinem aktuellem Team war es, bevor z.B. sowas hier Usus:
public int anyMethodName() {
    int lokaleVariable = X; // wobei X irgendeine Berechnung sein kann
    return lokaleVariable;
}
code
Jedes Lint-Programm weißt hier darauf hin, dass man sich die lokale Variable sparen kann und ich denke, dass da nahezu alle auch der Meinung sind, dass es wirklich unnütz is. In dem Team war das jedoch voll Absicht. Warum? Bitte festhalten: Weil man es besser debuggen kann. Kein typischer Smell nach Lehrbuch, aber hat mich recht gestört.. Habs einfach alles Refactored und ihnen gezeigt wie man den IntelliJ Debugger benutzt
Ho(r)st

RANG Sucker

#22 - 05.04 18:06

Das mit der Objektorientierung ist die nächste Sache: Soll alles um jeden Preis objektorientierte Features nutzen? Ich hab früher in C programmiert und habe nun Leute kennengelernt die gleich C++ gelernt haben. Ich habe gelegendlich den Eindruck dass diese Leute Dinge umständlicher als nötig machen. Ist natürlich auch wieder eine Frage des Levels aber ich hab z.B. garnichts prinzipielles gegen public variables einzuwenden (anstatt haufenweise get und set Methoden) und versuche Vererbung auch möglichst zu meiden. Mit dieser Aussage macht man sich aber vermutlich auch keine Freunde

Das ist übrigens einer der Rechner auf denen ich arbeite:

http://www.heise.de/newsticker/meldung/Universitaet-Bielefeld-weiht-GPU-Cluster-ein-1422265.html
Allanon // alex

CI-Chef

RANG Lord of Clanintern

#23 - 05.04 23:04

Nette Hardware

Zu OOP: Du stellst defintiv die richtigen Fragen, aber interpretierst sie glaub ich falsch.
Auch in C musste man Programme strukturieren und modularisieren. Durch OOP hat man dafür nun eigentlich nur neue Werkzeuge bekommen.

OOP um jeden Preis? Ja! Aber nicht weil man muss, sondern weil es passt. Meiner Ansicht nach lassen sich OOP-Programme sehr viel besser verstehen, weil sie sich (im Idealfall) nah an der "Natur" oder eben an der Fachlichkeit befinden.
Man muss aber aufpassen, dass man sich dabei nicht verkünstelt, z.B. durch übermäßigen Gebrauch von diversen Pattern etc.

Dein Beispiel mit Public Attributen? Auf keinen Fall! Getter und Setter? It depends..
Was verfolgen wir mit den Sichtbarkeiten und letztlich auch Gettern und Settern? Das Geheimnisprinzip. Wir wollen nicht, dass jeder alles über die Implementierung weiß und wir wollen schon gar nicht, dass jeder diese Details auch noch verändern kann! Soll ein Objekt verändert werden, macht das Objekt das selbst und genau das wird von vielen Programmierern nicht gelebt.
Blödes Beispiel: Bankkonto. Diese hat das Attribut Kontostand, was man auch über einen Getter abfragen können sollte. Auf keinen Fall sollte man das aber direkt setzen können, sondern maximal über deposit oder withdraw manipulieren, oder?
Die Frage muss also eher lauten: brauche ich Getter und Setter wirklich? Ich wage sogar zu sagen: Nein, die brauche ich fast nie! Meine Attribute gehören und bleiben privat und ich gebe möglichst wenig von mir preis.

Es gibt leider oft auch noch die sogenannten DTOs (Daten Transfer Objekte) die für nichts anderes als "Datenaustausch" da sind.. da bin ich voll bei dir und würde gern public attribute verwenden. Jedoch ist hier logischerweise die Syntax für den Zugriff anderes und der Code somit nicht mehr "einheitlich".

Vererbung vermeiden: Sehr gut! Siehe hierzu Clean Code: Favour Composition over Inheritance (FCoI)
Vererbung ist sinnvoll, wenn es auch so "in der Natur" ist. Leider wird in der Praxis viel zu oft aus rein "technischen" Gründen vererbt und damit massiv Komplexität aufgebaut. Ich hab sogar schon erlebt, dass, mangels möglicher Mehrfachvererbung, ganz Vererbungsbäume letztlich dupliziert wurden.
Ho(r)st

RANG Sucker

#24 - 07.04 19:10

Hmm. Ich sehe ein dass in der Webanwendung Objekte essentiell sind. Aber das hat doch auch damit zu tun, dass das Programm möglichst flexibel auf das Verhalten einer "Umgebung" bzw. eines Nutzers reagieren soll, oder?

Bei uns in der Physik werden häufig Algorithmen implementiert, für welche die Randbedingungen beim starten des Programms festgelegt werden und sich im Verlauf des Programms nicht ändern. Die Algorithmen bestehen dann häufig aus Iterationen derselben Prozedur. Von daher ist glaube ich die Problemstellung schon sehr viel "prozeduraler" als in anderen Gebieten. Dennoch setzte ich gerne objektorientierte Features ein. Klassen mit überladenen Operatoren sind zum Beispiel irre praktisch für uns. Eine Multiplikation einer Matrix mit einem Vektor einfach als
outvector = matrix * invector
code

schreiben zu können anstelle von z.B. sowas wie
mat_mult( &outvector, &matrix, &invector )
code

hilft unfassbar dabei einen Algorithmus transparent zu implementieren. Oder auch solche Sachen
determinant = matrix.getDeterminant();
code

sind irre praktisch, insbesondere wenn die Berechnung der Determinanten für verschiedene Klassen von Matrizen unterschiedlich optimiert wird.

Gerade heute habe ich eine Kontainerklasse für Inputparameter eines bestimmten Algorithmus implementiert. Bei der Instanzierung bearbeitet der Konstruktor die Daten noch ein wenig. Erst wollte ich alles privat machen und die Daten mit get() Methoden auslesen. Habe mich am Schluss dann aber doch für public Members entschieden. Wird alles sehr viel einfacher dadurch. Aber ist auch ein vergleichsweise banales Problem. Die Klasse kann nicht wirklich viel.