Fehlersuche

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@NoPy: Ich verstehe es immer noch nicht. Einerseits möchtest du eine polymorphe Operation anwenden auf Dinge, die diese Operation nicht bereitstellen und deswegen adaptiert werden müssen. So weit, so OOP. Andererseits vermisst du die statische Typprüfung von Methodenargumenten, was mit der ersten Fragestellung gar nichts zu tun zu haben scheint. Was ist denn nun dein Problem?

Und: Python ist auch mehr LISP als Pascal. Pascal und C sind eh dieselbe Sprache.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

pillmuncher hat geschrieben:@NoPy: Ich verstehe es immer noch nicht. Einerseits möchtest du eine polymorphe Operation anwenden auf Dinge, die diese Operation nicht bereitstellen und deswegen adaptiert werden müssen. So weit, so OOP. Andererseits vermisst du die statische Typprüfung von Methodenargumenten, was mit der ersten Fragestellung gar nichts zu tun zu haben scheint. Was ist denn nun dein Problem?

Und: Python ist auch mehr LISP als Pascal. Pascal und C sind eh dieselbe Sprache.
Noch mal: Ich will keinen Glaubenskrieg anfangen über Pascal/C/LISP/Python/Prolog/Forth/Basic
Alle haben Gemeinsamkeiten und Unterschiede, Vorteile und Nachteile

Ich will schlicht lernen, wie ich am effizientesten python nutze, um meine Probleme zu lösen. Es ist mir letztlich egal, wie das oder die Konzepte heißen und funktionieren.
Ich muss dazu die Konzepte lernen - das ist mir ganz klar.
Ich muss meine Aufgaben lösen - das sollte Euch klar sein.

Ich habe einen anderen Background und vor diesem Hintergrund bin ich einiges an Features gewöhnt, die nun zwangsläufig wegfallen. Dafür gewinne ich Freiheiten und neue Features. So ist das eben.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@NoPy: Um dir helfen zu können, muss ich wissen, welches Problem du hast. Ich habe es bis jetzt nicht verstanden.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

pillmuncher hat geschrieben:@NoPy: Um dir helfen zu können, muss ich wissen, welches Problem du hast. Ich habe es bis jetzt nicht verstanden.
  • -Das ursprüngliche Thema "Fehlersuche" bezog sich darauf, dass ein von mir benutztes Modul (openpyxl) generatoren zurückgeliefert hat, so dass für mich virtuell die Elemente nach dem ersten Ansehen verschwanden ("Burn after Reading").
    -Das führte im Weiteren dazu, dass ich mich informieren wollte, wie man python- like damit umgeht, wenn die eigenen Module etwas verwenden möchten, aber nur prinzipiell und nicht genau dazu passen.
    -Die Antwort von BlackJack war letztlich: Lieber Wrapperklassen, die die verwendeten Module kapseln, als die benutzenden Klassen variabel zu gestalten.
    -Seit dem versuche ich, die Mechanismen zu lernen, wie man python- like wrapper- Klassen baut.
Eigentlich ist für mich die Frage mittlerweile beantwortet (mal abgesehen von meiner letzten Reaktion auf die Antwort von BlackJack).
Im Moment versuche ich aus den vielen Versuchen, mir die Sprache python besonders schmackhaft zu machen, mir die Krumen Information herauszupicken, mit denen ich etwas anfangen kann.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@NoPy: Zur Frage nach den Generatoren: tatsächlich betrifft das Iteratoren. Generatoren sind manche Dinge, die Iteratoren erzeugen. Der Zusammenhang ist dieser. Generatorfunktionen sind Funktionen oder Methoden, die wenigstens ein yield-Statement haben. Generatorausdrücke sehen aus wie List Comprehensions, außer dass sie in runde statt eckige Klammern eingeschlossen sind. Wenn ich eine Generatorfunktion ausführe, erhalte ich als Ergebnis einen Generator zurück. Wenn ich einen Generatorausdruck auswerte, ebenfalls. Generatoren implementieren das Iterator-Protokoll, dh., sie besitzen eine __iter__() und eine __next__() Methode (next() in Python2.x). Generatoren haben zusätzlich noch weitere Methoden: send() und close() und throw(). Objekte, die eine __iter__() Methode haben, implementieren das Iterable-Protokoll. Wir haben also eine Hierarchie: Iterable <-- Iterator <-- Generator. Das ist keine Vererbungshierarchie, denn wir arbeiten hier mit Duck-Typing, nicht mit Vererbung. Deswegen nennen wir es auch Protokoll, und nicht Basisklasse. Jedes Objekt kann jedes beliebige Protokoll implementieren, wenn der Programmierer das so festlegt (indem er es so programmiert).

Iteratoren haben also genau zwei Methoden: __iter__() und __next__(). Die erste ist dafür da, damit man auf einem Iterator it wieder iter(it) aufrufen kann. Das braucht man manchmal. it wird also von iter() als Iterable verwendet. Die zweite Methode dient zum eigentlichen iterieren. In einer for-Schleife wird sie implizit aufgerufen, aber das kann man auch explizit machen, indem man zB. elem = next(it) schreibt. Die Funktion next() könnte man, wenn es sie nicht schon gäbe, so implementieren:

