Kleine Coding-Challenge

  • Allgemein

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Kleine Coding-Challenge

    Hi,

    Im Zuge von einer Vorlesung sollten wir ein Spiel unter gewissen Vorgaben programmieren. Das Ganze hieß Object Calisthenics, was im Endeffekt ein Hardcore-Mode für den Programmierstil ist. Die Regeln lauten wie folgt:
    • Nur eine Einzugsebene pro Methode. D.h. sowas ist nicht erlaubt:

      C#-Quellcode

      1. public int stuff(){
      2. if(bla){
      3. if(bla){
      4. }
      5. }
      6. }


      If-Abfragen müssen wohlgeformt sein, dh. nicht einfach den Einzeiler Syntatic Sugar der jeweiligen Sprache verwenden ;)
    • Keine Verwendung des else Key-words
    • Alle Primitivtypen und Strings müssen in Klassen verpackt werden
    • Nur First class collections
    • Einen Punkt pro Code Zeile, class.bla().bla(); ist nicht zulässig
    • Keine Abkürzungen verwenden
    • Jede Klasse soll weniger als 50 Zeilen haben
    • Keine Klasse darf mehr als 2 Instanzvariablen haben
    • Keine Klasse darf getter und setter haben, oder das jeweilige Sprachequivalent z.B. Properties in VB.NET
    Aufgabe lautete ein einfaches Konsolen Minesweeper zu programmieren, welches das aktuelle Spielfeld in der Form:
    xxxx111xxx
    xxxx1.1xxx
    xxxx111xxx

    darstellt und die Wahl des aufzudeckenden Feldes geschieht über einen einfachen Input mit den Koordinaten des Feldes.

    Dachte, dass es für den ein oder anderen hier vielleicht eine ganz interessante Übung darstellt denn bei dem Ganzen gibt es die ein oder andere Nuss zu knacken :D

    *Topic verschoben*

    8-) faxe1008 8-)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Marcus Gräfe“ ()

    d.h. das hier ist erlaubt?:

    C#-Quellcode

    1. void pseudoIf(bool xy,Action @true,Action @false)
    2. {
    3. if (xy)
    4. @true();
    5. if (!xy)
    6. @false();
    7. }
    8. //oder:
    9. void pseudoIf(bool xy,Action @true,Action @false)
    10. {
    11. if (xy)
    12. {
    13. @true();
    14. return;
    15. }
    16. @false();
    17. }

    und die anderen Einschränkungen sorgen nur dafür, dass der Code unnötig in Klassen aufgeteilt wird?
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    @jvbsl
    Ja es geht beides.

    jvbsl schrieb:

    und die anderen Einschränkungen sorgen nur dafür, dass der Code unnötig in Klassen aufgeteilt wird?


    Ja und Nein. Das Konzept der Challenge ist es ja Paradigmen sauberer Programmierung so hart auf die Spitze zu treiben, dass man zum Nachdenken angeregt wird. Nebenbei bemerkt hat jede der Regeln schon einen "Sinn" im Hinblick auf saubere Programmierung.

    • Keine Verwendung des else Key-words
      Man muss sich Gedanken über mögliche auftretende Fälle machen und nicht grob gesagt "Ach ja und alles andere schmeiss ich da rein, wird schon schief gehen".
    • Alle Primitivklassen und Strings müssen in Klassen verpackt werden
      Das ist hilfreich, denn das macht den Compiler wesentlich mächtiger bei der Entwicklung
      Im Minesweeper Beispiel habe ich z.B. eine Klasse GameField. Anstatt an den Konstruktor einfach zwei ints für die Dimensionen zu geben übergebe ich ein Row und Column Objekt.
      Also statt ​GameField(int, int) ​GameField(Row, Column)
      Vorteil beim letzten ist dass man sich nicht mehr vertun kann welcher Parameter jetzt die Reihe und welcher die Spalte ist, der Kompiler wird sich beschweren wenn man es verdreht. Natürlich kann man argumentieren, dass man das mit Intellisense ja nie falsch machen würde, aber zum einen hat man nicht immer den SuperDuperNonPlusUltra Editor zur Verfügung und zum anderen ist man häufig nie vor Leichtsinnsfehlern gefeit egal wie viel Zusatzhilfe man in ein Tool packt.

    • Keine Abkürzungen verwenden
      Erhöht Lesbarkeit des Codes
    • Jede Klasse soll weniger als 50 Zeilen haben
      Verhindert Schweizertaschenmesser Klassen, z.B. einen Datenbank Wrapper der außerdem noch Emailversendungsfunktionen beinhaltet o.ä.
    • Keine Klasse darf mehr als 2 Instanzvariablen haben
      Verbessert das Nachdenken bezüglich Redundanzen in der Informationsspeicherung, da man gezwungen ist sich Gedanken zu machen ob man die Information wirklich nochmal in der Klasse braucht oder sie anderweitig von draußen reinbekommen kann.
    • Keine Klasse darf getter und setter haben, oder das jeweilige Sprachequivalent z.B. Properties in VB.NET
      Das zu erklären würde mir jetzt zu lange dauern aber hier einen Referenzlink: javaworld.com/article/2073723/…ter-methods-are-evil.html
    Es gilt natürlich anzumerken dass keine der Regeln deinen Codestil auf Gottlevel hebt oder dass optimaler Code immer den Regeln folgt. Vielmehr ist es ein Anfangspunkt darin dein eigenes Codeverhalten zu reflektieren ;)

    8-) faxe1008 8-)
    Nur First class collections
    Alle Primitivklassen und Strings müssen in Klassen verpackt werden

    Das wären dann Arrays in .NET. Wie soll ich ohne Integer Elemente aus Arrays rausholen... geschweige denn eines erstellen?
    Und ich stelle mich jetzt mal absichtlich dumm und frage "was sind primitivklassen?".
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @Bluespide
    Interessant. Die Dokumentation dazu listet ein paar Typen, erklärt aber nicht, warum die jetzt primitiv sind.
    msdn.microsoft.com/en-us/libra…sprimitive(v=vs.110).aspx

    Die Unterscheidung scheint mir aktuell etwas arbiträr. Besonders im Kontext dieser Aufgabe. Ich könnte z.B. Decimal für alles verwenden, weils kein primitiver Datentyp ist. Oder alles über System.Drawing.Point und System.Drawing.Size rechnen, und dann halt nur eine Achse beachten.
    Aber die grundliegende Frage bleibt: Wie soll man überhaupt irgendwas machen, wenn man mit nichts arbeiten kann? Ich kann nichtmal Text auf die Konsole ausgeben, weil Console.WriteLine Strings entgegen nimmt, ich die aber nicht anrühren darf. Hier könnte man arbiträr Ausnahmen einführen, aber das ist ja auch nicht Sinn der Sache, oder?

    Bei der Auflistung der Regeln fehlt irgendwo ein "soweit es möglich ist". Sonst kann man wirklich überhaupt nichts machen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @Niko Ortner: Die Primitive-Typen werden dort tatsächlich nur aufgelistet. "Alles, was hier steht, sind Primitives." Aber der Sinn dahinter, was Primitives sind, dürfte klar sein.

    Niko Ortner schrieb:

    Ich kann nichtmal Text auf die Konsole ausgeben, weil Console.WriteLine Strings entgegen nimmt, ich die aber nicht anrühren darf.
    Wie steht es mit Console.WriteLine(Ausgabe.Text), wobei Text ein Field/ObjectMember vom Typ String in der neugeschaffenen Klasse Ausgabe ist. Erfüllt Regel 2 in Post#1.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    primitivtypen von mir aus. Aber Klassen ist mMn der Falsche Begriff. Schließlich ist int keine Klasse, sondern eher eine struct.
    Und das Beispiel mit Row und Column find ich auch eher meh, denn das sorgt dafür dass der Code schlecht lesbar wird GetField(new Row(1),new Column(2)), oder man macht nen impliziten Converter->dann kann man aber gleich ints direkt verwenden^^
    Row und Column halten nur einen int als Information und können auf diesen int nicht wirklich etwas neues machen(was mir gerade einfällt) also ist eine Abstraktion eher hinderlich als hilfreich.
    Mensch ich hab manchmal Methoden die länger als 50 Zeilen sind, sind die deshalb schlecht? Ich glaube nicht :P
    durch unnötiges Auseinanderziehen werden Dinge oft schwerer lesbar(und auch noch imperformanter)
    Nicht mehr als 2 Instanzvariablen soll inwiefern Redundanzen verhindern? Wie soll ich z.B. Model View und Controller instanzieren? Kann ich ja nicht in ner Klasse zusammenfassen :P In ner Methode? meh
    Keine getter und setter sorgt nur dafür, dass ich Dinge Public machen muss, die Argumentationen in dem Link sind mMn auch dämlich. Ich weiß nicht wer auf die Idee kommen würde bei Typänderung eines getters durch casting das Problem zu fixen. Abgesehen davon dass es var in C# oder auto in C++ gibt. Er bietet außerdem keine Alternative(fields sind public schließlich auch böse). Aber immerhin sagt er, dass es im nur ums minimieren der getter und setter geht nicht ums entfernen-> Regel sagt aber ganz ohne. Aber wie gesagt Daten die nach außen müssen brauchen getter und die gesetzt werden können müssen eben einen setter. Und ansonsten wundern mich Argumentationen eines Java Entwicklers gegen irgendetwas sowieso nicht :P
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    *Primitive* wird verwendet im Zusammenhang mit Elementar.
    Z.B. gibt es MeasPrimitive, wo das Anmessen eines Punktes, einer Kante, eines Bogens, eines Kreises usw. definiert sind.
    Einen komplexen Messablauf kann man dann einfach als Aufeinanderfolge solcher MeasPrimitiven gestalten.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Niko Ortner schrieb:

    was sind primitivklassen?".


    Huch mein Fehler das muss primitiv Typen heißen ^^ .

    Niko Ortner schrieb:

    Ich kann nichtmal Text auf die Konsole ausgeben, weil Console.WriteLine Strings entgegen nimmt, ich die aber nicht anrühren darf.


    Ganz einfach du gibst z.B. dem GameField eine printState() Methode ;)

    jvbsl schrieb:

    Methoden die länger als 50 Zeilen sind, sind die deshalb schlecht


    Nö sagt keiner - man soll sich nur bewusst sein was man eigentlich treibt ;)

    jvbsl schrieb:

    Aber wie gesagt Daten die nach außen müssen brauchen getter und die gesetzt werden können müssen eben einen setter.


    Nein, nicht zwangsläufig. Wenn man es darauf anlegt kann man immer einen Weg finden es zu vermeiden - z.B. indem man Objekte mit Methoden anstatt einfach nur losgelöste Infos übergibt und diese dann seinerseits an benötigter Stelle aufruft ;)

    8-) faxe1008 8-)

    faxe1008 schrieb:

    Wenn man es darauf anlegt kann man immer einen Weg finden es zu vermeiden
    Ja, man kann immer einen Weg finden, alles zu vermeiden.

    Nur bezweifel ich, dass man durch derlei Workarounds, die ausser iwelche Lehrer-Vorgaben zu befriedigen keinen Sinn haben, also dass man dadurch lernt, sauberer zu coden.
    Hi
    sehe ich anders. Es fordert, dass man sich Gedanken über die Gestaltung des Quellcodes macht. Die Regeln an sich sind mit Sicherheit zwar keine Instruktion zu elegantem Code, rufen aber unverweigerlich die Frage hervor "wie kann ich das so lösen, dass die Regeln erfüllt werden?" und diese fordert Reflexion über den Code, wodurch ein Grundelement der Logik gefördert wird: Dinge anders zu betrachten, um die Ecke zu denken, ein "logisches Umfeld" um etwas schaffen - und zusätzlich auch "warum wurde das dann wohl so gemacht?".
    Ich halte es für eine ganz gute Idee, solange man nicht mich selbst mit dieser Aufgabe konfrontiert.

    Viele Grüße
    ~blaze~