[Python] Wordt mijn class te groot?

Pagina: 1
Acties:

Vraag


  • Yariva
  • Registratie: November 2012
  • Laatst online: 10:30

Yariva

Moderator Internet & Netwerken

Power to the people!

Topicstarter
Ik heb een weekje geleden een class aangemaakt om middels een REST API data op te halen. Specifiek gaat het om een firewall beheer pakket waarin ik het volgende heb gemaakt:
- Login functie
- Logout functie
- Login controle functie
- Object toevoegen, verwijderen wijzigen etc.
- Firewall regel toevoegen, verwijderen, wijzigen etc.
- VPN tunnels aanmaken, wijzigen, verwijderen etc.
- Custom error classes voor try: except: blokken.

Dit werkt allemaal met de request.session functie gezien ik een cookie terug krijg met authenticatie gegevens. Deze cookie kan ik vervolgens hergebruiken door de gehele Class zodat ik niet bij iedere functie opnieuw hoef aan te melden / een token hoef mee te sturen etc.

De class begon klein met 6 a 7 functies. Echter zit ik nu op 700 lines aan code en begint de class erg groot aan te voelen. Het werkt allemaal prima, maar ik zou het netter vinden om bijvoorbeeld de objecten scripts te scheiden van de firewall regels en de vpn functies etc. Echter heb ik de class nu opgezet met een cookie welke ik moet mee geven voor alle functies.

Hebben jullie tips om dit aan te pakken? Of groeit deze class nog totaal niet uit proportie?

Mensen zijn gelijk, maar sommige zijn gelijker dan andere | Humans need not apply

Alle reacties


Acties:
  • +2 Henk 'm!

  • Nvidiot
  • Registratie: Mei 2003
  • Laatst online: 03-06 16:38

Nvidiot

notepad!

Wellicht kun je een configuratie module / class maken, en losse classes voor de verschillende typen functies (dus een class voor de VPN dingen, een voor firewall dingen, etc). Deze losse classes kunnen dan allemaal de configuratie module importeren en gebruiken, zonder dat elke functie de configuratie als parameter mee hoeft te krijgen. De configuratie module / class kun je dan ook verantwoordelijk maken voor het opslaan van de request cookie(s) en eventuele andere instellingen (bijvoorbeeld van een configfile op disk)\

En ter voorkoming van het iedere keer opnieuw aanmaken van een instance van een configuratie class kun je kijken naar het singleton pattern: Wikipedia: Singleton pattern

[ Voor 18% gewijzigd door Nvidiot op 03-09-2020 16:23 ]

What a caterpillar calls the end, the rest of the world calls a butterfly. (Lao-Tze)


Acties:
  • +2 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Aantal regels is ook maar arbitrair, je class heeft duidelijk meer dan 1 responsibility. Alhoewel, met 700 regels zou het sterk zijn als er maar eentje is. ;)

Dus die functies inderdaad apart. Met een DDD mindset valt authenticatie extra op, dat is meer ondersteunend/meta en niet het core business domein; Ik zou zelf niet kunnen slapen totdat ik dat uit elkaar gepeuterd zou hebben. :D

{signature}


Acties:
  • +1 Henk 'm!

  • Barreljan
  • Registratie: December 2001
  • Laatst online: 10:41

Barreljan

...Zoom-Zoom...

Op zich, 700 regels is nog niet bizar denk ik. Alleen nu het dus lijkt te groeien is het beter om wat op te splitsen voor het echt onhoudbaar word. Je kan volgens mij alle kanten op. Dat is vaak het lastige, wat is het beste. Wat wat speel je zoals door naar de functies aan objecten? Is het weinig tot niet en is het alles uit de class zelf gebruiken (self.bla)?

Je kan ook eens kijken naar je project structuur. Wellicht kan je functies die relatief simpel buiten de class aan te spreken zijn verkassen naar aparte modules. Wat simpel leesvoer en waar tenminste uitleg bij zit: https://dev.to/codemouse9...tructure-and-imports-38c6

Ik zelf wil nog wel eens t gemak kiezen door functies buiten een class te zetten (omdat ik het als 'common' functie gebruik in andere classes) en dan pass ik een dict door met data, ipv een hele rits variabelen. Dus dit in het klein (denk ff aan var1 tm var10 ofzo)