Code: Alles auswählen

def next(iterator):
    return iterator.__next__()
Analog dazu ruft iter(it) einfach it.__iter__() auf, aber wenn das fehlschlägt, versucht iter() über den Subscriptionsoperator an die Elemente zu kommen. Das interessiert uns hier aber nicht.

Man verwendet Generatoren bevorzugt dann, wenn das Berechnen der Elemente sehr teuer ist oder die Elemente sehr groß sind. Oder wenn es sehr viele Elemente sind, so dass eine Liste mit allen Elementen sehr viel Speicher benötigen würde. Oder in einem Fall wie diesem: Nehmen wir an, ich wollte einen Iterator haben, der Daten aus einer Netzwerkverbindung liefert, also Daten, die irgendein anderer Computer sendet. Nehmen wir irgendein simples Protokoll an, wo nur Strings gesendet werden, und ein '\n' sei der Trenner zwischen zwei Strings und '\0' signalisiert das Ende der Daten. Nach senden von '\0' wird die Verbindung geschlossen. Ich könnte das so implementieren:

Code: Alles auswählen

class NetIter:

    def __init__(self, host, port):
        self.host = host
        self.port = port

    def __iter__(self):
        connection = some_connect_function(self.host, self.port)
        while True:
            data = ''
            while True:
                data += connection.recv()
                if data[-1] == '\n':
                    yield data[:-1]
                    break
                elif data[-1] == '\0':
                    yield data[:-1]
                    return
Iter ist hier als Generatorfunktion implementiert. Angenommen, ich würde sowas machen:

Code: Alles auswählen

netit = NetIter('localhost', 12345)
xs = list(netit)
ys = list(netit)
Würdest du da erwarten, dass xs und ys dieselben Daten enthalten? Wenn nein, warum dann bei openpyxl? Dass die Daten über das Netzwerk kommen, ist dabei übrigens völlig unerheblich. Wichtig ist dagegen, was das Iterator-Protokoll garantiert: dass ein Element nach dem anderen geliefert wird, bis es entweder keine mehr gibt oder keine mehr nachgefragt werden.

Ein völlig anderes Problem ist, was ich mit den gelieferten Elementen anstelle. Sequentiell aus allen Elementen einer Struktur eine neue, evtl. nicht-isomorphe Struktur zu erzeugen, ist ein left fold. Den kann ich mittels Rekusion erzeugen, wie du das in Dump() getan hast, oder mittels einer for-Schleife (evtl. + Stack) oder mittels reduce(). Einfach ist es, wenn alle Elemente auf dieselbe Weise behandelt werden müssen. Schwieriger, wenn man einen Dispatch durchführen muss. Der Dispatch kann durch Konditionale (if-Statements) durchgeführt werden, aber zB. auch dadurch, dass ich mir Pythons Methoden-Dispatch zunutze mache. Guido nannte das AFAIR mal das Command Dispatch Pattern:

Code: Alles auswählen

class Foo:
    pass

class Bar:
    pass

class Dispatcher:

    def dispatch_Foo(self, elem):
        print 'Foo found!', elem

    def dispatch_Bar(self, elem):
        print 'Bar found!', elem

    def dispatch(self, elem):
        getattr(self, 'dispatch_' + type(elem).__name__)(elem)

d = Dispatcher()
d.dispatch(Foo())
d.dispatch(Bar())
Das hat aber dasselbe Problem wie explizite if-Abfragen und Visitors. Man muss immer, wenn ein neuer Fall dazukommt, alle Stellen ändern, wo man auf den neuen Fall reagieren muss. Aber das ist kein Problem von Python oder dynamisch typisierten Sprachen, sondern von allen mir bekannten Sprachen. Auch statische Typisierung hilft hier nicht, denn es gibt keine automatische Typprüfung der Art "Oh, hier ist was neues, da generiere ich mal automatisch den Code, den der Programmierer haben möchte, um mit dem neuen Dings umzugehen." Und auch mit Iteratoren hat das nichts zu tun, denn für diese Problemstellung ist es wurst, ob die Daten von einem Iterator geliefert werden oder aus einer Liste oder sonstwo her stammen. Entweder die Elemente haben dasselbe polymorphe Interface, wodurch man den Dispatch geschenkt bekommt, oder man muss den Dispatch selber durchführen, mit den og. Problemen. Manchmal muss man dazu Adapter (welche du Wrapper nennst) schreiben. Auch das hat weder etwas mit dynamischem vs. statischem Typing zu tun, noch mit Iteratoren.

Schlussendlich: mir ist immer noch nicht klar, wo dein Problem liegt. Abgesehen von dem oben gezeigten Command Dispatch Pattern, das so in Bondage & Discipline Sprachen nicht implementierbar ist, hat das alles nichts mit Python zu tun, sondern nur ganz allgemein mit OOP.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

