portaldacalheta.pt
  • Κύριος
  • Σχεδιασμός Ux
  • Κερδοφορία & Αποδοτικότητα
  • Κύκλος Ζωής Προϊόντος
  • Ευκίνητος
Πίσω Μέρος

WSGI: Η διεπαφή διακομιστή-εφαρμογής για Python



Το 1993, ο ιστός ήταν ακόμη στα σπάργανα, με περίπου 14 εκατομμύρια χρήστες και 100 ιστότοποι . Οι σελίδες ήταν στατικές αλλά υπήρχε ήδη ανάγκη δημιουργίας δυναμικού περιεχομένου, όπως ενημερωμένων ειδήσεων και δεδομένων. Απαντώντας σε αυτό, ο Rob McCool και άλλοι συνεισφέροντες εφάρμοσαν το Common Gateway Interface (CGI) στο Εθνικό Κέντρο Υπερυπολογιστικών Εφαρμογών (NCSA) Διακομιστής ιστού HTTPd (ο πρόδρομος του Apache). Αυτός ήταν ο πρώτος διακομιστής ιστού που μπορούσε να εξυπηρετήσει περιεχόμενο που δημιουργήθηκε από μια ξεχωριστή εφαρμογή.

Από τότε, ο αριθμός των χρηστών στο Διαδίκτυο έχει εκραγεί και δυναμικοί ιστότοποι έχουν γίνει πανταχού παρόντες. Κατά την πρώτη εκμάθηση μιας νέας γλώσσας ή ακόμη και την πρώτη εκμάθηση κωδικών, οι προγραμματιστές, σύντομα, θέλουν να μάθουν πώς να συνδέσουν τον κώδικά τους στον ιστό.



Η Python στον Ιστό και η άνοδος του WSGI