code:
1
2
eenfunctie(var1, var2, var3):
    print(f"hallo {var1} {var2}, {var3}"


naar

code:
1
2
eenfunctie(d):
    print(f"hallo {d['var1']} {d['var2']}, {d['var3']}"


Maar goed, er zijn tonnen met ideeën soms en het hangt net af van jou kennis en kunde. Het moet ook wel werkbaar blijven. De suggestie van @Voutloos over DDD (domain driven design) is ook goed om eens te kijken.

Alternatief is je manier van coden aanpakken. Kortere syntax, list comprehensions ipv volluit geschreven etc. Maar dat gaat vaak wel ten koste van leesbaarheid.

Mind you, ik ben geen fulltime programmeur maar kan me prima vermaken met Python (ik leer elke dag).

Time Attacker met de Mazda 323F 2.5 V6 J-spec | PV output


Acties:
  • 0 Henk 'm!

  • Yariva
  • Registratie: November 2012
  • Laatst online: 10:30

Yariva

Moderator Internet & Netwerken

Power to the people!

Topicstarter
Thanks voor de suggesties. Ik ga mij hier vandaag eens in verdiepen.

Zoals @Barreljan schrijft ben ik ook absoluut niet een full-time programmeur maar wel de persoon in mijn team met de meeste programmeer kennis. Ik ben nu bezig om bestaande scripts te converteren naar een class based setup om modules te importeren, custom error meldingen etc. Als je het doet wil ik het wel zo goed mogelijk doen :)

Mensen zijn gelijk, maar sommige zijn gelijker dan andere | Humans need not apply


Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Laatst online: 09:59
Lijkt op een Wikipedia: God object

Ik kan je dit boek wel aanraden om even een kijkje te krijgen in wat je zoal kan doen.
https://refactoring.guru/design-patterns

Acties:
  • 0 Henk 'm!

  • Yariva
  • Registratie: November 2012
  • Laatst online: 10:30

Yariva

Moderator Internet & Netwerken

Power to the people!

Topicstarter
Hmm zeker genoeg te lezen dit weekend. Wat ik nog niet direct heb uitgevonden is hoe je je authenticatie gaat afhandelen. Stel je voor ik heb de volgende code:

Class "algemene communicatie"
Class "firewall regels" (child van "algemene communicatie")
Class "VPN configuratie" (child van "algemene communicatie")

Wanneer ik een object maak voor de firewall regels heb ik alle eigenschappen van de "algemene communicatie" class. Daarin zou je dingen als inloggen, uitloggen etc inzetten. Echter gebruik je daar een token voor.

Nu wil ik naast firewall regels ook een VPN configuratie laden. Maar dan moet ik, gok ik, opnieuw inloggen. Tenzij je het API token uit het firewall regels object weet te vissen en door te geven naar het nieuwe VPN configuratie object.

Mensen zijn gelijk, maar sommige zijn gelijker dan andere | Humans need not apply


Acties:
  • 0 Henk 'm!

  • Lethalis
  • Registratie: April 2002
  • Niet online
Yariva schreef op vrijdag 4 september 2020 @ 13:16:
Hmm zeker genoeg te lezen dit weekend. Wat ik nog niet direct heb uitgevonden is hoe je je authenticatie gaat afhandelen. Stel je voor ik heb de volgende code:

Class "algemene communicatie"
Class "firewall regels" (child van "algemene communicatie")
Class "VPN configuratie" (child van "algemene communicatie")

Wanneer ik een object maak voor de firewall regels heb ik alle eigenschappen van de "algemene communicatie" class. Daarin zou je dingen als inloggen, uitloggen etc inzetten. Echter gebruik je daar een token voor.

Nu wil ik naast firewall regels ook een VPN configuratie laden. Maar dan moet ik, gok ik, opnieuw inloggen. Tenzij je het API token uit het firewall regels object weet te vissen en door te geven naar het nieuwe VPN configuratie object.
Het mooiste is wanneer er een scheiding is tussen de applicatielogica en de framework code. Waar jij nu schrijft over API tokens en cookies, zou het juiste abstractieniveau dus een logon principal of user zijn die bepaalde rechten heeft.

Technisch gezien is de rest "plumbing". Je hebt functies nodig die van een cookie of token naar een user vertalen, en die kun je ergens onder een auth of util class plaatsen.

Daarnaast is er een algemene voorkeur voor composition ten opzichte van inheritance. Met andere woorden: is het logisch dat die "firewall regels" en "VPN configuratie" overerven van de "algemene communicatie", of is het beter als ze gewoon een class krijgen (via dependency injection) die de "algemene communicatie" verzorgt?

Stof tot nadenken iig :)

Voor de rest laat ik me even niet teveel uit over het Python gedeelte, omdat ik normaal gesproken met ASP.NET werk. Maar dit zijn even mijn algemene bevindingen qua ontwerp.

Daarbij heb ik wel de kanttekening dat hoe mooi je iets oplost, ook erg afhankelijk van de scope van het project is (groot project = uitgebreid ontwerp, klein project = als het in 1 scriptje past, whatever).