pillmuncher hat geschrieben:Würdest du da erwarten, dass xs und ys dieselben Daten enthalten? Wenn nein, warum dann bei openpyxl? Dass die Daten über das Netzwerk kommen, ist dabei übrigens völlig unerheblich. Wichtig ist dagegen, was das Iterator-Protokoll garantiert: dass ein Element nach dem anderen geliefert wird, bis es entweder keine mehr gibt oder keine mehr nachgefragt werden.
Ganz ehrlich habe ich erwartet, dass mich die interne Implementation nicht interessieren muss. Wenn ich 2 mal hintereinander in ein Objekt hineinsehe, dann hätte ich gern 2 mal das gleiche Ergebnis. Ob dazu erneute eine Netzwerkverbindung etabliert werden muss oder was auch immer wäre mir egal...
pillmuncher hat geschrieben:Das hat aber dasselbe Problem wie explizite if-Abfragen und Visitors. Man muss immer, wenn ein neuer Fall dazukommt, alle Stellen ändern, wo man auf den neuen Fall reagieren muss. Aber das ist kein Problem von Python oder dynamisch typisierten Sprachen, sondern von allen mir bekannten Sprachen. Auch statische Typisierung hilft hier nicht, denn es gibt keine automatische Typprüfung der Art "Oh, hier ist was neues, da generiere ich mal automatisch den Code, den der Programmierer haben möchte, um mit dem neuen Dings umzugehen."
Schon klar, keine Ahnung, woher der Rechtfertigungsdruck kommt. Der einzige Unterschied zwischen statisch und dynamisch typisierten Sprachen an dieser Stelle ist der, dass der Compiler aufschreit, wenn der, dessen Klasse ich benutze, die Typen der Schnittstelle verändert hat. Wenn beispielsweise die Zellen nicht als Liste, sondern als Dictionary oder Generator ausgeliefert würden. Aber wie gesagt, ich will ja python lernen ...
pillmuncher hat geschrieben:Schlussendlich: mir ist immer noch nicht klar, wo dein Problem liegt. Abgesehen von dem oben gezeigten Command Dispatch Pattern, das so in Bondage & Discipline Sprachen nicht implementierbar ist, hat das alles nichts mit Python zu tun, sondern nur ganz allgemein mit OOP.
Das stimmt nicht ganz, wenn ich es darauf anlege, könnte ich beispielsweise auch Funktionen als Parameter benutzen und so den Patch quasi mitliefern. Aber auch das - ich brauch keinen Schwanzlängenvergleich zwischen python und irgend einer anderen Programmiersprache.

Wenn ich eine Frage der Form:
Wie mache ich etwas, das in BlaBlaBla so geht, mit python?

Dann fände ich folgende Arten von Antworten chic:
1. Das geht so:
2. Das macht man in python ganz anders, nämlich:
3. Das geht in python gar nicht. Lass Dir etwas anderes einfallen.

Das Infragestellen des Problems ist meist nervig und in der Regel wenig zielführend. Und ganz ehrlich PEP8 und PEP20 sind als Styleguide etwas dürftig.

Die Antwort von Dir war durchaus hilfreich, da ich ein Konstrukt von Python jetzt etwas besser verstanden habe (Command Dispatch Pattern)
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@NoPy: um konkrete Antworten zu geben, muß man das Problem verstanden haben. Du hast angefangen irgendwelche abstrakten Probleme zu diskutieren, von Raumschiffen und Zimmern, wo die Antwort immer die selbe ist, dass man ein einheitliches Interface für alle Zimmer braucht. Python erzwingt halt nur nicht, wie andere OOP-Sprachen, einen gemeinsamen Vorfahren mit abstrakten Methoden. Dass es das nicht erzwingt, heißt aber nicht, dass man kein einheitliches Interface haben kann. Aber wie schon öfter geschrieben, mit großer Freiheit kommt auch die Verantwortung, selbst zu Denken und nicht alles den Compiler machen zu lassen.

Ganz ehrlich, Deine Erwartungen sind reichlich naiv. Würdest Du bei einem File-Handle erwarten, dass, wenn man die Datei einmal gelesen hat, das System automatisch wieder an den Anfang springt?

Wenn Du in Java refactoring dadurch machst, dass Du das Interface änderst und schaust, wo der Compiler überall schreit, dann hast Du dort schon etwas falsch gemacht. Wenn Du bisher ohne Tests ausgekommen bist und angeblich nur einmal im Jahr einen Fehler machst, dann passen Deine Programme auf einen PostIt-Zettel.

Niemand behauptet hier, Python wäre anderen Sprachen überlegen, aber da Du ja anscheinend Erfahrung mit anderen Programmiersprachen hast, versuchen wir hier Gemeinsamkeiten und Unterschiede zwischen den Sprachen herauszustellen. Von Machogehabe kann ich hier nichts finden.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

