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 on juba olemas') } 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 }) }, } } })() TESTIMINE JAVASCRIPT... RUBY?! - The Codest
The Codest
  • Meie kohta
  • Teenused
    • Tarkvaraarendus
      • Frontend arendus
      • Backend arendus
    • Staff Augmentation
      • Frontend arendajad
      • Backend arendajad
      • Andmeinsenerid
      • Pilveinsenerid
      • QA insenerid
      • Muud
    • See nõuandev
      • Audit ja nõustamine
  • Tööstusharud
    • Fintech & pangandus
    • E-commerce
    • Adtech
    • Healthtech
    • Tootmine
    • Logistika
    • Autotööstus
    • IOT
  • Väärtus
    • CEO
    • CTO
    • Tarnejuht
  • Meie meeskond
  • Case Studies
  • Tea kuidas
    • Blogi
    • Kohtumised
    • Veebiseminarid
    • Ressursid
Karjäärivõimalused Võtke ühendust
  • Meie kohta
  • Teenused
    • Tarkvaraarendus
      • Frontend arendus
      • Backend arendus
    • Staff Augmentation
      • Frontend arendajad
      • Backend arendajad
      • Andmeinsenerid
      • Pilveinsenerid
      • QA insenerid
      • Muud
    • See nõuandev
      • Audit ja nõustamine
  • Väärtus
    • CEO
    • CTO
    • Tarnejuht
  • Meie meeskond
  • Case Studies
  • Tea kuidas
    • Blogi
    • Kohtumised
    • Veebiseminarid
    • Ressursid
Karjäärivõimalused Võtke ühendust
Tagasi nool TAGASI
2019-02-04
Tarkvaraarendus

TESTIMINE JAVASCRIPT... KOOS RUBY?!

Pawel Wal

Kuigi Codest on peamiselt Ruby pood, on üks paljudest projektidest, mida me ehitame, JavaScript. See on kliendipoolne raamatukogu, mis töötab üsna keerulises keskkonnas: see peab toetama peaaegu kõiki olemasolevaid brausereid, sealhulgas väga vanu, ning lisaks sellele suhtleb see veel hulga väliste skriptide ja teenustega. See on tohutult lõbus.

Kummaline juhtum mittekomplektsete sõltuvuste puhul

Ülaltoodud nõuetega kaasneb terve rida väljakutseid, mida tavaliselt kliendipoolses süsteemis ei esine. projektja üks nende küsimuste klass on seotud testimisega. Loomulikult on meil laitmatu hulk ühikteste ja me jooksutame neid oma CI/CD-keskkonnas väga suure hulga brauserite / operatsioonisüsteemide kombinatsioonide vastu, kuid see üksi ei uuri kõike, mis võib valesti minna.

Tulenevalt ökosüsteemi üldisest arhitektuurist, milles me tegutseme, sõltume sellest, et mõned välised raamatukogud laaditakse koos meie omadega - see tähendab, et me ei pakenda neid koos meie kood; me ei saa ja selle vastu pole midagi teha. See kujutab endast huvitavat väljakutset, sest need raamatukogud:

  • ei pruugi olla isegi olemas - kui keegi segab meie raamatukogu rakendamist,
  • võib olla olemas, kuid vales/mittesobivates versioonides,
  • võib olla muudetud mõne muu koodiga, mis on konkreetses rakenduses kaasas.

See näitab selgelt, miks ühiktestidest ei piisa: nad testivad reaalsest maailmast isoleeritult. Ütleme, et me mockime mõne välise raamatukogu avaliku API mingi osa, tuginedes sellele, mida me oleme avastanud selle dokumentides, ja käivitame selle vastu ühiktesti. Mida see tõestab?

Teil võib tekkida kiusatus öelda, et "see tähendab, et see töötab koos välise raamatukogu APIga", kuid te oleksite - kahjuks - valesti. See tähendab ainult seda, et see suhtleb korrektselt välise raamatukogu avaliku API alamhulgaga, ja isegi siis ainult selle versiooniga, mida me oleme jäljendanud.

