window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster υπάρχει ήδη') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Ορατότητα στοιχείων στο React με απόδοση υπό όρους και φρουρούς - The Codest
The Codest
  • Σχετικά με εμάς
  • Υπηρεσίες
    • Ανάπτυξη λογισμικού
      • Ανάπτυξη Frontend
      • Backend Ανάπτυξη
    • Staff Augmentation
      • Frontend Developers
      • Backend Developers
      • Μηχανικοί δεδομένων
      • Μηχανικοί cloud
      • Μηχανικοί QA
      • Άλλα
    • Συμβουλευτική
      • Έλεγχος & Συμβουλευτική
  • Βιομηχανίες
    • Fintech & Τραπεζική
    • E-commerce
    • Adtech
    • Healthtech
    • Κατασκευή
    • Εφοδιαστική
    • Αυτοκίνητο
    • IOT
  • Αξία για
    • CEO
    • CTO
    • Διευθυντής παράδοσης
  • Η ομάδα μας
  • Case Studies
  • Μάθετε πώς
    • Blog
    • Συναντήσεις
    • Διαδικτυακά σεμινάρια
    • Πόροι
Καριέρα Ελάτε σε επαφή
  • Σχετικά με εμάς
  • Υπηρεσίες
    • Ανάπτυξη λογισμικού
      • Ανάπτυξη Frontend
      • Backend Ανάπτυξη
    • Staff Augmentation
      • Frontend Developers
      • Backend Developers
      • Μηχανικοί δεδομένων
      • Μηχανικοί cloud
      • Μηχανικοί QA
      • Άλλα
    • Συμβουλευτική
      • Έλεγχος & Συμβουλευτική
  • Αξία για
    • CEO
    • CTO
    • Διευθυντής παράδοσης
  • Η ομάδα μας
  • Case Studies
  • Μάθετε πώς
    • Blog
    • Συναντήσεις
    • Διαδικτυακά σεμινάρια
    • Πόροι
Καριέρα Ελάτε σε επαφή
Πίσω βέλος GO BACK
2023-05-19
Ανάπτυξη λογισμικού

Ορατότητα εξαρτημάτων στο React με απόδοση υπό όρους και φρουρούς

Bartlomiej Kuczynski

Μάθετε πώς να απλοποιείτε και να βελτιώνετε την ορατότητα των εξαρτημάτων στο React χρησιμοποιώντας την απόδοση υπό όρους και τα προστατευτικά εξαρτήματα.

Σήμερα θα ήθελα να συζητήσω πώς να ελέγχετε ορατότητα εξαρτημάτων στο React. Αλλά πριν ξεκινήσουμε υπάρχει ένα μικρό
αποποίηση ευθυνών:

Η παρούσα λύση δεν είναι πολύ ασφαλής όσον αφορά την προστασία της εφαρμογής σας από "χάκερ" (όποιοι κι αν είναι αυτοί).
Να θυμάστε ότι πρέπει να προστατεύετε τα τελικά σας σημεία και να χρησιμοποιείτε καλές πρακτικές στη σχεδίαση εφαρμογών. Αυτή η λύση μόνο
κάνει τη δουλειά σας λίγο πιο εύκολη.

Εργασία, λύση προβλήματος ή τι θα θέλαμε να επιτύχουμε

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

Ας ρίξουμε μια ματιά στο SimpleAppHeader στοιχείο που περιέχει λίγα στοιχεία πλοήγησης.

<!-- wp:paragraph -->
<p><code>typescript jsx<br>
export const SimpleAppHeader: FC = () =&gt; {<br>
    return (<br>
        <header><br>
            <nav><br>
                <ul><br>
                    {<br>
                        currentUser.role === "ADMIN" &amp;&amp;<br>
                        <li>Στοιχείο μόνο για διαχειριστές</li><br>
                    }<br>
                    {<br>
                        currentUser.role === "USER" &amp;&amp;<br>
                        <li>User only component</li><br>
                    }<br>
                    {<br>
                        (currentUser.role === "ADMIN" || currentUser.role === "USER") &amp;&amp;<br>
                        <li>Στοιχείο μόνο για διαχειριστές και χρήστες</li><br>
                    }<br>
                    <li>Στοιχείο γενικής χρήσης</li><br>
                </ul><br>
            </nav><br>
        </header><br>
    )<br>
}<br>
</code></p>
<!-- /wp:paragraph -->