Sirius3 hat geschrieben:@NoPy: um konkrete Antworten zu geben, muß man das Problem verstanden haben. Du hast angefangen irgendwelche abstrakten Probleme zu diskutieren, von Raumschiffen und Zimmern, wo die Antwort immer die selbe ist, dass man ein einheitliches Interface für alle Zimmer braucht. Python erzwingt halt nur nicht, wie andere OOP-Sprachen, einen gemeinsamen Vorfahren mit abstrakten Methoden. Dass es das nicht erzwingt, heißt aber nicht, dass man kein einheitliches Interface haben kann. Aber wie schon öfter geschrieben, mit großer Freiheit kommt auch die Verantwortung, selbst zu Denken und nicht alles den Compiler machen zu lassen.
Natürlich, das ist mir ja nicht neu. Die Frage ist doch aber nicht, warum oder pauschal, wie. Es muss doch ein dazwischen geben wischen PEP8/PEP20 als megaabstrakt und jedem konkreten Sachverhalt. Ein abstraktes Beispiel, mit dem jeder aus der Anschauung heraus etwas anfangen kann als Beispiel hilft zumindest mir sehr. Und die darauf bezogenen Antworten waren für mich auch sehr hilfreich.
Sirius3 hat geschrieben:Ganz ehrlich, Deine Erwartungen sind reichlich naiv. Würdest Du bei einem File-Handle erwarten, dass, wenn man die Datei einmal gelesen hat, das System automatisch wieder an den Anfang springt?
Nein, natürlich nicht. Aber wenn ich das kapsle in eine Funktion/Klasse/was auch immer, die heißt "Dateiheader", dann würde ich schon erwarten, dass es sich nicht um ein EinmalLesen- Objekt handelt. Aber das steht doch schon lange nicht mehr zur Debatte, die Antwort habe ich doch schon am Anfang bekommen.
Sirius3 hat geschrieben:Wenn Du in Java refactoring dadurch machst, dass Du das Interface änderst und schaust, wo der Compiler überall schreit, dann hast Du dort schon etwas falsch gemacht. Wenn Du bisher ohne Tests ausgekommen bist und angeblich nur einmal im Jahr einen Fehler machst, dann passen Deine Programme auf einen PostIt-Zettel.
Was Du alles weißt...
Natürlich habe ich Tests gemacht und natürlich sind gelegentlich dabei auch kleinere Fehlerchen aufgetreten. Aber keine nennenswerten konzeptionellen, warum auch. In statisch typisierten Sprachen muss ich aber eben nicht auf Schnittstellen testen, ganz einfach. Das testet der Compiler halt für mich. Und natürlich nutze ich die Fähigkeiten meiner Werkzeuge aus, um schneller zu entwickeln. Ist nicht besser, nur anders.
Sirius3 hat geschrieben:Niemand behauptet hier, Python wäre anderen Sprachen überlegen, aber da Du ja anscheinend Erfahrung mit anderen Programmiersprachen hast, versuchen wir hier Gemeinsamkeiten und Unterschiede zwischen den Sprachen herauszustellen. Von Machogehabe kann ich hier nichts finden.
Ist nett gemeint, aber für mich nicht so direkt zielführend. Ich habe schon eine grundlegende Vorstellung von den Gemeinsamkeiten und Unterschieden. Was ich suche, sind praktikable Richtlinien zum richtigen Einstieg. Irgend etwas zwischen PEP* und wie mache ich eine Schleife von 1 bis 100. Und mir persönlich hilft das Raumschiffbeispiel sehr, kannst Du glauben.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

NoPy hat geschrieben:Ganz ehrlich habe ich erwartet, dass mich die interne Implementation nicht interessieren muss. Wenn ich 2 mal hintereinander in ein Objekt hineinsehe, dann hätte ich gern 2 mal das gleiche Ergebnis. Ob dazu erneute eine Netzwerkverbindung etabliert werden muss oder was auch immer wäre mir egal...
Du möchtest also eine Garantie in der Programmiersprache dafür, dass die Daten, die ein anderer Computer über das Netz schickt, jedesmal dieselben sind, wenn du zu ihm eine Verbindung aufbaust. Ok. Angenommen, die Daten stammen von einer Benutzereingabe, sagen wir aus einem Chat-Programm. Dann möchtest du also eine Garantie in der Programmiersprache dafür, dass ein anderer Benutzer immer dieselben Sachen eintippt, wenn dein Programm das so vorsieht. Ja, klar.

Was du außerdem übersiehst, ist dass das Ergebnis tatsächlich immer dasselbe ist. Du hast einen Iterator, also ein Objekt mit einem internen Zustand, und wenn der abgearbeitet ist, hast du immer noch denselben Iterator, nur mit einem anderen internen Zustand. Iteratoren funktionieren in allen mir bekannten Sprachen auf genau diese Weise. Wenn du unbedingt willst, dass Objekte keine internen veränderlichen Zustände haben, musst du in einer Sprache programmieren, die das sicherstellt. Haskell etwa.
NoPy hat geschrieben:ich brauch keinen Schwanzlängenvergleich zwischen python und irgend einer anderen Programmiersprache.