Mis siis, kui raamatukogu muutub sõna otseses mõttes meie alt ära? Mis siis, kui see saab - seal looduses - mingeid kummalisi vastuseid, mis panevad selle sattuma teistsugusele, dokumenteerimata koodipolgule? Kas me saame selle eest üldse kaitsta?

Mõistlik kaitse

Mitte 100%, ei - keskkond on selleks liiga keeruline. Kuid me saame olla mõistlikult kindlad, et kõik töötab nii, nagu see peaks toimima, kasutades mõningaid üldistatud näiteid selle kohta, mis meie koodiga võib looduses juhtuda: me saame teha integratsioonitestimist. Ühiktestid tagavad, et meie kood töötab sisemiselt korralikult, ja integratsioonitestid peavad tagama, et me "räägime" korralikult raamatukogudega, mida me ei saa kontrollida. Ja ka mitte nende tüvedega - tegelike, elusate raamatukogudega.

Me võiksime lihtsalt kasutada ühte olemasolevatest integratsioonitesti raamistikest, et JavaScript, ehitame lihtsa HTML-lehe, esitame mõned kutsed meie raamatukogule ja kaugeleulatuvatele raamatukogudele ning anname sellele korraliku treeningu. Me ei taha aga üle ujutada ühtegi kaugteenuse lõpp-punkti meie CI/CD-keskkonna poolt genereeritud üleskutsetega. See segaks mõningaid statistilisi andmeid, võib-olla rikuks mõned asjad, ja - viimaks, kuid mitte vähemtähtsaks - me ei oleks väga tore, kui me teeksime kellegi toodangu meie testide osaks.

Aga kas integratsioonitestimine oli üldse võimalik? Kuna Ruby on meie esimene ja peamine armastus, siis toetusime oma teadmistele ja hakkasime mõtlema, kuidas me tavaliselt Ruby projektides kaugteenustega integratsioonitestimist teeme. Me võiksime kasutada midagi sellist nagu vcr gem, et salvestada kord toimuvat, ja siis jätkata selle taasesitamist meie testidele, kui see on vajalik.

Sisestage proxy

Vcr saavutab selle sisemiselt taotluste vahendamise teel. See oli meie a-ha! hetk. Me pidime iga päringu, mis ei tohiks "päris" internetis midagi tabada, proxy'ga edasi suunama mõnele stubed responses'ile. Siis antakse need sissetulevad andmed edasi välisele raamatukogule ja meie kood töötab nagu tavaliselt.

Kui prototüüpimine tundub keeruline, kasutame sageli Ruby't kui aja kokkuhoiu meetodit. Otsustasime teha meie JavaScript jaoks prototüübi testvaljuse Ruby's, et näha, kui hästi proxy idee töötab, enne kui võtame kohustuse ehitada midagi keerulisemat (võimalik, et) JavaScript's. See osutus üllatavalt lihtsaks. Tegelikult on see nii lihtne, et me ehitame selle artikli raames üheskoos ühe 🙂 .

Valgus, kaamera... oota, me unustasime rekvisiidid!

Loomulikult ei tegele me "päris asjaga" - isegi natuke sellest, mida me ehitame, selgitamine ületab kaugelt ühe blogipostituse ulatuse. Me saame ehitada midagi kiiret ja lihtsat, mis seisab kõnealuste raamatukogude eest ja siis keskenduda rohkem Ruby osale.

Kõigepealt on meil vaja midagi, mis asendaks välist raamatukogu, millega me tegeleme. Meil on vaja, et see näitaks paari käitumist: see peaks võtma ühendust välise teenusega, kiirgama siin ja seal sündmust ning - mis kõige tähtsam - ei peaks olema ehitatud lihtsat integreerimist silmas pidades 🙂 .

Siin on see, mida me kasutame:

/* global XMLHttpRequest, Event */

const URL = 'https://poloniex.com/public/?command=returnTicker'
const METHOD = 'GET'