Φαίνεται "όχι κακό". Πιθανώς θα μπορούσατε να ενθυλακώσετε τους ελέγχους σε συναρτήσεις για να μειώσετε την πολυπλοκότητα. currentUser είναι κάποιο αντικείμενο
που έχει ρόλος αλλά θα μπορούσε να είναι οτιδήποτε θα θέλαμε να χρησιμοποιήσουμε ως αντικείμενο του μηχανισμού ελέγχου μας.

Αυτός ο κώδικας έχει κάποια προβλήματα. Εάν έργο μεγαλώνει πιθανώς χρησιμοποιούμε αυτές τις κατασκευές σε πολλά μέρη. Έτσι πρέπει να αντιγράψουμε,
με κάποιο τρόπο, συνθήκες. Αυτός ο κώδικας είναι δύσκολο να διατηρηθεί και να αλλάξει στο μέλλον. Ειδικά όταν οι κανόνες πρόσβασης αλλάζουν κατά τη διάρκεια
π.χ. πρέπει να αλλάξουμε currentUser σε κάτι άλλο. Είναι πολύ δύσκολο να δοκιμαστεί. Πρέπει να γράψετε πολλές δοκιμές
απλά για να επαληθεύσετε αν η κατάστασή σας είναι εντάξει.

Απλούστευση

Ώρα να απλοποιήσουμε λίγο αυτόν τον κώδικα. Θα μπορούσαμε να αφαιρέσουμε μερικές μεθόδους και να κάνουμε τον κώδικα πιο σύντομο και λιγότερο περίπλοκο:

const isAdmin = (role: string): boolean => role === "ADMIN",
const isUser = (role: string): boolean => role === "USER",
const isAdminOrUser = (role: string): boolean => isAdmin(role) || isUser(role),