Wenn ich eine Frage der Form:
Wie mache ich etwas, das in BlaBlaBla so geht, mit python?

Dann fände ich folgende Arten von Antworten chic:
1. Das geht so:
2. Das macht man in python ganz anders, nämlich:
3. Das geht in python gar nicht. Lass Dir etwas anderes einfallen.
Wenn du ein konkretes Problem hast, kann man konkret helfen. Deine Problembeschreibungen sind aber viel zu abstrakt, um konkret beantwortet zu werden.

Achja: Schwanzlängenvergleich. Liest du eigentlich, was ich schreibe? Ich habe nirgends behauptet, Python sei viel superer als alle anderen Sprachen. Ich habe mich lediglich über Bondage & Discipline Sprachen lustig gemacht, aber auch das ist kein Schwanzlängenvergleich. Überall sonst habe ich darauf hingewiesen, dass die genannten Probleme alle genannten Sprachen betreffen. Das ist ein toller Schanzlängenvergleich, wo der Vergleicher sagt: "Hey, meine Sprache ist die superste von allen, weil sie genauso funktioniert, wie alle anderen."
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

NoPy hat geschrieben: Natürlich habe ich Tests gemacht und natürlich sind gelegentlich dabei auch kleinere Fehlerchen aufgetreten. Aber keine nennenswerten konzeptionellen, warum auch.
Öh... das kann ich nicht glauben, oder wir sind doch wieder bei extrem kleinen Programmen! Die Art der Typisierung hat gemein hin nichts mit fachlicher oder technischer Konzeption zu tun ;-) Insofern ist das bei allen Sprachen *gleich schwer* und vor allem gleich Fehler anfällig!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@NoPy: ich habe den Eindruck, dass Du noch nie wirkliche Tests geschrieben hast. Konzeptionelle Fehler findet man mit Testcases auch nicht.
NoPy hat geschrieben:In statisch typisierten Sprachen muss ich aber eben nicht auf Schnittstellen testen, ganz einfach.
In Python wird auch nicht die Schnittstelle getestet, sondern nur, ob sinnvolle Eingaben sinnvolle Ergebnisse liefern und falls gefordert, ob unsinnvolle Eingaben sinnvolle Fehlermeldungen.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

Hyperion hat geschrieben:
NoPy hat geschrieben: Natürlich habe ich Tests gemacht und natürlich sind gelegentlich dabei auch kleinere Fehlerchen aufgetreten. Aber keine nennenswerten konzeptionellen, warum auch.
Öh... das kann ich nicht glauben, oder wir sind doch wieder bei extrem kleinen Programmen! Die Art der Typisierung hat gemein hin nichts mit fachlicher oder technischer Konzeption zu tun ;-) Insofern ist das bei allen Sprachen *gleich schwer* und vor allem gleich Fehler anfällig!
Noch mal: Ich weiß, dass statische Typisierung nichts mit dem Konzept zu tun haben. Es erleichtert nur das Arbeiten, weil man sich eben darum nicht zu kümmern braucht.
Es ist eben eine erzwungene Definition eines Schnittstellenbestandteiles. Aber wie gesagt, das ist Wurst, in python ist es halt nicht so. Und gut.

Die Konzeptionierung findet doch normalerweise VOR der Erstellung des Programmes statt. Wenn es fertig ist, muss man nur noch umsetzen. Da sich die meisten meiner letzen Anwendungen auf Datenbanken bezogen (im Wesentlichen auf Oracle) und dadurch schon einiges an Rahmen vorgegeben war, war das keine Hexerei. Es waren eher Details, an denen man verschiedene Varianten ausprobiert hat.
Ich hatte zumindest nicht das Gefühl, dass es sich bei meinen/unseren Programmen um Mikro- Programme gehandelt hat. Woran machst Du das fest? An Quellzeilen? An Mannjahren? An Funktionalitäten? Tut mir leid, bislang war das Konzept wirklich selten mein Problem. Vielleicht auch deshalb, weil ich auf das Konzept idR frühzeitig Einfluss hatte.
Die meisten Sorgen hatte ich wirklich damit, Fremdmodule einzubinden und auszuprobieren, wie diese funktionieren - gerade deshalb, weil eben nicht immer das dokumentiert war, was ich wissen wollte. Wie ich meinen Mist baue, weiß ich schon - zumindest, was die Werkzeuge anging, mit denen ich seit Jahren/Jahrzehnten zu tun hatte.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also da frage ich mich schon, ueber was fuer Programme wir hier reden. In meiner Praxis (hauptsaechlich Python, Java, C++, also unabhaengig vom Typsystem) hat so gut wie nie ausser fuer triviale Skripte eine Planung am gruenen Tisch eine dauerhafte Grundlage geliefert.

Was nicht heissen soll, dass man planlos drauf los programmieren soll. Aber Softwareentwicklung ist doch grundsaetzlich ein iteratives Geschaeft - und da veraendern sich Anforderungen an Komponenten/Architektur, die eben *nicht* vorher antizipiert werden konnten.

