Motivation bei Privatprojekten (Split aus Diamond of Death)



  • 314159265358979 schrieb:

    Okay, nehmen wir als Beispiel den IRC Bot. (Nicht so groß wie die anderen Projekte und erfordert weniger Basiswissen als KI oder Parsen.)

    Wie würdet ihr an dieses Projekt herangehen?
    Was sollte man im Vorhinein planen?
    Wie sollte man Code organisieren?
    Womit fängt man beim Programmieren an?
    ...

    Also zuerst mal (auch wenn es u.U. ungewohnt ist) nicht mit programmieren anfangen.
    Sondern:

    1. Mache dir klar, was genau du willst, und stelle nicht zu hohe Anforderungen.
    Ich weiß nicht, welche Art Bot es werden soll, ich nehme mal beispielhaft einen Quizbot. Was genau soll dieser Bot können? Quizfragen stellen, mit oder ohne Hinweisen, mit genauer Antwort oder "ähnlichster" Antwort, soll er auf Befehle reagieren und/oder automatisch starten, soll er in mehreren Channels oder gar auf mehreren Servern gleichzeitig aktiv sein? Bleib dabei auf den Boden. Es ist nur ein Quizbot, er braucht kein Scriptinginterface oder Web-Frontent, die Fragen kann er aus einer Textdatei laden und braucht keine Benutzeroferfläche. Sowas kann man später hinzufügen.
    Nimm für den Anfang etwas ganz einfaches: der Bot liest seine Fragen aus einer Datei in der Form "Frage\nAntwort\nFrage\nAntwort...", mit "/quiz" wird eine zufällige Frage gestellt, die Antwort muss bis auf Groß- und Kleinschreibung exakt stimmen. Anschließend wird derjenige gepostet, der die Antwort nannte bzw. nach einer bestimmten Wartezeit wird aufgelöst. Mehr nicht. Diese klaren Anforderungen helfen dir u.a. auch, zu erkennen, wann du fertig bist. Mache dir erst danach über Erweiterungen und Verbesserungen Gedanken.

    2. Stelle ein Design auf, so genau wie möglich.
    Wichtig hierbei ist, dass du den gesamten Bot betrachtest und nicht nur seine Kernkomponente (das Fragenstellen). Viele machen den Fehler, nur Teile zu betrachten, zu denken, dass diese sehr einfach umsetzbar sind, und den Rest zu vergessen. Beziehe also Quizlogik, IRC-Logik, Frageneingabe, Netzwerk usw. mit ein. Wenn er mehrere Channel gleichzeitig bedienen soll, wäre es sicher ratsam, Channel-/Nachrichtenlogik und Quizlogik zu trennen. Mache dir über so etwas Gedanken. Und nimm dir genügend Zeit für das Design, das ist sicher nicht an einem Nachmittag erledigt. Während du das Design entwirfst, kannst du dir auch überlegen, wie man es später einfach erweitern kann. Überteibe aber nicht, du musst ihn nicht soweit erweitern können, dass aus dem Quizbot irgendwann ein Channel-Servicebot wird.

    3. Programmieren
    Jetzt kannst du anfangen zu programmieren. Sicher werden sich während der Programmierung noch Änderungen am Design ergeben, das ist nicht schlimm, da du den Grundstock aber schon durchdesignt hast, sollten sich aber keine großen Probleme ergeben. Du kannst mit der Grundkomponente an, also der eigentlichen Quizlogik anfangen (vielleicht soweit, dass der Quizbot schon auf der Kommandozeile ganz ohne IRC funktioniert) und baust den Rest später drumherum (in der Form, wie du es designt hast), oder aber auch z.B. mit der IRC-Funktionalität oder den Netzwerkkomponenten, das ist eigentlich egal.

    4. Dranbleiben
    Nicht alles wird auf Anhieb funktionieren. Hier ist es jetzt wichtig, dass du nicht nachlässt. Mit den oben genannten Punkten wird dir der Punkt aber leichter fallen.



  • motivationsfördernd ist auch, was zu entwickeln, was es nicht schon 100-mal gibt. Also lieber eine lib für 3d-Grafikbeschleunigung per Auslagerung auf den Tastaturprozessor, als ein Launchpad oder einen Texteditor. Es sei denn, der Texteditor könnte was, was der emacs nicht kann 😃



  • Also ich versuch mich mal an Punkt 1 - sag mir, ob das "zu hohe Anforderungen" sind, wie du sagst.

    Der Bot soll keine Funktionalität eingebaut haben, er soll eine IRC-Schnittstelle für Plugins darstellen. Plugins (.dylib bei mir unter Mac OS) werden dynamisch geladen und können Event-Listener registrieren. Der Bot empfängt Nachrichten, verpackt sie in Events und ruft damit den entsprechenden Handler im Plugin auf.

    Soweit mal die Grundidee.



  • 314159265358979 schrieb:

    Der Bot soll keine Funktionalität eingebaut haben, er soll eine IRC-Schnittstelle für Plugins darstellen. Plugins (.dylib bei mir unter Mac OS)

    Mit der Plugin-Methode wird es aber schwer, ein abstürzendes Plugin daran zu hindern den kompletten Bot zum Absturz zu bringen. Dynamic libraries sind eine ziemlich enge Bindung, vielleicht ist bei IRC-Bot-Plugins eine lockere Bindung eine Überlegung wert.



  • Wie setzt man sowas denn um? Ich kenne nur dynamisch gelinkte Libraries.
    (Kann man da überhaupt Klassen reinwerfen?)



  • 314159265358979 schrieb:

    Wie setzt man sowas denn um? Ich kenne nur dynamisch gelinkte Libraries?

    Eine extrem lockere Bindung wäre zum Beispiel die Plugins über TCP mit dem Bot kommunizieren zu lassen. Dann wäre ein abstürzendes Plugin einfach weg, aber das wär dem Bot egal.

    Allgemein sind separate Prozesse ganz gut, wenn man auf relativ einfache Weise Aufgaben stark trennen möchte. Dann übergibst du das Problem, die Prozesse separat zu halten, nämlich an das Betriebssystem, statt es selber lösen zu müssen.

    Eine Alternative wären zum Beispiel Skript-Sprachen wie lua oder Javascript, die das Plugin in einer Sandbox ausführen können. Sandbox heißt hier, wenn das Plugin fehlerhaft ist, kann der restliche Bot trotzdem weiterlaufen statt automatisch mit abzustürzen. Dann kannst du aber die Plugins nur in dieser Skriptsprache schreiben, was die Plugins wieder etwas einschränkt.

    edit: Einfacher als TCP, falls du unter Linux oder Mac OS X arbeitest, wäre eventuell ein fifo. Dein Bot würde dann für jedes Plugin einen separaten fifo anlegen und darüber mit den Plugins kommunizieren. Die Plugins laufen in separaten Prozessen und beenden sich, sobald der fifo weg ist (d.h. sobald der Bot weg ist).
    Vorteil: Du lernst fifos kennen.
    Nachteil: fifos sind vielleicht nicht die optimale Lösung hier: es gibt dann nämlich immer noch das Problem, was passiert, wenn ein Plugin sich nicht selbst beendet, obwohl der fifo weg ist. Das Problem würde ich aber vielleicht erstmal ignorieren.



  • Ich möchte aber die Möglichkeit, Plugins in C++ zu schreiben. 😉
    Reichen denn nicht Worker-Threads für die Plugins?



  • 314159265358979 schrieb:

    Ich möchte aber die Möglichkeit, Plugins in C++ zu schreiben. 😉
    Reichen denn nicht Worker-Threads für die Plugins?

    Ich hab meinem letzten Posting gerade noch ein edit hinzugefügt.

    Threads können reichen, aber verglichen mit separaten Prozessen ist es schwieriger, das so abzusichern, dass ein abstürzendes Plugin nicht den ganzen Bot mitreißt.

    Mit der TCP-Methode oder der fifo-Methode kannst du die Plugins in jeder Sprache schreiben, nicht nur C++.

    Ein kleiner Nachteil der TCP- und die fifo-Methode ist aber auch, dass das Interface zwischen Bot und Plugin rein seriell ist: Du kannst keine Datenstrukturen direkt übergeben, du kannst nur Strings austauschen. Aber die Datenstrukturen bei einem IRC-Bot sind sowieso eher simpel, da sollte das kein zu großes Problem darstellen.

    Ist natürlich nur ein Vorschlag. Vorteil wäre eben, du würdest dann etwas über fifos oder vielleicht auch andere Methoden der inter-process communication lernen.



  • Achso, ein fifo ist außerdem one-way. Jetzt wo ich drüber nachdenke, ist ein Socket wahrscheinlich doch sinnvoller, weil du vermutlich doch Daten in beide Richtungen austauschen musst, und für jede Richtung ein fifo anlegen ist nicht wirklich toll.



  • Über einen Socket kann ich aber auch nicht so einfach Daten austauschen. Außerdem wird die Thread-Variante eine geringere Latenz haben.



  • Wenn die Plugins eigene Prozesse sind, stehen dir prinzipiell alle Möglichkeiten der IPC offen. Wenn du dich auf C++ beschränken willst, wäre Boost.Interprocess sicher anschauenswert. Dort kannst du über shared memory auch (fast) beliebige Objekte austauschen.

    Prinzipiell ist es aber sowieso sinnvoller, ein Plugin-Grundgerüst zur Verfügung zu stellen, das die Kommunikation mit dem Bot kapselt. Dann kann man auch einfach z.B. auf Sockets umsteigen, indem man einfach das Grundgerüst ändert.



  • 314159265358979 schrieb:

    Außerdem wird die Thread-Variante eine geringere Latenz haben.

    Die Latenz zwischen Bot und Plugin wird in jedem Fall gering genug sein gegenüber der Latenz zwischen Bot und IRC-Server.

    Wenn zwei Prozesse auf demselben PC lokal über ein Socket kommunizieren, ist die Latenz quasi Null.



  • ipsec schrieb:

    Wenn die Plugins eigene Prozesse sind, stehen dir prinzipiell alle Möglichkeiten der IPC offen. Wenn du dich auf C++ beschränken willst, wäre Boost.Interprocess sicher anschauenswert. Dort kannst du über shared memory auch (fast) beliebige Objekte austauschen.

    Shared memory ist doch unter vielen Betriessystemen über das Dateisystem gelöst, wäre das nicht ziemlich langsam gegenüber Sockets?

    ipsec schrieb:

    Prinzipiell ist es aber sowieso sinnvoller, ein Plugin-Grundgerüst zur Verfügung zu stellen, das die Kommunikation mit dem Bot kapselt. Dann kann man auch einfach z.B. auf Sockets umsteigen, indem man einfach das Grundgerüst ändert.

    Gute Idee. Das muss ich mir mal durch den Kopf gehen lassen.



  • 314159265358979 schrieb:

    ipsec schrieb:

    Wenn die Plugins eigene Prozesse sind, stehen dir prinzipiell alle Möglichkeiten der IPC offen. Wenn du dich auf C++ beschränken willst, wäre Boost.Interprocess sicher anschauenswert. Dort kannst du über shared memory auch (fast) beliebige Objekte austauschen.

    Shared memory ist doch unter vielen Betriessystemen über das Dateisystem gelöst, wäre das nicht ziemlich langsam gegenüber Sockets?

    Ich glaube du verwechselst das mit memory-mapped files. Und selbst die sollten schnell genug sein, da sie ja (wie der Name sagt) in den Arbeitsspeicher gemappt sind.



  • 314159265358979 schrieb:

    ipsec schrieb:

    Wenn die Plugins eigene Prozesse sind, stehen dir prinzipiell alle Möglichkeiten der IPC offen. Wenn du dich auf C++ beschränken willst, wäre Boost.Interprocess sicher anschauenswert. Dort kannst du über shared memory auch (fast) beliebige Objekte austauschen.

    Shared memory ist doch unter vielen Betriessystemen über das Dateisystem gelöst, wäre das nicht ziemlich langsam gegenüber Sockets?

    Lokale Sockets bei Unix-ähnlichen Systemen kann man auch über das Dateisystem laufen lassen. Das ist überhaupt nicht langsam, weil "Dateisystem" hier nicht heißt, dass die Festplatte irgendwie daran beteiligt wäre. Das läuft alles im RAM ab.

    "Im Dateisystem" kann man so sehen: Anstelle, dass man lokale listening Sockets nur anhand ihrer Port-Nummer finden kann, kann man Sockets auch sprechende Namen geben, zum Beispiel "/var/run/foo". Auf das Socket namens /var/run/foo zu verbinden ist einfach nur etwas sprechender als auf "localhost:1234" zu verbinden, das ist alles. Von der Geschwindigkeit her gibt sich das alles nichts, zumindest im Rahmen eines IRC-Bots.



  • Na dann ist das ja gut. 🙂
    Bleibt die Frage, ob Sockets oder Shared Memory.

    Sockets haben den Vorteil, dass ich auch in anderen Sprachen Plugins schreiben könnte. Ist shared memory performanter oder hat er andere Vorteile?



  • Privat-Projekte scheitern auch daran, das sie perfektioniert wollen. D.h. man arbeitet ewig lange dran, ohne Ende, weil einem immer was auffällt/einfällt, was verbessert werden kann. Das Problem ist nur, es gibt von Menschen nichts perfektes! 💡

    Da ist es also gut, wenn man z.B. jemand dabei hat oder benennt, der einem auch mal sagt "Jetzt ist aber Schluss! Lass das Programm jetzt endlich mal auf die Menschheit los!". Bei beruflichen Projekten ist da immer der Auftraggeber oder das knappe Budget, das einem einen Schlussstrich vorgibt.



  • 314159265358979 schrieb:

    Na dann ist das ja gut. 🙂
    Bleibt die Frage, ob Sockets oder Shared Memory.

    Sockets haben den Vorteil, dass ich auch in anderen Sprachen Plugins schreiben könnte. Ist shared memory performanter oder hat er andere Vorteile?

    Wenn performanter, dann nicht in einem Ausmaß, das du irgendwie bemerken wirst. Der Hauptvorteil von shared memory ist Bequemlichkeit, da du dort gleich die Objekte austauschen kannst.



  • Was tut man denn, wenn sich ein Plugin aufhängt, und der Bot sich dann beendet? Eigentlich sollte doch der Bot dafür verwantwortlich sein, dass alle Plugins beendet/gekillt werden.

    Edit: Evtl. SIGTERM zu allen Plugins schicken und in den Plugins einen Handler dafür installieren?



  • 314159265358979 schrieb:

    Edit: Evtl. SIGTERM zu allen Plugins schicken und in den Plugins einen Handler dafür installieren?

    SIGTERM beendet auch ohne speziellen Handler das Programm. Wenn du sichergehen willst musst du wahrscheinlich erst SIGTERM senden und dann nach einem timeout SIGKILL, denn SIGTERM kann ignoriert werden.


Anmelden zum Antworten