module.exports = {
fetch: function () {
var req = new XMLHttpRequest()
req.responseType = 'json'
req.open(METHOD, URL, true)
var doneEvent = new Event('example:fetched')

req.onreadystatechange = function (aEvt) {
  if (req.readyState === 4) {
    if (req.status === 200) {
      this.data = req.response
    } else {
      this.error = true
    }
    window.dispatchEvent(doneEvent)
  }
}.bind(this)

req.send(null)

},
error: false,
data: {}
}

Sa märkad, et see kutsub avatud API-d mõnede andmete jaoks - antud juhul mõned krüptovaluuta vahetuskursid, kuna see on tänapäeval kogu raevu See API ei eksponeeri liivakasti ja see on rate-limited, mis teeb sellest suurepärase näite millestki, mida ei tohiks tegelikult testides tabada.

Te võite märgata, et see on tegelikult NPM-ühilduv moodul, samas kui ma vihjasin sellele, et skript, millega me tavaliselt tegeleme, ei ole NPM-is saadaval, et seda saaks hõlpsasti komplekteerida. Selle demonstratsiooni jaoks piisab sellest, et see näitab teatud käitumist, ja ma tahaksin siin pigem lihtsustada seletamist liigse lihtsustamise hinnaga.

Näitlejate kutsumine

Nüüd on meil vaja ka midagi, mis asendaks meie raamatukogu. Jällegi hoiame nõuded lihtsad: see peab kutsuma meie "välist" raamatukogu ja tegema midagi väljundiga. Selleks, et hoida "testitav" osa lihtsana, laseme tal teha ka kahekordset logimist: nii konsooli, mida on natuke raskem lugeda spetsifikatsioonides, kui ka globaalselt saadaval olevasse massiivi.

window.remote = require('remote-calling-example')

window.failedMiserably = true
window.logs = []

function log (message) {
window.logs.push(message)
console.log(message)
}