Und wenn du gleichzeitig das Beduerfnis verspuerst, Dritthersteller-Software weg zu abstrahieren, weil du sie austauschen musst/willst, dann haben deine Programme doch offensichtlich auch Zyklen in ihrer Entwicklung.

Dabei hast du noch nie erlebt, dass Konzepte adaptiert werden mussten?
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

pillmuncher hat geschrieben:
NoPy hat geschrieben:Ganz ehrlich habe ich erwartet, dass mich die interne Implementation nicht interessieren muss. Wenn ich 2 mal hintereinander in ein Objekt hineinsehe, dann hätte ich gern 2 mal das gleiche Ergebnis. Ob dazu erneute eine Netzwerkverbindung etabliert werden muss oder was auch immer wäre mir egal...
Du möchtest also eine Garantie in der Programmiersprache dafür, dass die Daten, die ein anderer Computer über das Netz schickt, jedesmal dieselben sind, wenn du zu ihm eine Verbindung aufbaust. Ok.
Angenommen, die Daten stammen von einer Benutzereingabe, sagen wir aus einem Chat-Programm. Dann möchtest du also eine Garantie in der Programmiersprache dafür, dass ein anderer Benutzer immer dieselben Sachen eintippt, wenn dein Programm das so vorsieht. Ja, klar.
Nein, da hab ich mich wohl missverständlich ausgedrückt. Ich erwarte das nicht von der Programmiersprache, sondern ich hätte mir das vom Entwickler gewünscht.
Für mich existiert durchaus ein Unterschied zwischen einem Chat oder Daten, die über das Netzwerk fließen und einer Excel- Tabelle. Rein von der Nutzung sind Excel- Dateien nicht so gedacht, dass mehrere gleichzeitig an diesen arbeiten (ich weiß, dass es geht. Aber es ist keinerlei Rechtemanagement und Transaktionsprotokoll implementiert. Excel macht bei Kollisionen das, was es für vernünftig hält). Somit ist Excel für mich tatsächlich etwas, was sich nur dann ändern sollte, wenn ICH es ändere. Daher hätte ich etwas anderes erwartet, als einen Generator/Iterator o.ä. Aber wie gesagt, das ist abgehakt.
pillmuncher hat geschrieben:Was du außerdem übersiehst, ist dass das Ergebnis tatsächlich immer dasselbe ist. Du hast einen Iterator, also ein Objekt mit einem internen Zustand, und wenn der abgearbeitet ist, hast du immer noch denselben Iterator, nur mit einem anderen internen Zustand. Iteratoren funktionieren in allen mir bekannten Sprachen auf genau diese Weise. Wenn du unbedingt willst, dass Objekte keine internen veränderlichen Zustände haben, musst du in einer Sprache programmieren, die das sicherstellt. Haskell etwa.
NoPy hat geschrieben:ich brauch keinen Schwanzlängenvergleich zwischen python und irgend einer anderen Programmiersprache.

Wenn ich eine Frage der Form:
Wie mache ich etwas, das in BlaBlaBla so geht, mit python?

Dann fände ich folgende Arten von Antworten chic:
1. Das geht so:
2. Das macht man in python ganz anders, nämlich:
3. Das geht in python gar nicht. Lass Dir etwas anderes einfallen.
Wenn du ein konkretes Problem hast, kann man konkret helfen. Deine Problembeschreibungen sind aber viel zu abstrakt, um konkret beantwortet zu werden.

Achja: Schwanzlängenvergleich. Liest du eigentlich, was ich schreibe? Ich habe nirgends behauptet, Python sei viel superer als alle anderen Sprachen. Ich habe mich lediglich über Bondage & Discipline Sprachen lustig gemacht, aber auch das ist kein Schwanzlängenvergleich. Überall sonst habe ich darauf hingewiesen, dass die genannten Probleme alle genannten Sprachen betreffen. Das ist ein toller Schanzlängenvergleich, wo der Vergleicher sagt: "Hey, meine Sprache ist die superste von allen, weil sie genauso funktioniert, wie alle anderen."
Es tut mir leid, wenn ich einen Nerv getroffen habe, das wollte ich nicht. Ich fand deine Antworten völlig in Ordnung, das ist ein klares Danke Schön.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