PS
Het klinkt overigens als een project dat qua security erg gevoelig is. Wel tricky om zoiets te bouwen als je niet alle ins en outs kent. Sessie management kun je dan het beste zoveel mogelijk overlaten aan een bestaande framework oplossing, die veel dingen voor jou al regelt (CSRF tokens, secure cookies, password hashing met random salts etc, etc).

[ Voor 6% gewijzigd door Lethalis op 04-09-2020 13:54 ]

Ask yourself if you are happy and then you cease to be.


Acties:
  • 0 Henk 'm!

  • Yariva
  • Registratie: November 2012
  • Laatst online: 10:30

Yariva

Moderator Internet & Netwerken

Power to the people!

Topicstarter
Lethalis schreef op vrijdag 4 september 2020 @ 13:44:
[...]

Het mooiste is wanneer er een scheiding is tussen de applicatielogica en de framework code. Waar jij nu schrijft over API tokens en cookies, zou het juiste abstractieniveau dus een logon principal of user zijn die bepaalde rechten heeft.

Technisch gezien is de rest "plumbing". Je hebt functies nodig die van een cookie of token naar een user vertalen, en die kun je ergens onder een auth of util class plaatsen.

Daarnaast is er een algemene voorkeur voor composition ten opzichte van inheritance. Met andere woorden: is het logisch dat die "firewall regels" en "VPN configuratie" overerven van de "algemene communicatie", of is het beter als ze gewoon een class krijgen (via dependency injection) die de "algemene communicatie" verzorgt?

Stof tot nadenken iig :)

Voor de rest laat ik me even niet teveel uit over het Python gedeelte, omdat ik normaal gesproken met ASP.NET werk. Maar dit zijn even mijn algemene bevindingen qua ontwerp.

Daarbij heb ik wel de kanttekening dat hoe mooi je iets oplost, ook erg afhankelijk van de scope van het project is (groot project = uitgebreid ontwerp, klein project = als het in 1 scriptje past, whatever).

PS
Het klinkt overigens als een project dat qua security erg gevoelig is. Wel tricky om zoiets te bouwen als je niet alle ins en outs kent. Sessie management kun je dan het beste zoveel mogelijk overlaten aan een bestaande framework oplossing, die veel dingen voor jou al regelt (CSRF tokens, secure cookies, password hashing met random salts etc, etc).
Thanks voor de input (no pun intended ;) )!

Jup ik laat de authenticatie over aan cookies in een request sessie. Die secure cookies gebruik ik hierna weer in alle overige functies. Ik gebruikte het voorbeeld van een token om het verhaal iets te vereenvoudigen :)

Mensen zijn gelijk, maar sommige zijn gelijker dan andere | Humans need not apply


Acties:
  • +1 Henk 'm!

  • Zarhrezz
  • Registratie: Juli 2013
  • Laatst online: 25-12-2024
Nvidiot schreef op donderdag 3 september 2020 @ 16:22:
<snip van allemaal goed advies>

En ter voorkoming van het iedere keer opnieuw aanmaken van een instance van een configuratie class kun je kijken naar het singleton pattern: Wikipedia: Singleton pattern
Binnen Python heb je zelden een singleton nodig. Dit vanwege de werking van het Python import systeem; als in verschillende modules dezelfde import gedaan wordt, wordt deze import 1x uitgevoerd. Als het resultaat van een import een class instance is, gedraagt deze zich dus al als singleton. Voor een config file (die eenmalig ingeladen moet worden) zou dit er ongeveer zo uitzien:

module appconfig.py:
code:
1
2
3
4
5
6
class AppConfig:
    def __init__(self):
        self.some_setting = None


APPCONFIG = AppConfig()


module foo.py:
code:
1
2
3
4
5
from appconfig import APPCONFIG

def some_method(self, value):
    if not APPCONFIG.some_setting:
         APPCONFIG.some_setting = value


Even heel simpel uit de losse pols (look mom, no linters :+ ) maar ik hoop dat het concept duidelijk is. Iedere module die iets met de appconfig moet, doet simpelweg de import van APPCONFIG en die gedraagt zich als een singleton. Het is geen zuivere singleton, want je kan dit doen om een nieuwe instantie te maken:
code:
1
2
3
from appconfig import AppConfig

my_new_config = AppConfig()

Dit is natuurlijk wel weer te voorkomen, maar de vraag is even welk probleem je dan aan het oplossen bent; het makkelijk kunnen delen van de config data of het voorkomen dat iemand die de documentatie niet leest er een zooitje van maakt.

<GOT> Zarhrezz#2885

Pagina: 1