... À la fin de l'article - sur une nouvelle stratégie d'embauche de spécialistes. Il fut un temps où l'informatique d'Alfa-Bank était principalement concentrée dans trois villes - Moscou, Saint-Pétersbourg, Ekaterinbourg. Maintenant, nous pouvons regarder des gens de partout au pays. Et pas seulement.
Merci à tous ceux qui ont répondu - il y avait plus de 1500 personnes de ce type, dont 198 gars ont atteint la finale qui ont montré les meilleurs résultats. Oui, ce n'était pas facile: les tâches se sont avérées plus difficiles que ce que beaucoup de participants attendaient et le format du championnat en ligne avec un flux de conférence, franchement, était tendu. Pourtant, 5 heures de programmation en ligne ne sont pas une expérience rétro en équipe.
Au total, trois gagnants ont reçu un prix en argent, ainsi que des invitations à travailler pour nous et pour les partenaires du championnat. Les voici:
1ère place: Mikhail Burshtein, Moscou (250 000 roubles)
2e place: Alexander Ilyushechkin, Moscou (150 000 roubles)
3e place: Pavel Lyubinsky, Saint-Pétersbourg (100 000 roubles)
Tâches
# 1 Où est le guichet automatique
Détails de la tâche
-.
REST API IP:8080.
API – api.json.
- API .
: api.alfabank.ru/node/238
API .
: api.alfabank.ru/start
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task1
: GET IP:8080/atms/{deviceId}
:
— 200 AtmResponse
— 404 ErrorResponse ( )
:
:
18 .
- — .
3 ! -.
payments=true, (. - API ATMServices).
: GET IP:8080/atms/nearest?latitude=string&longitude=string&payments=boolean
: 200 AtmResponse
:
:
36 .
- .
, .
: GET IP:8080/atms/nearest-with-alfik?latitude=string&longitude=string&alfik=int
: 200 [AtmResponse]
, WebSocket STOMP .
:
( task1):
: ws://IP:8100
: { “deviceId”: 0 }
/topic/alfik: { “deviceId”: 0, “alfik”: 0 }
:
(.. 153463 — 383026 )
:
( , )
État
-.
REST API IP:8080.
API – api.json.
- API .
: api.alfabank.ru/node/238
API .
: api.alfabank.ru/start
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task1
1. deviceId
: GET IP:8080/atms/{deviceId}
:
— 200 AtmResponse
— 404 ErrorResponse ( )
:
GET http://IP:8080/atms/153463
200
{
"deviceId": 153463,
"latitude": "55.6610213",
"longitude": "37.6309405",
"city": "",
"location": " ., 4, . 10",
"payments": false
}
:
GET http://IP:8080/atms/1
404
{
“status”: “atm not found”
}
18 .
2. (-)
- — .
3 ! -.
payments=true, (. - API ATMServices).
: GET IP:8080/atms/nearest?latitude=string&longitude=string&payments=boolean
: 200 AtmResponse
:
GET http://IP:8080/atms/nearest?latitude=55.66&longitude=37.63
200
{
"deviceId": 153463,
"latitude": "55.6610213",
"longitude": "37.6309405",
"city": "",
"location": " ., 4, . 10",
"payments": false
}
:
GET http://IP:8080/atms/nearest?latitude=55.66&longitude=37.63&payments=true
200
{
"deviceId": 210612,
"latitude": "55.66442",
"longitude": "37.628051",
"city": "",
"location": " , . 14",
"payments": true
}
36 .
3.
- .
, .
: GET IP:8080/atms/nearest-with-alfik?latitude=string&longitude=string&alfik=int
: 200 [AtmResponse]
, WebSocket STOMP .
:
mkdir task1 ; cd task1
wget https://raw.githubusercontent.com/evgenyshiryaev/alfa-battle-resources/master/task1/docker-compose.yml
docker-compose up -d
( task1):
docker-compose down
: ws://IP:8100
: { “deviceId”: 0 }
/topic/alfik: { “deviceId”: 0, “alfik”: 0 }
:
GET http://IP:8080/atms/nearest-with-alfik?latitude=55.66&longitude=37.63&alfik=300000
200
[{
"deviceId": 153463,
"latitude": "55.6610213",
"longitude": "37.6309405",
"city": "",
"location": " ., 4, . 10",
"payments": false
}]
(.. 153463 — 383026 )
:
GET http://IP:8080/atms/nearest-with-alfik?latitude=55.66&longitude=37.63&alfik=400000
200
[{
"deviceId": 153463,
"latitude": "55.6610213",
"longitude": "37.6309405",
"city": "",
"location": " ., 4, . 10",
"payments": false
},
{
“deviceId": 153465,
"latitude": "55.6602801",
"longitude": "37.633823",
"city": "",
"location":" ., 18",
"payments": false
}]
( , )
# 2 Analysez-le
Détails de la tâche
Kafka RAW_PAYMENTS .
docker IP:29092 .
Kafka.
:
.
( task2):
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task2
:
, key1 — .
.
:
RAW_PAYMENTS. .
, .
, Kafka .
.
, , . , ( , - ).
:
start.sh, . ,
Swagger- api-swagger.json .
:
( categoryId).
, .
.
200
:
:
analyticInfo Id .
— 200
— 404 + {«status»:”user not found"} ( )
:
:
40 .
. :
— 200
— 404 + {«status»:”user not found"} ( )
.
:
60
.
:
, .
— 200
— 404 + {«status»:”user not found"} ( )
, .
:
Kafka RAW_PAYMENTS .
docker IP:29092 .
Kafka.
:
mkdir task2 ; cd task2
wget https://raw.githubusercontent.com/evgenyshiryaev/alfa-battle-resources/master/task2/data.txt
wget https://raw.githubusercontent.com/evgenyshiryaev/alfa-battle-resources/master/task2/docker-compose.yml
wget https://raw.githubusercontent.com/evgenyshiryaev/alfa-battle-resources/master/task2/start.sh
bash start.sh
.
( task2):
docker-compose down
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task2
:
key1:{"ref":"U030306190000188", "categoryId":1, "userId":"XAABAA", "recipientId":"XA3SZV", "desc":" ", "amount":10.0}
, key1 — .
.
:
- Kafka.
- .
- REST API . 8081.
RAW_PAYMENTS. .
, .
, Kafka .
.
, , . , ( , - ).
:
- consumer-group-id. .
- consumer-group. , , ,
docker exec -i broker kafka-consumer-groups --bootstrap-server broker:9092 --all-groups --all-topics --reset-offsets --to-earliest --execute
start.sh, . ,
Swagger-
Swagger- api-swagger.json .
:
key1:{"ref":"ref1", "categoryId":1, "userId":"User_1", "recipientId":"User_2", "desc":" _1", "amount":10.0}
key2:{"ref":"ref2", "categoryId":2, "userId":"User_1", "recipientId":"User_2", "desc":" _2", "amount":350.56}
key3:{"ref":"ref3", "categoryId":1, "userId":"User_1", "recipientId":"User_2", "desc":" _3", "amount":700.0}
key4:{"ref":"ref4", "categoryId":3, "userId":"User_1", "recipientId":"User_2", "desc":" _4", "amount":5.99}
key5:{"ref":"ref5", "categoryId":1, "userId":"User_1", "recipientId":"User_2", "desc":" _5", "amount":10.0}
key6:{"ref":"ref6", "categoryId":2, "userId":"User_2", "recipientId":"User_3", "desc":" _6", "amount":350.56}
key7:{"ref":"ref7", "categoryId":1, "userId":"User_1", "recipientId":"User_2", "desc":" _7", "amount":890.0}
key8:{"ref":"ref8", "categoryId":3, "userId":"User_3", "recipientId":"User_2", "desc":" _8", "amount":35.99}
key9:{"ref":"ref9", "categoryId":1, "userId":"User_1", "recipientId":"User_2", "desc":" _9", "amount":890.0}
key10:{"ref":"ref10", "categoryId":3, "userId":"User_3", "recipientId":"User_2", "desc":" _10", "amount":35.9910}
key11:{"ref":"ref11", "categoryId":1, "userId":"User_1", "recipientId":"User_2", "desc":" _11", "amount":10.0}
key12:{"ref":"ref12", "categoryId":2, "userId":"User_2", "recipientId":"User_3", "desc":" _12", "amount":350.56}
key13:{"ref":"ref13", "categoryId":1, "userId":"User_1", "recipientId":"User_2", "desc":" _13", "amount":10.0}
key14:{"ref":"ref14", "categoryId":2, "userId":"User_2", "recipientId":"User_3", "desc":" _14", "amount":350.56}
key15:{"ref":"ref15", "categoryId":4, "userId":"User_1", "recipientId":"User_4", "desc":" _15", "amount":15.00}
1.
( categoryId).
, .
.
GET IP:8081/admin/health
200
:
{"status":"UP"}
<h4>GET http://IP:8081/analytic</h4>
200
:
[
{
"userId": "User_3",
"totalSum": 71.981,
"analyticInfo": {
"3": {
"min": 35.99,
"max": 35.991,
"sum": 71.981
}
}
},
{
"userId": "User_2",
"totalSum": 1051.68,
"analyticInfo": {
"2": {
"min": 350.56,
"max": 350.56,
"sum": 1051.68
}
}
},
{
"userId": "User_1",
"totalSum": 2891.55,
"analyticInfo": {
"1": {
"min": 10,
"max": 890,
"sum": 2520
},
"2": {
"min": 350.56,
"max": 350.56,
"sum": 350.56
},
"3": {
"min": 5.99,
"max": 5.99,
"sum": 5.99
},
"4": {
"min": 15,
"max": 15,
"sum": 15
}
}
}
]
analyticInfo Id .
GET IP:8081/analytic/{userId}
— 200
— 404 + {«status»:”user not found"} ( )
:
GET http://IP:8081/analytic/User_1
:
{
"userId": "User_1",
"totalSum": 2891.55,
"analyticInfo": {
"1": {
"min": 10,
"max": 890,
"sum": 2520
},
"2": {
"min": 350.56,
"max": 350.56,
"sum": 350.56
},
"3": {
"min": 5.99,
"max": 5.99,
"sum": 5.99
},
"4": {
"min": 15,
"max": 15,
"sum": 15
}
}
}
40 .
2.
. :
GET IP:8081/analytic/{userId}/stats
— 200
— 404 + {«status»:”user not found"} ( )
.
:
GET http://IP:8081/analytic/User_1/stats
:
{
"oftenCategoryId": 1,
"rareCategoryId": 2,
"maxAmountCategoryId": 1,
"minAmountCategoryId": 3
}
60
3.
.
:
- , , (recipientId userId )
, .
GET IP:8081/analytic/{userId}/templates
— 200
— 404 + {«status»:”user not found"} ( )
, .
:
GET http://IP:8081/analytic/User_1/templates
:
[
{
"recipientId": "User_2",
"categoryId": 1,
"amount": 10
}
]
# 3 Caisse gratuite
Détails de la tâche
- .
REST API IP:8082.
API – api.json.
, , , , .
PostgreSQL.
PostgreSQL:
( task3):
: IP:5432
DB: alfa_battle
Auth: alfa_battle / qwe123
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task3
: GET IP:8082/branches/{id}
:
— 200 Branches
— 404 ErrorResponse ( )
:
:
8 .
-, , 1.
.
, Latitude Longitude.
: GET IP:8082/branches/lat=string&lon=string
: 200 Branches
:
Distance — , , .
28 .
, — , , , , .
.
: GET IP:8082/branches/{id}/predict?dayOfWeek=int&hourOfDay=int
:
— 200 BranchesWithPredicting
— 404 ErrorResponse ( )
:
dayOfWeek — , 1, 7
hourOfDay — 0 23
Predicting — , , .
:
.
, , apache-commons-math3
- .
REST API IP:8082.
API – api.json.
, , , , .
PostgreSQL.
PostgreSQL:
mkdir task3 ; cd task3
wget https://raw.githubusercontent.com/evgenyshiryaev/alfa-battle-resources/master/task3/docker-compose.yml
wget https://raw.githubusercontent.com/evgenyshiryaev/alfa-battle-resources/master/task3/Dockerfile
wget https://raw.githubusercontent.com/evgenyshiryaev/alfa-battle-resources/master/task3/init_db.sql
docker-compose up -d
( task3):
docker-compose down
: IP:5432
DB: alfa_battle
Auth: alfa_battle / qwe123
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task3
1. id
: GET IP:8082/branches/{id}
:
— 200 Branches
— 404 ErrorResponse ( )
:
GET http://IP:8082/branches/612
200
{
"id": 612,
"title": "",
"lon": 37.6329,
"lat": 55.7621,
"address": " ., 13, . 1"
}
:
GET http://IP:8082/branches/1
404
{
“status”: “branch not found”
}
8 .
2. (-)
-, , 1.
.
, Latitude Longitude.
: GET IP:8082/branches/lat=string&lon=string
: 200 Branches
:
GET http://IP:8082/branches/lat=55.773284&lon=37.624125
200
{
"id": 631,
"title": " ",
"lon": 37.6227,
"lat": 55.7695,
"address": " ., 16/1",
"distance": 430
}
Distance — , , .
28 .
3.
, — , , , , .
.
: GET IP:8082/branches/{id}/predict?dayOfWeek=int&hourOfDay=int
:
— 200 BranchesWithPredicting
— 404 ErrorResponse ( )
:
GET http://IP:8082/branches/612/predict?dayOfWeek=1&hourOfDay=14
200
{
"id": 612,
"title": "",
"lon": 37.6329,
"lat": 55.7621,
"address": " ., 13, . 1",
"dayOfWeek": 1,
"hourOfDay": 14,
"predicting": 117
}
dayOfWeek — , 1, 7
hourOfDay — 0 23
Predicting — , , .
:
GET http://IP:8082/branches/1/predict?dayOfWeek=1&hourOfDay=14
404
{
“status”: “branch not found”
}
.
, , apache-commons-math3
# 4 Prêts élastiques
Détails de la tâche
1 2 JSON:
person.json — , :
, :
ID — ,
DocId — ( 9 )
FIO —
Birthday — MM/dd/yyyy
Salary — , , .. 201.02 20102 .
Gender —
loans.json — , :
, :
Loan — ,
PersonId —
Amount — , , .. 201.02 20 102
StartDate — MM/dd/yyyy
Period —
, ElasticSearch .
REST- ElasticSearch, . IP:8083
ElasticSearch:
ElasticSearch IP:9200
( task4):
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task4
ElasticSearch :
persons
loans
GET IP:8083/admin/health
200
{«status»:«UP»}
ElasicSearch.
POST IP:8083/loans/loadPersons
200
{«status»:«OK»}
ElasicSearch.
, Document, ElasticSearch .
POST IP:8083/loans/loadLoans
200
{«status»:«OK»}
400 ( )
{
«status»: «person not found»
}
400 ( )
, — Document.
, :
countLoan —
sumAmountLoans —
loans —
, ( ElasticSearch).
1 2 JSON:
person.json — , :
{
"ID":"29",
"DocId":"702821510",
"FIO":"Phoebe Whitehouse",
"Birthday":"7/12/1971",
"Salary":"201.02",
"Gender":"F"
}
, :
ID — ,
DocId — ( 9 )
FIO —
Birthday — MM/dd/yyyy
Salary — , , .. 201.02 20102 .
Gender —
loans.json — , :
{
"Loan":"631553",
"PersonId":"68",
"Amount":"201.02",
"StartDate":"6/1/2019",
"Period":"1"
}
, :
Loan — ,
PersonId —
Amount — , , .. 201.02 20 102
StartDate — MM/dd/yyyy
Period —
, ElasticSearch .
REST- ElasticSearch, . IP:8083
ElasticSearch:
mkdir task4 ; cd task4
wget https://raw.githubusercontent.com/evgenyshiryaev/alfa-battle-resources/master/task4/docker-compose.yml
docker-compose up -d
ElasticSearch IP:9200
( task4):
docker-compose down
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task4
ElasticSearch :
persons
- Birthday — 1945-05-03
- Salary — ,
loans
- PersonId — , Document, DocId Persons.
- Amount — , .
- StartDate — , 1945-05-03
- Period — ,
GET IP:8083/admin/health
200
{«status»:«UP»}
ElasicSearch.
POST IP:8083/loans/loadPersons
200
{«status»:«OK»}
ElasicSearch.
, Document, ElasticSearch .
POST IP:8083/loans/loadLoans
200
{«status»:«OK»}
GET http://IP:8083/loans/getPerson/855406656/
200
{
"docid": "855406656",
"fio": "Celina Jackson",
"birthday": "1961-05-22",
"salary": 69106.0,
"gender": "F"
}
400 ( )
{
«status»: «person not found»
}
GET http://IP:8083/loans/getLoan/692826/
200
{
"loan": "692826",
"amount": 448900,
"document": "027665876",
"startdate": "2017-01-16",
"period": 48
}
400 ( )
{
"status": "loan not found"
}
, — Document.
GET http://IP:8083/loans/creditHistory/737767072/
200
{
"countLoan": 4,
"sumAmountLoans": 1058400.0,
"loans": [
{
"loan": "434224",
"amount": 7100,
"document": "737767072",
"startdate": "2019-09-18",
"period": 12
},
{
"loan": "917105",
"amount": 283600,
"document": "737767072",
"startdate": "2019-12-22",
"period": 12
},
{
"loan": "692147",
"amount": 300800,
"document": "737767072",
"startdate": "2016-08-01",
"period": 24
},
{
"loan": "145020",
"amount": 466900,
"document": "737767072",
"startdate": "2017-01-16",
"period": 36
}
]
}
, :
countLoan —
sumAmountLoans —
loans —
,
GET http://IP:8083/loans/creditClosed
200
[
{
"loan": "222398",
"amount": 265400,
"document": "074658188",
"startdate": "2017-09-22",
"period": 12
},
"loan": "826942",
"amount": 329400,
"document": "788117788",
"startdate": "2016-01-29",
"period": 48
},
...
]
, ( ElasticSearch).
GET http://IP:8083/loans/loansSortByPersonBirthday
200
[
{
"id": null,
"docid": "840704451",
"fio": "John Isaac",
"birthday": "19.08.1989",
"salary": 58295.0,
"gender": "M",
"loans": [
{
"loan": "771916",
"amount": 337600,
"document": "840704451",
"startdate": "2019-11-09",
"period": 48
},
{
"loan": "504544",
"amount": 358900,
"document": "840704451",
"startdate": "2018-06-10",
"period": 36
},
{
"loan": "699247",
"amount": 464400,
"document": "840704451",
"startdate": "2018-10-30",
"period": 36
},
{
"loan": "783101",
"amount": 139300,
"document": "840704451",
"startdate": "2017-02-19",
"period": 36
}
]
},
{
"id": null,
"docid": "023665566",
"fio": "Denny Tanner",
"birthday": "25.03.1989",
"salary": 80713.0,
"gender": "M",
"loans": [
{
"loan": "631553",
"amount": 403000,
"document": "023665566",
"startdate": "2019-06-01",
"period": 12
},
{
"loan": "598452",
"amount": 198500,
"document": "023665566",
"startdate": "2015-09-28",
"period": 36
},
{
"loan": "151915",
"amount": 13600,
"document": "023665566",
"startdate": "2019-06-15",
"period": 12
},
{
"loan": "368342",
"amount": 350500,
"document": "023665566",
"startdate": "2017-02-06",
"period": 48
},
{
"loan": "633056",
"amount": 482900,
"document": "023665566",
"startdate": "2016-07-01",
"period": 12
}
]
},
...
]
# 5 Sur l'aiguille promo
Détails de la tâche
.
- .
.
REST API IP:8084 :
: /promo, /receipt.
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task5
- , -, .
-, - .
- , -, .
2 RoundingMode.HALF_EVEN.
!!! , code review !!!
:
: POST IP:8084/promo
{}
: 200
: POST IP:8084/receipt
{
«shopId»: 1,
«loyaltyCard»: false,
«positions»:
[
{
«itemId»: «3432166»,
«quantity»: 1
}
]
}
: 200
{
«total»: 141.99,
«discount»: 0.00,
«positions»:
[
{
«id»: «3432166»,
«name»: «...G11 Green .1»,
«price»: 141.99,
«regularPrice»: 141.99
}
]
}
8 .
/promo - “ ” (LoyaltyCardRule). , .
- , /receipt loyaltyCard=true - , id .
:
: POST IP:8084/promo
: 200
: POST IP:8084/receipt
16 .
/promo - LoyaltyCardRule ItemCountRule. , .
N+k , N ID k . N=3, k=2:
.
- .
.
REST API IP:8084 :
- /promo – POST - ( , ). .
- /receipt – , POST id , (, ), , , .
: /promo, /receipt.
* IP — IP .
* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task5
- CSV :
- API – api.yml
- , -, .
-, - .
- , -, .
2 RoundingMode.HALF_EVEN.
!!! , code review !!!
1. -
:
: POST IP:8084/promo
{}
: 200
: POST IP:8084/receipt
{
«shopId»: 1,
«loyaltyCard»: false,
«positions»:
[
{
«itemId»: «3432166»,
«quantity»: 1
}
]
}
: 200
{
«total»: 141.99,
«discount»: 0.00,
«positions»:
[
{
«id»: «3432166»,
«name»: «...G11 Green .1»,
«price»: 141.99,
«regularPrice»: 141.99
}
]
}
8 .
2. -
/promo - “ ” (LoyaltyCardRule). , .
- , /receipt loyaltyCard=true - , id .
:
: POST IP:8084/promo
{
"loyaltyCardRules":
[
{
"shopId": -1,
"discount": 0.03
},
{
"shopId": 2,
"discount": 0.05
}
]
}
: 200
: POST IP:8084/receipt
{
"shopId": 1,
"loyaltyCard": false,
"positions":
[
{
"itemId": "3432166",
"quantity": 1
}
]
}
: 200
{
"total": 137.73,
"discount": 4.26,
"positions":
[
{
"id": "3432166",
"name": "...G11 Green .1",
"price": 137.73,
"regularPrice": 141.99
}
]
}
16 .
3. - N+k
/promo - LoyaltyCardRule ItemCountRule. , .
N+k , N ID k . N=3, k=2:
Enregistrements vidéo de rapports
Tous les 16 rapports de nos gars et partenaires de Beeline et X5 Retail Group que vous pouvez voir sur le site Web de l'événement .
Alors qu'en est-il de l'embauche?
Damir Battulin, notre directeur du département pour le développement des canaux en ligne, a évoqué l'embauche, les initiatives stratégiques de la banque, les principes du travail d'équipe sur les projets et les critères de choix de nouveaux spécialistes pour le développement de la digitalisation.
: , - . , , , , . . , .
. , . , , . , . .
Vous pouvez consulter toutes nos offres d'emploi actuelles (informatique, marketing, RH, etc.) sur cette page.
Pour les amateurs de détails - toute l'interview
- 100 . . , , . , - -, , .
— -, 2021 . . , , — . 7 12 . , , .
, - , . , , , , . , , ( , ): — , , -. , .
— ?
— , -.
— , , .
— . , . , , , .
, , — smart branch. – 400 . , , .
? , . , . , . , . , , .
, . , , , .
, , -. . , , , . , , , .
— ?
— : , - . , , , , . . , .
. , . , , . , . .
— ?
— – time to market. . , . . , , .
, , . smart branch , .
— , ?
— -. , . , . .
. , . — , . , . - , . . , : iOS- Lead product manager iOS, Chief product owner .
. 56, . 60%, 100%.
— ?
— , . , .
, chief product owner. , . – , , . , . , - , , , .
— , . ?
— , , , . , , , . .
. , , .
— ?
— – . . . , , , .
– . , -, . , , . , .
, , , , , . — , , , . .
— -, 2021 . . , , — . 7 12 . , , .
, - , . , , , , . , , ( , ): — , , -. , .
— ?
— , -.
— , , .
— . , . , , , .
, , — smart branch. – 400 . , , .
? , . , . , . , . , , .
, . , , , .
, , -. . , , , . , , , .
— ?
— : , - . , , , , . . , .
. , . , , . , . .
— ?
— – time to market. . , . . , , .
, , . smart branch , .
— , ?
— -. , . , . .
. , . — , . , . - , . . , : iOS- Lead product manager iOS, Chief product owner .
. 56, . 60%, 100%.
— ?
— , . , .
, chief product owner. , . – , , . , . , - , , , .
— , . ?
— , , , . , , , . .
. , , .
— ?
— – . . . , , , .
– . , -, . , , . , .
, , , , , . — , , , . .