__deets__ hat geschrieben:Also da frage ich mich schon, ueber was fuer Programme wir hier reden. In meiner Praxis (hauptsaechlich Python, Java, C++, also unabhaengig vom Typsystem) hat so gut wie nie ausser fuer triviale Skripte eine Planung am gruenen Tisch eine dauerhafte Grundlage geliefert.
Tut mir leid, aber das sollte sie schon.
__deets__ hat geschrieben:Was nicht heissen soll, dass man planlos drauf los programmieren soll. Aber Softwareentwicklung ist doch grundsaetzlich ein iteratives Geschaeft - und da veraendern sich Anforderungen an Komponenten/Architektur, die eben *nicht* vorher antizipiert werden konnten.
Natürlich. Aber auch dafür steht das Konzept, das umzusetzen ist, BEVOR man mit der Umsetzung anfängt. Wenn man es am grünen Tisch nicht entscheiden kann, dann bietet sich ein Prototyping an. Und das habe ich in der Regel so quick and dirty programmiert, dass ich gar nicht nachnutzen möchte. Das Ziel vom Prototyping ist ja, dass man sich anhand dessen abstimmen kann. Und natürlich gibt es da auch punktuell Dinge/Objekte etc., die angepasst werden müssen. Aber ein Auto bleibt ein Auto, bislang war es höchst selten, etwas zu verändern, was nicht durch erweitern zu lösen war. Aber wie gesagt, mag sein, dass mein Betätigungsumfeld anders ist. Ich schreibe Datenbanksoftware. Es ist teuer, diese Daten zu erheben, daher tut man sich schwer damit, die Strukturen der Daten umzuwälzen, weil entweder eine Migration danach nicht möglich ist - Datenverlust - oder eine Migration möglich ist - dann ist der Umbau oft unnötig.
__deets__ hat geschrieben:Und wenn du gleichzeitig das Beduerfnis verspuerst, Dritthersteller-Software weg zu abstrahieren, weil du sie austauschen musst/willst, dann haben deine Programme doch offensichtlich auch Zyklen in ihrer Entwicklung.

Dabei hast du noch nie erlebt, dass Konzepte adaptiert werden mussten?
Natürlich müssen an einer Software im Laufe des Lebens dieser Anpassungen vorgenommen werden. Beispielsweise, weil sich Datenbank- oder Betriebssystem- Versionen ändern. Aber bislang mussten noch keine Konzepte in Größenordnungen angepasst werden. Wie gesagt, ich bilde eine relativ steife Realität ab. Änderungen an dieser haben Laufzeiten von Jahrzehnten. Wenn Dinge also einmal etabliert sind, dann müssen sie meist nur erweitert werden.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also da scheinst du in einer sehr speziellen Ecke des Softwareentwicklungskosmos zu residieren.

Denn dein Vergleich mit Auto-Konstruktion hinkt in meinen Augen sehr, und ist auch der Grund dafuer, warum viele Leute nicht verstehen, wieso Softwareentwicklung eine dermassen schlecht planbare Kunst ist - statt schoen ingenieurswissenschaftlich Standardloesungen fuer Standardkomponenten zu verschrauben.

Der Grund liegt in meinen Augen darin, dass die Konnektivitaet deutlich geringer ist - eine Kupplung haengt an einer Seite am Motor, und an der anderen am Getriebe. Aber niemals am Schiebedach. In der Softwareentwicklung ist das jedoch gang & gaebe.

Wenn dein Job hauptsaechlich aus DB-Entwurf besteht - da bin ich bei dir. Unser Datenmodell hat sich verhaeltnismaessig wenig entwickelt in den letzten Jahren.

Aber wenn man etwas anderes als nur simpelste Masken zur Betrachtung & Bearbeitung vorsieht - dann kann man schon mal gezwungen sein, fuer die Integration eines neuen Payment Anbieters weite Teile des Codes umzuwerfen, weil der Seitenfluss nicht mehr derselbe ist - ohne dabei einen Fehler beim urspruengliche Konzept gemacht zu haben. Gab halt noch kein PayPal.

Genauso hat die Einfuehrung von Hardware statt reinen Software Verkaeufen inklusive der Notwendigkeit, Vorbestellungen aufzugeben, abzuarbeiten, zu widerrufen, Einfluss auf all den bestehenden Code, und da muss dann schon nachgebessert werden.

Mit anderen Worten: das Auto lernt schwimmen und fliegen, und ist kein Auto mehr, sondern ein FliWaTüt, und das natuerlich nicht durch Neukonstruktion, sondern refactoring.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