window.addEventListener('example:fetched', function () {
if (window.remote.error) {
log("[EXAMPLE] Remote fetch failed')
window.failedMiserably = true
} else {
log('[EXAMPLE] Remote fetch successful')
log([EXAMPLE] BTC to ETH: ${window.remote.data.BTC_ETH.last})
}
})

window.remote.fetch()

Ma hoian ka käitumise meelega hämmastavalt lihtsana. Nii nagu see on, on ainult kaks tegelikult huvitavat koodirada, mille jaoks spetsifitseerida, nii et me ei jää spetsifikaatide laviini alla, kui me ehitamise käigus edasi liigume.

See kõik lihtsalt klapib kokku

Viskame üles lihtsa HTML-lehe:

<code> <!DOCTYPE html>
 <html>
 <head>
   <title>Näidisleht</title>
   <script type="text/javascript" src="./index.js"></script>
 </head>
 <body></body>
 </html>

Selle demo tarbeks ühendame oma HTML ja JavaScript koos Pakett, väga lihtne veebirakendus komplekteerija. Mulle meeldib Parcel väga sellistel puhkudel, kui ma viskan kokku kiire näite või häkkisin mingi klassiidee. Kui teed midagi nii lihtsat, et Webpacki konfigureerimine võtaks rohkem aega kui soovitud koodi kirjutamine, on see parim.

See on ka piisavalt tagasihoidlik, et kui ma tahan vahetada midagi, mis on natuke rohkem lahingukatsetatud, ei pea ma tegema peaaegu mingit tagasilööki Parcelist, mida ei saa öelda Webpacki kohta. Märkus ettevaatust, aga - Parcel on raske arengu ja probleemid võivad ja ilmnevad; mul on olnud probleem, kus transpiled JavaScript väljund oli kehtetu vanemal Node.js. Lõpptulemus: ärge tehke seda veel oma tootmisprotsessi osaks, kuid proovige seda sellegipoolest.

Integratsiooni võimsuse rakendamine

Nüüd saame koostada oma testivalmisprogrammi.

Spetsifikaadi raamistiku enda jaoks kasutasime rspec. Arenduskeskkondades testime, kasutades tegelikku, mitteheadless Chrome'i - selle käivitamise ja kontrollimise ülesanne on langenud watir (ja selle usaldusväärne abiline watir-rspec). Meie proxy jaoks oleme kutsunud Puffing Billy ja rack peole. Lõpuks tahame oma JavaScript ehitust iga kord uuesti käivitada, kui käivitame spetsifikatsioonid, ja see saavutatakse järgmiselt. kokaiin.

See on terve hulk liikuvaid osi ja seega on meie spetsifitseerimise abimees isegi selles lihtsas näites mõnevõrra... kaasatud. Vaatame seda ja võtame selle lahti.

Dir['./spec/support/*/.rb'].each { |f| require f }

TEST_LOGGER = Logger.new(STDOUT)

RSpec.configure do |config|
config.before(:suite) { Cocaine::CommandLine.new('npm', 'run build', logger: TEST_LOGGER).run }

config.include Watir::RSpec::Helper
config.include Watir::RSpec::Matchers

config.include ProxySupport

config.order = :random
BrowserSupport.configure(config)
end

Billy.configure do |c|
c.cache = false
c.cacherequestheaders = false
c.persistcache = false
c.recordstubrequests = true
c.logger = Logger.new(File.expandpath('../log/billy.log', FILE))
end

Enne kogu komplekti käivitame oma kohandatud ehituskäsu läbi kokaiini. See konstant TEST_LOGGER võib olla natuke üle jõu käiv, kuid me ei ole siin väga mures objektide arvu pärast. Loomulikult käivitame specs'id juhuslikus järjekorras ja meil on vaja lisada kõik watir-rspec'i head asjad. Samuti peame seadistama Billy nii, et see ei teeks vahemälu, kuid ulatuslik logimine toimub spec/log/billy.log. Kui te ei tea, kas päring on tegelikult peatunud või tabab live-serverit (hups!), siis on see logi puhas kuld.

Olen kindel, et teie terav silm on juba märganud ProxySupport ja BrowserSupport. Sa võid arvata, et meie kohandatud maiuspalad istuvad seal... ja sul oleks täpselt õigus! Vaatame kõigepealt, mida BrowserSupport teeb.

Brauser, kontrollitud

Esmalt tutvustame TempBrowser:

klass TempBrowser
def get
@browser ||= Watir::Browser.new(web_driver)
end

def kill
@browser.close if @browser
@browser = nil
end

private

def web_driver
Selenium::WebDriver.for(:chrome, options: options)
end

def options
Selenium::WebDriver::Chrome::Options.new.tap do |options|
options.addargument '--auto-open-devtools-for-tabs'
options.addargument "--proxy-server=#{Billy.proxy.host}:#{Billy.proxy.port}"
end
end
end

Töötades tagasi läbi kõnepuu, näeme, et me seadistame Seleniumi brauseri valikute komplekti Chrome'ile. Üks valikuid, mida me sinna edastame, on meie seadistuses oluline: see annab Chrome'i instantsile korralduse edastada kõik meie Puffing Billy instantsi kaudu. Teine valik on lihtsalt tore - iga instants, mida me käivitame, mis ei ole peata avanevad kontrollivahendid automaatselt. See säästab meid lugematul hulgal Cmd+Alt+I'd päevas 😉.

Pärast seda, kui oleme seadistanud brauseri nende valikutega, edastame selle Watirile ja see ongi enam-vähem kõik. Veebileht tappa meetod on natuke suhkrut, mis võimaldab meil vajaduse korral draiverit korduvalt peatada ja taaskäivitada, ilma et TempBrowser'i instantsi ära visata.

Nüüd saame anda meie rspec näidetele paar supervõimet. Esiteks, me saame nutikaid brauser abimeetod, mille ümber meie spetsifikatsioonid enamasti keerlevad. Me saame kasutada ka praktilist meetodit, et taaskäivitada brauser konkreetse näite jaoks, kui me teeme midagi ülitundlikku. Loomulikult tahame ka brauseri pärast testikomplekti lõpetamist tappa, sest me ei taha mitte mingil juhul, et Chrome'i instantsid jääksid püsima - meie RAM-i huvides.

moodul BrowserSupport
def self.browser
@browser ||= TempBrowser.new
end

def self.configure(config)
config.around(:iga) do |example|
BrowserSupport.browser.kill if example.metadata[:clean]
@browser = BrowserSupport.browser.get
@browser.cookies.clear
@browser.driver.manage.timeouts.implicit_wait = 30
example.run
end

config.after(:suite) do
  BrowserSupport.browser.kill
end

end
end

Proxy ühendamine

Meil on loodud brauser ja spetsiifilised abimehed ning me oleme valmis alustama päringute edastamist meie proksile. Aga oodake, me ei ole seda veel seadistanud! Me võiksime iga näite jaoks korduvaid kutsungeid Billyle paugutada, kuid parem on hankida endale paar abimeetodit ja säästa paar tuhat klahvivajutust. See ongi see, mida ProxySupport teeb.

See, mida me kasutame oma testseadistuses, on veidi keerulisem, kuid siin on üldine idee:

frozenstringliteral: true

nõuda 'json'

moodul ProxySupport
HEADERS = {
'Access-Control-Allow-Methods' => 'GET',
'Access-Control-Allow-Headers' => 'X-Requested-With, X-Prototype-Version, Content-Type',
'Access-Control-Allow-Origin' => '*'
}.freeze

def stubjson(url, file)
Billy.proxy.stub(url).andreturn({
body: open(file).read,
code: 200,
headers: HEADERS.dup
})
end

def stubstatus(url, status)
Billy.proxy.stub(url).andreturn({
body: '',
code: status,
headers: HEADERS.dup
})
end

def stubpage(url, file)
Billy.proxy.stub(url).andreturn(
body: open(file).read,
content_type: 'text/html',
code: 200
)
end

def stubjs(url, file)
Billy.proxy.stub(url).andreturn(
body: open(file).read,
content_type: 'application/javascript',
code: 200
)
end
end

Me võime torkida:

  • HTML-lehe taotlused - meie peamise "mänguväljaku" lehe jaoks,
  • JS taotlused - meie komplekteeritud raamatukogu teenindamiseks,
  • JSON-päringud - taotluse esitamiseks kaugele API-le,
  • ja lihtsalt "mis tahes" taotlus, mille puhul meid huvitab ainult konkreetse, mitte-200 HTTP-vastuse tagastamine.

See sobib meie lihtsa näite jaoks hästi. Näidetest rääkides - me peaksime looma paar!

Hea külje testimine

Me peame kõigepealt ühendama paar "marsruuti" meie proxy jaoks:

let(:pageurl) { 'http://myfancypage.local/index.html' }
let(:jsurl) { 'http://myfancypage.local/dist/remote-caller-example.js' }

let(:pagepath) { './dist/index.html' }
let(:jspath) { './dist/remote-caller-example.js' }

before do
stubpage pageurl, pagepath
stubjs jsurl, jspath
end

Tasub märkida, et rspec'i seisukohalt viitavad suhtelised teed siin projekti põhikataloogile, seega laadime oma HTML-i ja JS-i otse kataloogist dist kataloogi - nagu on ehitatud Parcel'i poolt. Saate juba näha, kuidas need stub_* abilised tulevad kasuks.

Samuti tasub märkida, et me paigutame oma "võltsitud" veebilehe kohta .local TLD. Sel viisil ei tohiks meie kohalikust keskkonnast väljuda ühtegi väljapääsmatut taotlust, kui midagi läheb halvasti. Üldise tavana soovitaksin vähemalt mitte kasutada "päris" domeeninimesid stubides, kui see pole absoluutselt vajalik.

Teine märkus, mille me peaksime siinkohal tegema, on see, et me ei tohi ennast korrata. Kuna proxy marsruutimine muutub keerulisemaks, palju rohkemate teede ja URL-idega, on selle seadistuse väljavõtmine jagatud konteksti ja selle lihtne kaasamine vajaduse korral tõelist väärtust.

Nüüd saame täpsustada, kuidas meie "hea" tee peaks välja nägema:

kontekst 'õige vastusega' do
before do
stubjson %r{http://poloniex.com/public(.*)}, './spec/fixtures/remote.json'
goto pageurl
Watir::Wait.until { browser.execute_script('return window.logs.length === 2') }
end

it 'logib korralikud andmed' do
expect(browser.execute_script('return window.logs')).to(
eq(['[EXAMPLE] Remote fetch successful', '[EXAMPLE] BTC to ETH: 0.03619999'])
)
end
end

See on üsna lihtne, kas pole? Veel mõned seadistused siin - stubime JSON-vastuse kaug-API-st koos kinnitusega, läheme meie peamisele URLile ja siis... ootame.

Pikim ooteaeg

Ootused on viis, kuidas ümber käia piiranguga, millega me oleme Watiriga kokku puutunud - me ei saa usaldusväärselt oodata näiteks JavaScript sündmusi, seega peame natuke petma ja "ootama", kuni skriptid on liigutanud mõne objekti, millele meil on juurdepääs, meile huvipakkuvasse olekusse. Miinuseks on see, et kui seda olekut ei tule kunagi (näiteks vea tõttu), siis peame ootama, et watir waiter aeg maha võtaks. See ajab spec aega natuke üles. Spekter siiski usaldusväärselt ebaõnnestub.

Pärast seda, kui leht on "stabiliseerunud" meile huvipakkuvas olekus, saame sooritada veel mõned JavaScript lehekülje kontekstis. Siinkohal kutsume üles avalikku massiivi kirjutatud logid ja kontrollime, kas need on need, mida me ootasime.

Kõrvalmärkusena - siinkohal paistab kaugjuhtimispäringu stubbing tõesti silma. Vastus, mis konsooli logitakse, sõltub kaugjuhtimisplatvormi poolt tagastatud vahetuskursist, nii et me ei saaks usaldusväärselt testida logi sisu, kui see pidevalt muutuks. Loomulikult on võimalusi selle vältimiseks, kuid need ei ole väga elegantsed.

Halva haru testimine

Veel üks asi, mida testida: "ebaõnnestumise" haru.

kontekst 'ebaõnnestunud vastusega' do
before do
stubstatus %r{http://poloniex.com/public(.*)}, 404
goto pageurl
Watir::Wait.until { browser.execute_script('return window.logs.length === 1') }
end

it 'logide ebaõnnestumine' do
expect(browser.execute_script('return window.logs')).to(
eq(['[EXAMPLE] Remote fetch failed'])
)
end
end

See on väga sarnane ülaltooduga, erinevus seisneb selles, et me tagastame vastuseks HTTP-koodi 404 ja ootame teistsugust logi.

Käivitame nüüd meie spetsifikatsioonid.

% pakett exec rspec
Randomiseeritud seemnega 63792
I, [2017-12-21T14:26:08.680953 #7303] INFO -- : Command :: npm run build

Kaugkutsumine
õige vastusega
logib õiged andmed
ebaõnnestunud vastusega
logib ebaõnnestumise

Lõpetas 23,56 sekundiga (failide laadimine võttis aega 0,86547 sekundit).
2 näidet, 0 ebaõnnestumist

Woohoo!

Kokkuvõte

Me arutasime lühidalt, kuidas JavaScript saab integreerimist testida koos Ruby'ga. Kuigi algselt peeti seda pigem vahepealseks, oleme nüüd oma väikese prototüübiga üsna rahul. Loomulikult kaalume endiselt puhta JavaScript lahenduse loomist, kuid vahepeal on meil lihtne ja praktiline viis, kuidas reprodutseerida ja testida mõningaid väga keerulisi olukordi, millega oleme looduses kokku puutunud.

Kui te kaalute midagi sarnast ise ehitada, tuleb märkida, et see ei ole ilma piiranguteta. Näiteks kui teie testimine muutub väga AJAX-rohke, võtab Puffing Billy-l vastamine kaua aega. Samuti, kui teil on vaja mõned SSL-allikaid kasutada, on vaja veel veidi rohkem fiktsioone - vaadake watiri dokumentatsiooni, kui see on teie nõue. Kindlasti jätkame uurimist ja otsime parimaid viise meie unikaalse kasutusjuhtumi lahendamiseks - ja anname kindlasti ka teile teada, mida me välja leidsime.

Seotud artiklid

Tarkvaraarendus

Tulevikukindlate veebirakenduste loomine: The Codest ekspertide meeskonna ülevaade

Avastage, kuidas The Codest paistab skaleeritavate, interaktiivsete veebirakenduste loomisel silma tipptehnoloogiatega, mis pakuvad sujuvat kasutajakogemust kõigil platvormidel. Saate teada, kuidas meie eksperditeadmised aitavad kaasa digitaalsele ümberkujundamisele ja äritegevusele...

THECODEST
Tarkvaraarendus

Top 10 Lätis asuvat tarkvaraarendusettevõtet

Tutvu Läti parimate tarkvaraarendusettevõtete ja nende innovaatiliste lahendustega meie viimases artiklis. Avastage, kuidas need tehnoloogiajuhid saavad aidata teie äri edendada.

thecodest
Enterprise & Scaleups lahendused

Java tarkvaraarenduse põhitõed: A Guide to Outsourcing Successfully

Tutvuge selle olulise juhendiga, kuidas edukalt outsourcing Java tarkvara arendada, et suurendada tõhusust, pääseda ligi eksperditeadmistele ja edendada projekti edu The Codest abil.

thecodest
Tarkvaraarendus

Ülim juhend Poola allhanke kohta

outsourcing kasv Poolas on tingitud majanduslikust, hariduslikust ja tehnoloogilisest arengust, mis soodustab IT kasvu ja ettevõtlussõbralikku kliimat.

TheCodest
Enterprise & Scaleups lahendused

Täielik juhend IT-auditi vahendite ja tehnikate kohta

IT-auditid tagavad turvalised, tõhusad ja nõuetele vastavad süsteemid. Lisateavet nende tähtsuse kohta leiate kogu artiklist.

The Codest
Jakub Jakubowicz CTO & kaasasutajad

Tellige meie teadmistebaas ja jääge kursis IT-sektori eksperditeadmistega.

    Meie kohta

    The Codest - rahvusvaheline tarkvaraarendusettevõte, mille tehnoloogiakeskused asuvad Poolas.

    Ühendkuningriik - peakorter

    • Büroo 303B, 182-184 High Street North E6 2JA
      London, Inglismaa

    Poola - kohalikud tehnoloogiakeskused

    • Fabryczna büroopark, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Varssavi, Poola

      The Codest

    • Kodu
    • Meie kohta
    • Teenused
    • Case Studies
    • Tea kuidas
    • Karjäärivõimalused
    • Sõnastik

      Teenused

    • See nõuandev
    • Tarkvaraarendus
    • Backend arendus
    • Frontend arendus
    • Staff Augmentation
    • Backend arendajad
    • Pilveinsenerid
    • Andmeinsenerid
    • Muud
    • QA insenerid

      Ressursid

    • Faktid ja müüdid koostööst välise tarkvaraarenduspartneriga
    • USAst Euroopasse: Miks otsustavad Ameerika idufirmad Euroopasse ümber asuda?
    • Tech Offshore arenduskeskuste võrdlus: Euroopa (Poola), ASEAN (Filipiinid), Euraasia (Türgi).
    • Millised on CTO ja CIOde peamised väljakutsed?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Copyright © 2025 by The Codest. Kõik õigused kaitstud.

    etEstonian
    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 elGreek etEstonian