Από τη δημιουργία του CGI, πολλά έχουν αλλάξει. Η προσέγγιση CGI έγινε ανέφικτη, καθώς απαιτούσε τη δημιουργία μιας νέας διαδικασίας σε κάθε αίτημα, σπατάλη μνήμης και CPU. Μερικές άλλες προσεγγίσεις χαμηλού επιπέδου εμφανίστηκαν, όπως το FastCGI] (http://www.fastcgi.com/) (1996) και mod_python (2000), παρέχοντας διαφορετικές διεπαφές μεταξύ των πλαισίων Ιστού Python και του διακομιστή Ιστού. Καθώς πολλαπλασιάστηκαν διαφορετικές προσεγγίσεις, η επιλογή του πλαισίου του προγραμματιστή κατέληξε να περιορίζει τις επιλογές των διακομιστών ιστού και το αντίστροφο.



Για να αντιμετωπιστεί αυτό το πρόβλημα, το 2003 ο Phillip J. Eby πρότεινε PEP-0333 , το Python Web Server Gateway Interface (WSGI). Η ιδέα ήταν να παρέχουμε ένα υψηλού επιπέδου, καθολική διεπαφή μεταξύ εφαρμογών Python και διακομιστών ιστού.



Το 2003, PEP-3333 ενημέρωσε τη διεπαφή WSGI για να προσθέσει υποστήριξη Python 3. Σήμερα, σχεδόν όλα τα πλαίσια της Python χρησιμοποιούν το WSGI ως μέσο, ​​αν όχι το μόνο μέσο, ​​για επικοινωνία με τους διακομιστές τους. Ετσι Τζάνγκο , Φλάσκα και πολλά άλλα δημοφιλή πλαίσια το κάνουν.

Αυτό το άρθρο σκοπεύει να δώσει στον αναγνώστη μια ματιά στον τρόπο λειτουργίας του WSGI και να επιτρέψει στον αναγνώστη να δημιουργήσει μια απλή εφαρμογή ή διακομιστή WSGI. Ωστόσο, δεν προορίζεται να είναι εξαντλητικός, και οι προγραμματιστές που σκοπεύουν να εφαρμόσουν διακομιστές ή εφαρμογές έτοιμες για παραγωγή θα πρέπει να ρίξουν μια πιο προσεκτική ματιά στο Προδιαγραφή WSGI .



Η διεπαφή Python WSGI

Το WSGI καθορίζει απλούς κανόνες στους οποίους πρέπει να συμμορφώνεται ο διακομιστής και η εφαρμογή. Ας ξεκινήσουμε εξετάζοντας αυτό το συνολικό μοτίβο.

Η διεπαφή διακομιστή-εφαρμογής Python WSGI.



Διεπαφή εφαρμογής

Στο Python 3.5, οι διεπαφές εφαρμογής έχουν ως εξής:

def application(environ, start_response): body = b'Hello world! ' status = '200 OK' headers = [('Content-type', 'text/plain')] start_response(status, headers) return [body]

Στο Python 2.7, αυτή η διεπαφή δεν θα ήταν πολύ διαφορετική. η μόνη αλλαγή θα ήταν ότι το σώμα αντιπροσωπεύεται από ένα str αντικείμενο, αντί για bytes ένας.



Αν και έχουμε χρησιμοποιήσει μια συνάρτηση σε αυτήν την περίπτωση, οποιαδήποτε καλεί θα κάνω. Οι κανόνες για το αντικείμενο εφαρμογής εδώ είναι:

  • Πρέπει να είναι κλήσιμο με environ και start_response Παράμετροι.
  • Πρέπει να καλέσετε το start_response επιστροφή κλήσης πριν από την αποστολή του σώματος.
  • Πρέπει να επιστρέψετε μια επανάληψη με κομμάτια του σώματος του εγγράφου.

Ένα άλλο παράδειγμα ενός αντικειμένου που ικανοποιεί αυτούς τους κανόνες και θα παράγει το ίδιο αποτέλεσμα είναι:



class Application: def __init__(self, environ, start_response): self.environ = environ self.start_response = start_response def __iter__(self): body = b'Hello world! ' status = '200 OK' headers = [('Content-type', 'text/plain')] self.start_response(status, headers) yield body

Διασύνδεση διακομιστή

Ένας διακομιστής WSGI ενδέχεται να διασυνδέεται με αυτήν την εφαρμογή ως εξής ::

def write(chunk): '''Write data back to client''' ... def send_status(status): '''Send HTTP status code''' ... def send_headers(headers): '''Send HTTP headers''' ... def start_response(status, headers): '''WSGI start_response callable''' send_status(status) send_headers(headers) return write # Make request to application response = application(environ, start_response) try: for chunk in response: write(chunk) finally: if hasattr(response, 'close'): response.close()

Όπως ίσως έχετε παρατηρήσει, το start_response callable επέστρεψε ένα write κλήση που μπορεί να χρησιμοποιήσει η εφαρμογή για την αποστολή δεδομένων πίσω στον πελάτη, αλλά αυτό δεν χρησιμοποιήθηκε από το παράδειγμα κώδικα εφαρμογής μας. Αυτό write η διεπαφή έχει καταργηθεί και μπορούμε να την αγνοήσουμε για τώρα Θα συζητηθεί σύντομα αργότερα στο άρθρο.



Μια άλλη ιδιαιτερότητα των ευθυνών του διακομιστή είναι να καλέσετε το προαιρετικό close μέθοδος στο επαναληπτικό απόκρισης, εάν υπάρχει. Όπως επισημαίνεται στο άρθρο του Graham Dumpleton εδώ , είναι ένα χαρακτηριστικό του WSGI που συχνά παραβλέπεται. Καλώντας αυτήν τη μέθοδο, αν υπαρχει , επιτρέπει στην εφαρμογή να αποδεσμεύει τυχόν πόρους που ενδέχεται να διατηρεί.

Η εφαρμογή με δυνατότητα κλήσης environ Διαφωνία

Το environ η παράμετρος πρέπει να είναι αντικείμενο λεξικού. Χρησιμοποιείται για τη μετάδοση πληροφοριών αιτήματος και διακομιστή στην εφαρμογή, όπως και το CGI. Στην πραγματικότητα, όλες οι μεταβλητές περιβάλλοντος CGI είναι έγκυρες στο WSGI και ο διακομιστής πρέπει να περάσει όλα όσα ισχύουν για την εφαρμογή.

Ενώ υπάρχουν πολλά προαιρετικά κλειδιά που μπορούν να περάσουν, πολλά είναι υποχρεωτικά. Λαμβάνοντας ως παράδειγμα τα ακόλουθα GET αίτηση:

$ curl 'http://localhost:8000/auth?user=obiwan&token=123'

Αυτά είναι τα κλειδιά που ο διακομιστής πρέπει παρέχουν και τις τιμές που θα λαμβάνουν:

Κλειδί αξία Σχόλια
REQUEST_METHOD 'GET'
SCRIPT_NAME '' εξαρτάται από τη ρύθμιση του διακομιστή
PATH_INFO '/auth'
QUERY_STRING 'token=123'
CONTENT_TYPE ''
CONTENT_LENGTH ''
SERVER_NAME '127.0.0.1' εξαρτάται από τη ρύθμιση του διακομιστή
SERVER_PORT '8000'
SERVER_PROTOCOL 'HTTP/1.1'
HTTP_(...) Παρέχονται από τον πελάτη κεφαλίδες HTTP
wsgi.version (1, 0) πλειάδα με έκδοση WSGI
wsgi.url_scheme 'http'
wsgi.input Αντικείμενο που μοιάζει με αρχείο
wsgi.errors Αντικείμενο που μοιάζει με αρχείο
wsgi.multithread False True εάν ο διακομιστής είναι πολλαπλών νημάτων
wsgi.multiprocess False True εάν ο διακομιστής εκτελεί πολλές διαδικασίες
wsgi.run_once False True εάν ο διακομιστής αναμένει ότι αυτό το σενάριο θα εκτελεστεί μόνο μία φορά (π.χ. σε περιβάλλον CGI)

Η εξαίρεση σε αυτόν τον κανόνα είναι ότι εάν ένα από αυτά τα πλήκτρα ήταν κενό (όπως CONTENT_TYPE στον παραπάνω πίνακα), τότε μπορούν να παραλειφθούν από το λεξικό και θα υποτεθεί ότι αντιστοιχούν στην κενή συμβολοσειρά.

wsgi.input και wsgi.errors

Τα περισσότερα environ Τα πλήκτρα είναι απλά, αλλά δύο από αυτά αξίζουν λίγο περισσότερη διευκρίνιση: wsgi.input, η οποία πρέπει να περιέχει μια ροή με το σώμα αιτήματος από τον πελάτη και wsgi.errors, όπου η εφαρμογή αναφέρει τυχόν σφάλματα που συναντά. Σφάλματα που στάλθηκαν από την εφαρμογή στο wsgi.errors συνήθως αποστέλλεται στο αρχείο καταγραφής σφαλμάτων διακομιστή.

Αυτά τα δύο κλειδιά πρέπει να περιέχουν αντικείμενα που μοιάζουν με αρχεία. δηλαδή, αντικείμενα που παρέχουν διασυνδέσεις για ανάγνωση ή εγγραφή σε ροές, όπως και το αντικείμενο που λαμβάνουμε όταν ανοίγουμε ένα αρχείο ή μια υποδοχή στο Python. Αυτό μπορεί να φαίνεται δύσκολο στην αρχή, αλλά ευτυχώς, η Python μας δίνει καλά εργαλεία για να το χειριστούμε.

Πρώτον, για τι είδους ροές μιλάμε; Σύμφωνα με τον ορισμό WSGI, wsgi.input και wsgi.errors πρέπει να χειριστεί bytes αντικείμενα στο Python 3 και str αντικείμενα στο Python 2. Σε κάθε περίπτωση, εάν θέλουμε να χρησιμοποιήσουμε ένα buffer στη μνήμη για να περάσουμε ή να λάβουμε δεδομένα μέσω της διεπαφής WSGI, μπορούμε να χρησιμοποιήσουμε την κλάση io.BytesIO.

Για παράδειγμα, εάν γράφουμε διακομιστή WSGI, θα μπορούσαμε να παρέχουμε το σώμα αιτήματος στην εφαρμογή όπως αυτό:

  • Για Python 2.7
import io ... request_data = 'some request body' environ['wsgi.input'] = io.BytesIO(request_data)
  • Για Python 3.5
import io ... request_data = 'some request body'.encode('utf-8') # bytes object environ['wsgi.input'] = io.BytesIO(request_data)

Από την πλευρά της εφαρμογής, εάν θέλαμε να μετατρέψουμε μια είσοδο ροής που λάβαμε σε συμβολοσειρά, θα θέλαμε να γράψουμε κάτι σαν αυτό:

  • Για Python 2.7
readstr = environ['wsgi.input'].read() # returns str object
  • Για Python 3.5
readbytes = environ['wsgi.input'].read() # returns bytes object readstr = readbytes.decode('utf-8') # returns str object

Το wsgi.errors Η ροή πρέπει να χρησιμοποιείται για την αναφορά σφαλμάτων εφαρμογής στο διακομιστή και οι γραμμές πρέπει να τερματίζονται με . Ο διακομιστής Ιστού πρέπει να φροντίσει να μετατρέψει σε διαφορετική γραμμή που τελειώνει σύμφωνα με το σύστημα.

Η εφαρμογή με δυνατότητα κλήσης start_response Διαφωνία

Το start_response Το όρισμα πρέπει να είναι callable με δύο απαιτούμενα ορίσματα, δηλαδή status και headers, και ένα προαιρετικό όρισμα, exc_info. Πρέπει να καλείται από την εφαρμογή προτού αποσταλεί οποιοδήποτε μέρος του σώματος στον διακομιστή ιστού.

Στο πρώτο παράδειγμα εφαρμογής στην αρχή αυτού του άρθρου, επιστρέψαμε το κύριο μέρος της απάντησης ως λίστα και, ως εκ τούτου, δεν έχουμε κανέναν έλεγχο για το πότε θα επαναληφθεί η λίστα. Εξαιτίας αυτού, έπρεπε να καλέσουμε start_response πριν επιστρέψετε στη λίστα.

Στο δεύτερο, καλέσαμε start_response λίγο πριν αποδώσετε το πρώτο (και, σε αυτήν την περίπτωση, μόνο) κομμάτι του σώματος απόκρισης. Και οι δύο τρόποι είναι έγκυροι σύμφωνα με τις προδιαγραφές WSGI.

Από την πλευρά του διακομιστή ιστού, η κλήση του start_response δεν πρέπει να στείλετε τις κεφαλίδες στον πελάτη, αλλά να το καθυστερήσετε έως ότου υπάρχει τουλάχιστον ένα μη κενό κενό στο σώμα απόκρισης για αποστολή στον πελάτη. Αυτή η αρχιτεκτονική επιτρέπει τη σωστή αναφορά σφαλμάτων μέχρι την τελευταία δυνατή στιγμή της εκτέλεσης της εφαρμογής.

σύναψη επιχειρηματικού σχεδίου

Το status Το επιχείρημα της start_response

Το status το όρισμα πέρασε στο start_response Η επιστροφή κλήσης πρέπει να είναι μια συμβολοσειρά που αποτελείται από έναν κωδικό κατάστασης HTTP και μια περιγραφή, διαχωρισμένη με ένα κενό διάστημα. Τα έγκυρα παραδείγματα είναι: '200 OK', ή '404 Not Found'.

Το headers Το επιχείρημα της start_response

Το headers το όρισμα πέρασε στο start_response Η επανάκληση πρέπει να είναι Python list από tuple s, με κάθε πλειάδα να συντίθεται ως (header_name, header_value). Τόσο το όνομα όσο και η τιμή κάθε κεφαλίδας πρέπει να είναι συμβολοσειρές (ανεξάρτητα από την έκδοση Python). Αυτό είναι ένα σπάνιο παράδειγμα στο οποίο έχει σημασία ο τύπος, καθώς αυτό απαιτείται πράγματι από την προδιαγραφή WSGI.

Εδώ είναι ένα έγκυρο παράδειγμα του τι a header το επιχείρημα μπορεί να μοιάζει με:

response_body = json.dumps(data).encode('utf-8') headers = [('Content-Type', 'application/json'), ('Content-Length', str(len(response_body))]

Οι κεφαλίδες HTTP δεν έχουν διάκριση πεζών-κεφαλαίων και αν γράφουμε έναν διακομιστή ιστού συμβατό με WSGI, αυτό είναι κάτι που πρέπει να λάβετε υπόψη κατά τον έλεγχο αυτών των κεφαλίδων. Επίσης, η λίστα των κεφαλίδων που παρέχεται από την εφαρμογή δεν πρέπει να είναι εξαντλητική. Είναι ευθύνη του διακομιστή να διασφαλίσει ότι υπάρχουν όλες οι απαιτούμενες κεφαλίδες HTTP πριν αποστείλετε την απάντηση πίσω στον πελάτη, συμπληρώνοντας τυχόν κεφαλίδες που δεν παρέχονται από την εφαρμογή.

Το exc_info Το επιχείρημα της start_response

Το start_response Η επιστροφή κλήσης πρέπει να υποστηρίζει ένα τρίτο όρισμα exc_info, που χρησιμοποιείται για τον χειρισμό σφαλμάτων. Η σωστή χρήση και εφαρμογή αυτού του επιχειρήματος είναι υψίστης σημασίας για τους διακομιστές και τις εφαρμογές web παραγωγής, αλλά δεν εμπίπτει στο πεδίο εφαρμογής αυτού του άρθρου.

Περισσότερες πληροφορίες σχετικά με αυτό μπορούν να ληφθούν στην προδιαγραφή WSGI, εδώ .

Το start_response Αξία επιστροφής - Η write Επιστροφή κλήσης

Για σκοπούς συμβατότητας προς τα πίσω, οι διακομιστές ιστού που εφαρμόζουν WSGI θα πρέπει να επιστρέφουν ένα write καλεί. Αυτή η επιστροφή θα πρέπει να επιτρέπει στην εφαρμογή να γράφει δεδομένα απόκρισης σώματος απευθείας στον πελάτη, αντί να τα αποδίδει στο διακομιστή μέσω επαναληπτικού.

Παρά την παρουσία του, αυτή είναι μια καταργημένη διεπαφή και οι νέες εφαρμογές πρέπει να απέχουν από τη χρήση της.

Δημιουργία του σώματος απόκρισης

Οι εφαρμογές που εφαρμόζουν το WSGI θα πρέπει να δημιουργήσουν το σώμα απόκρισης επιστρέφοντας ένα επαναλαμβανόμενο αντικείμενο. Για τις περισσότερες εφαρμογές, το σώμα απόκρισης δεν είναι πολύ μεγάλο και χωράει εύκολα στη μνήμη του διακομιστή. Σε αυτήν την περίπτωση, ο πιο αποτελεσματικός τρόπος αποστολής είναι όλα ταυτόχρονα, με ένα στοιχείο επαναλαμβανόμενο. Σε ειδικές περιπτώσεις, όπου η φόρτωση ολόκληρου του σώματος στη μνήμη δεν είναι εφικτή, η εφαρμογή μπορεί να το επιστρέψει εν μέρει μέσω αυτής της επαναλαμβανόμενης διεπαφής.

Υπάρχει μόνο μια μικρή διαφορά εδώ μεταξύ του Python 2 και του WSGI του Python 3: στο Python 3, το σώμα απόκρισης αντιπροσωπεύεται από bytes αντικείμενα στο Python 2, ο σωστός τύπος για αυτό είναι str.

Μετατροπή συμβολοσειρών UTF-8 σε bytes ή str είναι μια εύκολη εργασία:

  • Python 3.5:
body = 'unicode stuff'.encode('utf-8')
  • Python 2.7:
body = u'unicode stuff'.encode('utf-8')

Αν θέλετε να μάθετε περισσότερα σχετικά με το unicode του Python 2 και τον χειρισμό bytesting, υπάρχει ένα ωραίο σεμινάριο για Youtube .

Οι διακομιστές Ιστού που εφαρμόζουν WSGI θα πρέπει επίσης να υποστηρίζουν το write callback για συμβατότητα προς τα πίσω, όπως περιγράφεται παραπάνω.

Δοκιμή της εφαρμογής σας χωρίς διακομιστή Web

Με την κατανόηση αυτής της απλής διεπαφής, μπορούμε εύκολα να δημιουργήσουμε σενάρια για να δοκιμάσουμε τις εφαρμογές μας χωρίς να χρειαστεί να ξεκινήσουμε έναν διακομιστή.

Πάρτε αυτό το μικρό σενάριο, για παράδειγμα:

from io import BytesIO def get(app, path = '/', query = ''): response_status = [] response_headers = [] def start_response(status, headers): status = status.split(' ', 1) response_status.append((int(status[0]), status[1])) response_headers.append(dict(headers)) environ = { 'HTTP_ACCEPT': '*/*', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_USER_AGENT': 'TestAgent/1.0', 'PATH_INFO': path, 'QUERY_STRING': query, 'REQUEST_METHOD': 'GET', 'SERVER_NAME': '127.0.0.1', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'TestServer/1.0', 'wsgi.errors': BytesIO(b''), 'wsgi.input': BytesIO(b''), 'wsgi.multiprocess': False, 'wsgi.multithread': False, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0), } response_body = app(environ, start_response) merged_body = ''.join((x.decode('utf-8') for x in response_body)) if hasattr(response_body, 'close'): response_body.close() return {'status': response_status[0], 'headers': response_headers[0], 'body': merged_body}

Με αυτόν τον τρόπο, θα μπορούσαμε, για παράδειγμα, να αρχίσουμε ορισμένα δεδομένα δοκιμών και πλαστά στοιχεία στην εφαρμογή μας και να κάνουμε GET καλεί για να ελέγξει εάν ανταποκρίνεται ανάλογα. Μπορούμε να δούμε ότι δεν είναι πραγματικός διακομιστής ιστού, αλλά διασυνδέεται με την εφαρμογή μας με συγκρίσιμο τρόπο παρέχοντας στην εφαρμογή ένα start_response επανάκληση και ένα λεξικό με τις μεταβλητές περιβάλλοντος. Στο τέλος του αιτήματος, καταναλώνει τον επαναληπτικό του σώματος απόκρισης και επιστρέφει μια συμβολοσειρά με όλο το περιεχόμενό της. Παρόμοιες μέθοδοι (ή γενικές) μπορούν να δημιουργηθούν για διαφορετικούς τύπους αιτημάτων HTTP.

Τύλιξε

Το WSGI είναι ένα κρίσιμο μέρος σχεδόν οποιουδήποτε διαδικτυακού πλαισίου Python.

Σε αυτό το άρθρο, δεν έχουμε προσεγγίσει τον τρόπο με τον οποίο το WSGI ασχολείται με τις μεταφορτώσεις αρχείων, καθώς αυτό θα μπορούσε να θεωρηθεί μια πιο «προηγμένη» δυνατότητα, δεν είναι κατάλληλη για ένα εισαγωγικό άρθρο. Αν θέλετε να μάθετε περισσότερα για αυτό, ρίξτε μια ματιά στο Ενότητα PEP-3333 που αναφέρεται στο χειρισμό αρχείων .

Ελπίζω ότι αυτό το άρθρο είναι χρήσιμο για τη δημιουργία μιας καλύτερης κατανόησης του τρόπου με τον οποίο η Python μιλά σε διακομιστές ιστού και επιτρέπει στους προγραμματιστές να χρησιμοποιούν αυτήν τη διεπαφή με ενδιαφέροντες και δημιουργικούς τρόπους.

Ευχαριστίες

Θα ήθελα να ευχαριστήσω τον συντάκτη μου Νικ Μακρέα για να με βοηθήσετε με αυτό το άρθρο. Λόγω του έργου του, το αρχικό κείμενο έγινε πολύ πιο σαφές και πολλά λάθη δεν διορθώθηκαν.

Γιατί ο Τέσλα; Αξιολόγηση της ηλεκτρικής τρέλας

Επενδυτές & Χρηματοδότηση

Γιατί ο Τέσλα; Αξιολόγηση της ηλεκτρικής τρέλας
Ένας οδηγός για ισχυρές δοκιμές μονάδων και ενοποίησης με το JUnit

Ένας οδηγός για ισχυρές δοκιμές μονάδων και ενοποίησης με το JUnit

Πίσω Μέρος

Δημοφιλείς Αναρτήσεις
Αισθητική και αντίληψη - Τρόπος προσέγγισης εικόνων εμπειρίας χρήστη
Αισθητική και αντίληψη - Τρόπος προσέγγισης εικόνων εμπειρίας χρήστη
Βέλτιστες πρακτικές διάταξης ιστού: Αναλύθηκαν 12 διαχρονικά μοτίβα διεπαφής χρήστη
Βέλτιστες πρακτικές διάταξης ιστού: Αναλύθηκαν 12 διαχρονικά μοτίβα διεπαφής χρήστη
Εξοικείωση με το Πρόγραμμα ανάπτυξης Sketch
Εξοικείωση με το Πρόγραμμα ανάπτυξης Sketch
Mini Tutorial - Ένας οδηγός για συνδυασμούς γραμματοσειρών
Mini Tutorial - Ένας οδηγός για συνδυασμούς γραμματοσειρών
Για Σχεδιαστές με Αγάπη (Ένα Γράμμα από έναν Προγραμματιστή Front-end)
Για Σχεδιαστές με Αγάπη (Ένα Γράμμα από έναν Προγραμματιστή Front-end)
 
Σχεδιασμός βάσει δεδομένων και γενετικός σχεδιασμός - Μια επισκόπηση
Σχεδιασμός βάσει δεδομένων και γενετικός σχεδιασμός - Μια επισκόπηση
Διακομιστές ARM: Κινητή αρχιτεκτονική CPU για κέντρα δεδομένων;
Διακομιστές ARM: Κινητή αρχιτεκτονική CPU για κέντρα δεδομένων;
Ξεκινήστε με μικροσυσκευές: Ένα εκπαιδευτικό πρόγραμμα Dropwizard
Ξεκινήστε με μικροσυσκευές: Ένα εκπαιδευτικό πρόγραμμα Dropwizard
Μείνετε Sharp - Πώς να ενισχύσετε τη δημιουργικότητα όταν υποχωρεί η εργασία
Μείνετε Sharp - Πώς να ενισχύσετε τη δημιουργικότητα όταν υποχωρεί η εργασία
Ditch MVP, Υιοθετήστε Ελάχιστα Βιώσιμα Πρωτότυπα (MVPr)
Ditch MVP, Υιοθετήστε Ελάχιστα Βιώσιμα Πρωτότυπα (MVPr)
Δημοφιλείς Αναρτήσεις
  • βέλτιστες πρακτικές για αποκριτικές εικόνες σχεδίασης ιστοσελίδων
  • πώς να βρείτε πελάτες για διαβούλευση
  • σε ποια γλώσσα είναι γραμμένα τα λειτουργικά συστήματα
  • κόμβος js express ξεκούραστο api
  • Στις περισσότερες περιπτώσεις, αυτό δεν πρέπει να ενεργοποιείται επειδή παρακάμπτει ένα πολύ σημαντικό χαρακτηριστικό ασφαλείας.
  • δύναμη αγοραστών και προμηθευτών
Κατηγορίες
  • Σχεδιασμός Ux
  • Κερδοφορία & Αποδοτικότητα
  • Κύκλος Ζωής Προϊόντος
  • Ευκίνητος
  • © 2022 | Ολα Τα Δικαιώματα Διατηρούνται

    portaldacalheta.pt