__deets__ hat geschrieben:Also da scheinst du in einer sehr speziellen Ecke des Softwareentwicklungskosmos zu residieren.
Wahrscheinlich schon, denn die meisten meiner "Objekte" sind echte, darunter einige, die mit Sicherheit die Lebenszeit der virtuellen überdauern (z.B. Bäume).
Natürlich hängen an diesen Objekte dran, die sich gelegentlich ändern, je nach Vorschriften/Regeln etc. Aber auch das hält sich in Grenzen.
__deets__ hat geschrieben:Denn dein Vergleich mit Auto-Konstruktion hinkt in meinen Augen sehr, und ist auch der Grund dafuer, warum viele Leute nicht verstehen, wieso Softwareentwicklung eine dermassen schlecht planbare Kunst ist - statt schoen ingenieurswissenschaftlich Standardloesungen fuer Standardkomponenten zu verschrauben.
Vor ca. 15 Jahren habe ich mich mal mit Metriken zur Berechnung des zu erwartenden Entwicklungsaufwandes beschäftigt. Es geht schon, aber den Aufwand betreibt halt keiner mehr, weil alles schnell gehen muss. Es wird eher grob ins Blaue geschätzt, als wirklich vorher die TippelTappelTour Lastenheft - Pflichtenheft - Lastenheft - Pflichtenheft ... durchzugehen, nicht zuletzt, weil Softwareprojekte oft ausgeschrieben werden müssen. Oft wird dann soviel geliefert, wie zu diesem Preis gefertigt werden kann. Den Rest macht die 90/10- Regel (90% des Aufwandes schafft man in 10% der Zeit, für die restlichen 10% benötigt man 90% der Zeit. Wenn man also 45% des Aufwandes bezahlt bekam, kann man 90% + 35/90*10% liefern, also in etwa 94%. Die restlichen versteckt man dann dahinter, dass der Kunde sich etwas anders überlegt hat und muss sie nie umsetzen oder bekommt sie indirekt bezahlt.

Mein Glück ist, wie gesagt, dass ich in die Konzeptionsphase eingebunden war, so dass einerseits ich schneller begreifen konnte, was erwartet wurde, und andererseits der Kunde gleich eine Aufwandsabschätzung mitbekommen konnte. Aber jetzt bin ich sowieso in einer anderen Situation. Ich programmiere nur noch für mich, gewissermaßen zum Spaß, um meine Arbeit effektiver zu machen. Ich beschaffe Informationen aus Daten, die nur aus den Ecken herausgekratzt werden können. Meine Projekte sind jetzt keine eigentlichen Software- Projekte mehr. Dennoch lassen sich die meisten Dinge nur effizient lösen, wenn man algorithmisch an die Sache herangeht.

Und daher brauche ich einen Satz spezifisches Werkzeug, das ich schnell zu einem Roboter bauen kann, der quasi die Eingangsdaten besorgen, mit Datenbankdaten verschneiden und die Ausgangsdaten herausbrechen kann. Die Aufgabenstellungen sind immer unterschiedlich, die benutzten "Schnittstellen" im weiteren Sinne aber meist die gleichen, wenn auch oft unterschiedliche Aspekte zum Tragen kommen.
__deets__ hat geschrieben:Der Grund liegt in meinen Augen darin, dass die Konnektivitaet deutlich geringer ist - eine Kupplung haengt an einer Seite am Motor, und an der anderen am Getriebe. Aber niemals am Schiebedach. In der Softwareentwicklung ist das jedoch gang & gaebe.
Na ja, bei mir halt nicht. Um bei dem Modell zu bleiben: Es ist für mich kein Problem, das Auto zum fliegen zu bringen, schließlich habe ich es ja selbst gebaut. Mein Problem ist, dass ich Himmel und Erde von anderen benutze. Da brauche ich nur wenige Schnittstellen, die Farbe des Himmels und die Temperatur sind mir egal, dafür muss ich aber unkompliziert auf die Position der Wolken zugreifen können, und zwar immer wieder und eigentlich immer nur die Wolken. Falls mich Hubschrauber je interessieren sollten, müsste ich meine Schnittstelle zum Himmel erweitern.

So habe ich im Grunde über Jahre entwickelt, das war kein Problem. Und selbst, wenn ich meine Himmel- Schnittstelle nur alle 3 Jahre benutzt habe, musste ich keine Dokumentation lesen, weil die Schnittstelle selbsterkärend und selbstüberwachend war. Letzteres bekomme ich bei Python halt nicht, ist aber auch nicht so schlimm. Ich muss jetzt eben lernen, wie ich mir meine Werkzeuge mit python so baue, dass ich sie immer wieder so benutzen kann, wie ich sie benötige.
__deets__ hat geschrieben:Wenn dein Job hauptsaechlich aus DB-Entwurf besteht - da bin ich bei dir. Unser Datenmodell hat sich verhaeltnismaessig wenig entwickelt in den letzten Jahren.
Noch nicht einmal Entwurf, sondern nur mit komplexen Auswertungen.
__deets__ hat geschrieben:Aber wenn man etwas anderes als nur simpelste Masken zur Betrachtung & Bearbeitung vorsieht - dann kann man schon mal gezwungen sein, fuer die Integration eines neuen Payment Anbieters weite Teile des Codes umzuwerfen, weil der Seitenfluss nicht mehr derselbe ist - ohne dabei einen Fehler beim urspruengliche Konzept gemacht zu haben. Gab halt noch kein PayPal.

Genauso hat die Einfuehrung von Hardware statt reinen Software Verkaeufen inklusive der Notwendigkeit, Vorbestellungen aufzugeben, abzuarbeiten, zu widerrufen, Einfluss auf all den bestehenden Code, und da muss dann schon nachgebessert werden.

Mit anderen Worten: das Auto lernt schwimmen und fliegen, und ist kein Auto mehr, sondern ein FliWaTüt, und das natuerlich nicht durch Neukonstruktion, sondern refactoring.
Das ist schon richtig, in solchen Fällen ändert sich das Design ständig. Ich habe keine Ahnung, ob man dafür dann irgend etwas wie agile Programmierung oder extreme programming benutzen sollte, aber dazu habe ich auch nur mal was gelesen, ich habe es nie gebraucht.
Antworten