export const SimplifiedAppHeader: FC = () => { {
return (

{

isAdmin(currentUser.role) &&
Στοιχείο μόνο για διαχειριστές

}
{
isUser(currentUser.role) &&

Συστατικό μόνο για χρήστες

}
{
(isAdminOrUser(currentUser.role)) &&

Συστατικό μόνο για διαχειριστές και χρήστες

}

Στοιχείο γενικής χρήσης

)
}
```

Φαίνεται πολλά υποσχόμενο. Μειώνουμε το θόρυβο od γραμμές επανάληψης. Ο κώδικας είναι πιο ευανάγνωστος και ευκολότερα συντηρήσιμος. Αλλά ρίξτε μια ματιά στο
συνάρτηση isAdminOrUser. Έχουμε μόνο δύο ρόλους. Αν εισάγουμε τρίτο ρόλο πρέπει να δημιουργήσουμε ένα άλλο σύνολο συναρτήσεων
που συνδυάζει ρόλους. Ώρα για μια άλλη έκδοση.

Φιλτράρισμα

Ας εισαγάγουμε τη συνάρτηση hasRole που θα αντικαταστήσει το isX λειτουργίες.

const hasRole = (role: string, requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => role === s),
return found !== undefined,
}

export const FilteringAppHeader: FC = () => { {
return (

{

hasRole(currentUser.role, ["ADMIN"]) &&
Στοιχείο μόνο για διαχειριστές

}
{
hasRole(currentUser.role, ["USER"]) &&

Συστατικό μόνο για χρήστες

}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&

Συστατικό μόνο για διαχειριστές και χρήστες

}

Στοιχείο γενικής χρήσης

)
}
```

Τώρα φαίνεται καλό. Εξακολουθούμε να έχουμε συνθήκες στο html μέρος του κώδικα, αλλά τώρα μπορούμε να δοκιμάσουμε hasRole λειτουργία και να εμπιστεύεστε ότι
θα χρησιμοποιηθεί με το σωστό σύνολο παραμέτρων. Η προσθήκη ή η αλλαγή ρόλων είναι πλέον ευκολότερη. Χρησιμοποιούμε πίνακα που περιέχει όλους τους
τους ρόλους που χρειαζόμαστε στη θέση τους.

Ωστόσο, η λύση αυτή δεσμεύει currentUser αντικείμενο. Η υπόθεση είναι ότι το αντικείμενο είναι κατά κάποιο τρόπο παγκόσμιο ή εύκολα προσβάσιμο σε
οποιαδήποτε θέση στην εφαρμογή. Μπορούμε λοιπόν να προσπαθήσουμε να το ενθυλακώσουμε αυτό. Φυσικά, μπορούμε να το μετακινήσουμε στο hasRole λειτουργία:

 const hasRole = (requiredRole: string[]): boolean => {
     let found: string | undefined = requiredRole.find(s => currentUser.role === s),
     return found !== undefined,
 }

Αλλά αυτό δεν μας δίνει σχεδόν τίποτα.

Το Φρουρός Στοιχείο

Ώρα να δημιουργήσετε ένα συστατικό που να ενσωματώνει ολόκληρη τη λογική. Το ονόμασα Φρουρός και έτσι θέλω να το χρησιμοποιήσω.

 export const GuardedAppHeader: FC = () => { {
     return (
         
  • Στοιχείο μόνο για τον διαχειριστή
  • User only component
  • Συστατικό διαχειριστή και χρήστη
  • Στοιχείο γενικής χρήσης
); }

Το συστατικό χρειάζεται δύο ιδιότητες. Πρώτη παιδιά υπεύθυνος για το περιεχόμενο που φυλάσσεται. Δεύτερο requiredRoles που
χειρίζεται σειρά ρόλων που μας δίνει πρόσβαση.

Χρειαζόμαστε αναπαράσταση αυτής της δομής. Είναι πολύ απλή. Επεκτείνουμε τον τύπο React.PropsWithChildren που έχει παιδιά
ιδιοκτησία. Φυσικά μπορείτε να προσθέσετε χειροκίνητα την ιδιότητα αυτή στον τύπο σας και να παραλείψετε την επέκταση.

interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[],
}

Το ίδιο το εξάρτημα είναι επίσης απλό. Θα επαναχρησιμοποιήσουμε hasRole λειτουργία εδώ.

export const Guard = (props: IGuardProps) => {
const hasRole = (requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => currentUser.role === s),
return found !== undefined,
}

if (hasRole(props.requiredRoles)) {
    return (
        
            {props.children}
        
    );
} else {
    return ,
}
}
"`

Και θα μπορούσα να πω να σταματήσετε εδώ, αλλά θα ήταν πολύ εύκολο. Τώρα έχουμε το συστατικό, και μπορούμε να το χρησιμοποιήσουμε στα άκρα 😀

`GuardService`

Το πρώτο βήμα θα είναι η εξωτερίκευση των ελέγχων. currentUser είναι σκληρά κωδικοποιημένη τιμή. Θα ήθελα να ενθυλακώσω αυτή την τιμή
σε κάποια υπηρεσία, η οποία θα "ξέρει" πώς να επαληθεύει τους ρόλους. Τεχνικά αυτό σημαίνει ότι μετακινούμε hasRole συνάρτηση σε μια άλλη
κατηγορία.

Δημιουργώ απλή διεπαφή IGuardService που έχει μόνο μία ιδιότητα - hasRole.

export interface IGuardService {
checkRole: (roles: string[]) => boolean,
}

Τώρα η απλή εφαρμογή θα μπορούσε να μοιάζει με αυτό

class SimpleGuard implements IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role),
return found !== undefined,
}
}

