Alfa Battle - how it was, conference recording and task list

In early June, we launched Alfa Battle for Java Developers. It's time to talk about how everything went, share useful videos from the speakers of the stream conference "Coding of the Future" (Alfa-Bank, Beeline, X5 Retail Group) and show our tasks. By the way, about the tasks. Either we overdid it and overestimated the possible participants, or the weather was so-so, in general, out of 1498 participants from 50 cities, no one completely solved all problems (5 pieces). Therefore, under the cut you will find all the tasks with a description and, if you want to solve them, you can do it without any deadlines. We will gladly invite those who master







... At the end of the post - about a new strategy for hiring specialists. There was a time when Alfa-Bank's IT was mostly concentrated in three cities - Moscow, St. Petersburg, Yekaterinburg. Now we can look at people from all over the country. And not only.



Thanks to everyone who responded - there were more than 1,500 such people, of which 198 guys reached the finals who showed the best results. Yes, it was not easy: the tasks turned out to be more difficult than many participants expected, and the format of the online championship with a conference stream, frankly, was tense. Still, 5 hours of online programming is not a retro experience in a team.



In total - three winners who received a cash prize, as well as invitations to work with us and with partners of the championship. Here they are:



1st place: Mikhail Burshtein, Moscow (250,000 rubles)

2nd place: Alexander Ilyushechkin, Moscow (150,000 rubles)

3rd place: Pavel Lyubinsky, St. Petersburg (100,000 rubles)



Tasks



# 1 Where is the ATM



Task details

Condition



-.

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 Analyze it



Task details



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 .



.





, , . , ( , - ).



:

  1. consumer-group-id. .
  2. 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 Free cash desk



Task details



- .

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 Elastic loans



Task details



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 On the promo needle



Task details



.

- .

.



REST API IP:8084 :



  • /promo – POST - ( , ). .
  • /receipt – , POST id , (, ), , , .




: /promo, /receipt.



* IP — IP .

* : github.com/evgenyshiryaev/alfa-battle-resources/tree/master/task5





  1. CSV :
  2. 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:



Video recordings of reports







All 16 reports from our guys and partners from Beeline and X5 Retail Group you can see on the event website .



So what about hiring?



Damir Battulin, our director of the online channels development department, spoke about hiring, the bank's strategic initiatives, the principles of teamwork on projects and the criteria for choosing new specialists for the development of digitalization.



: , - . , , , , . . , .



. , . , , . , . .




You can view all our current vacancies (IT, marketing, HR, etc.) on this page.



For lovers of details - the entire 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. , . – , , . , . , - , , , .



— , . ?



— , , , . , , , . .

. , , .



— ?



— – . . . , , , .



– . , -, . , , . , .



, , , , , . — , , , . .




All Articles