Για να το χρησιμοποιήσουμε πρέπει να αλλάξουμε IGuardProperties και περίπτωση χρήσης.

export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[],
guardService: IGuardService,
}

// ...

const AppHeader: FC = () => { {
const guardService = new SimpleGuard(),
return (

Στοιχείο μόνο για διαχειριστές
 

User only component

Στοιχείο διαχειριστή και χρήστη
 
 

Στοιχείο γενικής χρήσης

 

);
}
```

Τώρα το συστατικό μοιάζει με:

 export const Guard = (props: IGuardProps) => {
     if (props.guardService.checkRole(props.requiredRoles)) {
         return (
             
                 {props.children}
             
         );
     } else {
         return ,
     }
 }
 

Πολύ καλύτερα. GuardService μας διαχωρίζουν από τη λογική που ελέγχει τους ρόλους. Μπορούμε να το αλλάξουμε χωρίς συνέπειες για την
συστατικό. Συνήθης περίπτωση χρήσης είναι η χρήση προσομοίωσης σε δοκιμές και κάποια "πραγματική" υλοποίηση στον κώδικα παραγωγής.

Απαγορευμένο στοιχείο

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

 export interface IGuardProps extends React.PropsWithChildren {
     requiredRoles: string[],
     guardService: IGuardService,
     forbidden?: () => React.ReactNode,
 }

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

export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (

{props.children}

);
} else if (props.forbidden === undefined) {
return ,
} else {
return (
{props.forbidden()}

);
}
}

// ...

export const AppHeader: FC = () => { {
const guardService = new SimpleGuard(),
return (

Συστατικό μόνο για διαχειριστές
 

User only component

Απαγορευμένο - μόνο ο συντονιστής μπορεί να το δει αυτό
}>
 

Συστατικό συντονιστή

 

Στοιχείο διαχειριστή και χρήστη
 
 

Στοιχείο γενικής χρήσης

 

);
}
```

Ευελιξία των τύπων

Ώρα για τελευταία μεγάλη αλλαγή. Η τρέχουσα έκδοση του συστατικού υποστηρίζει μόνο ρόλους ως string. Θα μπορούσαμε να έχουμε πολλές διαφορετικές
τύπους ακινήτων που θα θέλαμε να ελέγξουμε. Οι αριθμοί ή οι προσαρμοσμένοι τύποι δεν είναι τίποτα το ιδιαίτερο. Θα προσθέσω υποστήριξη γενικής χρήσης.

Το πρώτο βήμα είναι οι αλλαγές στο IGuardService διεπαφή. Οι υλοποιήσεις θα εξαρτώνται από τον τύπο της εξεταζόμενης τιμής. Θα μπορούσε να
να είναι οτιδήποτε, οπότε η διεπαφή θα πρέπει να το χειριστεί.

 export interface IGuardService {
     checkRole: (roles: ROLE[]) => boolean,
 }

Τώρα παίρνει συστοιχία των ΡΟΛΟΣ γενικός τύπος. Η απλή μας υλοποίηση θα αλλάξει λίγο.

 class SimpleGuard implements IGuardService {
     checkRole(roles: string[]): boolean {
         let found: string | undefined = roles.find(e => e === currentUser.role),
         return found !== undefined,
     }
 }

Πρέπει να προσθέσουμε παράμετρο τύπου, αλλά θα μπορούσαμε να προετοιμάσουμε υλοποίηση που υποστηρίζει IRole διεπαφή.

διεπαφή IRole {
name: string,
}

//...
class RoleGuardService implements IGuardService {
checkRole(roles: IRole[]): boolean {
let found: IRole | undefined = roles.find(e => e === userWithRole.role),
return found !== undefined,
}
}
```

Το δεύτερο βήμα είναι η διάδοση αυτής της αλλαγής στο IGuardProps.

 interface IGuardProps extends React.PropsWithChildren {
     requiredRoles: ROLE[],
     guardService: IGuardService,
     forbidden?: () => React.ReactNode,
 }

Και αντίστοιχα σε Φρουρός συστατικό.

export const Guard = (props: IGuardProps) => {
     if (props.guardService.checkRole(props.requiredRoles)) {
         return (
             
                 {props.children}
             
         );
     } else if (props.forbidden === undefined) {
         return ,
     } else {
         return (
                 {props.forbidden()}
             
         );
     }
 }

Και οι περιπτώσεις χρήσης μας

export const AppHeader: FC = () =&gt; { {
     const guardService = new SimpleGuard(),
     const roleService = new RoleGuardService(),
     return (
         <header>
             <nav>
                 <ul>
                     <Guard<IRole&gt; requiredRoles={[{name: "ADMIN"}]} guardService={roleService}&gt;
                         <li>Στοιχείο μόνο για διαχειριστές</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["USER"]} guardService={guardService}&gt;
                         <li>Συστατικό μόνο για τον χρήστη</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["MODERATOR"]} guardService={guardService}
                                    forbidden={() =&gt; <div>Απαγορευμένο - μόνο ο συντονιστής μπορεί να το δει αυτό</div>}>
                         <li>Συστατικό συντονιστή</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["USER", "ADMIN"]} guardService={guardService}&gt;
                         <li>Στοιχείο διαχειριστή και χρήστη</li>
                     </Guard>
                     <li>Στοιχείο γενικής χρήσης</li>
                 </ul>
             </nav>
         </header>
     );
 }

Σε αυτό το παράδειγμα χρησιμοποιώ και τις δύο υλοποιήσεις του IGuardservice μόνο για ενδεικτικούς σκοπούς. Σε πραγματικές περιπτώσεις χρήσης
πιθανότατα θα χρησιμοποιήσετε μόνο ένα.

Εξειδικευμένα εξαρτήματα και φωλιασμός

Το Φρουρός θα μπορούσε να φωλιάσει. Απλά να θυμάστε ότι η πρόσβαση θα επιλύεται με τη σειρά από την πιο εξωτερική περίπτωση.

export const NestAppHeader: FC = () =&gt; { {
     const guardService = new SimpleGuard(),
     return (
         <header>
             <nav>
                 <ul>
                     <Guard<string&gt; requiredRoles={["USER", "ADMIN"]} guardService={guardService}&gt;
                         <Guard<string&gt; requiredRoles={["ADMIN"]} guardService={guardService}&gt;
                             <li>Στοιχείο μόνο για διαχειριστές</li>
                         </Guard>
                         <Guard<string&gt; requiredRoles={["USER"]} guardService={guardService}&gt;
                             <li>Συστατικό μόνο για τον χρήστη</li>
                         </Guard>
                         <li>Στοιχείο διαχειριστή και χρήστη</li>
                         <Guard<string&gt; requiredRoles={["MODERATOR"]} guardService={guardService}
                                        forbidden={() =&gt; <div>Απαγορευμένο - μόνο ο συντονιστής μπορεί να το δει αυτό</div>}>
                             <li>Συστατικό συντονιστή</li>
                         </Guard>
                     </Guard>
                     <li>Στοιχείο γενικής χρήσης</li>
                 </ul>
             </nav>
         </header>
     );
 }

Στο παραπάνω παράδειγμα Συστατικό συντονιστή δεν θα μπορούσε ποτέ να εμφανιστεί, επειδή ο χρήστης μπορεί να χειριστεί μόνο έναν ρόλο. Πρώτο Φρουρός όρια
ρόλους σε ADMIN και ΧΡΗΣΤΗΣ, οπότε ΣΥΝΤΟΝΙΣΤΗΣ δεν θα περάσει ποτέ τον πρώτο έλεγχο.

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

export const AdminGuard = (props: Omit) => {
return 
{props.children}

}

//...
export const SpecializedAppHeader: FC = () => { {
const guardService = new SimpleGuard(),
return (

Στοιχείο μόνο για διαχειριστές
 


Συστατικό μόνο για χρήστες


Forbidden - μόνο ο συντονιστής μπορεί να το δει αυτό
}>

Συστατικό συντονιστή



Συστατικό διαχειριστή και χρήστη

 

Στοιχείο γενικής χρήσης

);
}
```

Σε αυτή την περίπτωση AdminGuard προκαθορίστε το ADMIN ρόλο. Στις συνέπειες, πρέπει να ορίσουμε ρητά τον τύπο του ΡΟΛΟΣ τύπος
παράμετρος.

Συνοψίστε

Σε αυτό το άρθρο θα σας δείξω πώς να δημιουργήσετε και να χρησιμοποιήσετε Φρουρός συστατικό στο React. Ξεκινάμε από πολύπλοκο κώδικα που είναι δύσκολο να
να διαβάζει και να συντηρεί. Το εξελίσσουμε σε πιο φιλική προς τον προγραμματιστή κατάσταση και εισάγουμε προσαρμοσμένο λειτουργικό στοιχείο. Στη συνέχεια
επεκτείνετε το συστατικό προσθέτοντας επιπλέον λειτουργίες, αναδιαμορφώνετε την υπηρεσία εξαγωγής και τέλος προσθέτετε γενικούς τύπους.

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

Σχετικά άρθρα

Ανάπτυξη λογισμικού

Πλεονεκτήματα και μειονεκτήματα του React

Γιατί αξίζει να χρησιμοποιήσετε το React; Ποια πλεονεκτήματα έχει αυτή η βιβλιοθήκη JavaScript; Για να μάθετε τις απαντήσεις βουτήξτε σε αυτό το άρθρο και ανακαλύψτε τα πραγματικά οφέλη της χρήσης του React.

The Codest
Cezary Goralski Software Engineer

Εγγραφείτε στη βάση γνώσεών μας και μείνετε ενήμεροι για την τεχνογνωσία από τον τομέα της πληροφορικής.

    Σχετικά με εμάς

    The Codest - Διεθνής εταιρεία ανάπτυξης λογισμικού με κέντρα τεχνολογίας στην Πολωνία.

    Ηνωμένο Βασίλειο - Έδρα

    • Γραφείο 303B, 182-184 High Street North E6 2JA
      Λονδίνο, Αγγλία

    Πολωνία - Τοπικοί κόμβοι τεχνολογίας

    • Πάρκο γραφείων Fabryczna, Aleja
      Pokoju 18, 31-564 Κρακοβία
    • Πρεσβεία του εγκεφάλου, Konstruktorska
      11, 02-673 Βαρσοβία, Πολωνία

      The Codest

    • Αρχική σελίδα
    • Σχετικά με εμάς
    • Υπηρεσίες
    • Case Studies
    • Μάθετε πώς
    • Καριέρα
    • Λεξικό

      Υπηρεσίες

    • Συμβουλευτική
    • Ανάπτυξη λογισμικού
    • Backend Ανάπτυξη
    • Ανάπτυξη Frontend
    • Staff Augmentation
    • Backend Developers
    • Μηχανικοί cloud
    • Μηχανικοί δεδομένων
    • Άλλα
    • Μηχανικοί QA

      Πόροι

    • Γεγονότα και μύθοι σχετικά με τη συνεργασία με εξωτερικό συνεργάτη ανάπτυξης λογισμικού
    • Από τις ΗΠΑ στην Ευρώπη: Γιατί οι αμερικανικές νεοσύστατες επιχειρήσεις αποφασίζουν να μετεγκατασταθούν στην Ευρώπη
    • Σύγκριση υπεράκτιων κόμβων ανάπτυξης τεχνολογίας: Ευρώπη (Πολωνία), ASEAN (Φιλιππίνες), Ευρασία (Τουρκία)
    • Ποιες είναι οι κορυφαίες προκλήσεις των CTOs και των CIOs;
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Πνευματικά δικαιώματα © 2025 από The Codest. Όλα τα δικαιώματα διατηρούνται.

    elGreek
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek