рдмреИрдЪ рдХреНрд╡реЗрд░реА рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреА рд╕рдорд╕реНрдпрд╛рдПрдВ рдФрд░ рдЙрдирдХреЗ рд╕рдорд╛рдзрд╛рди (рднрд╛рдЧ 1)

рдмреИрдЪ рдХреНрд╡реЗрд░реА рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреА рд╕рдорд╕реНрдпрд╛рдПрдВ рдФрд░ рдЙрдирдХреЗ рд╕рдорд╛рдзрд╛рди (рднрд╛рдЧ 1)рд▓рдЧрднрдЧ рд╕рднреА рдЖрдзреБрдирд┐рдХ рд╕реЙрдлрд╝реНрдЯрд╡реЗрдпрд░ рдЙрддреНрдкрд╛рджреЛрдВ рдореЗрдВ рдХрдИ рд╕реЗрд╡рд╛рдПрдБ рд╢рд╛рдорд┐рд▓ рд╣реЛрддреА рд╣реИрдВред рдЕрдХреНрд╕рд░, рдЗрдВрдЯрд░рд╕рд░реНрд╡рд┐рд╕ рдЪреИрдирд▓реЛрдВ рдХрд╛ рд▓рдВрдмрд╛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдордп рдкреНрд░рджрд░реНрд╢рди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХрд╛ рдПрдХ рд╕реНрд░реЛрдд рдмрди рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рддрд░рд╣ рдХреА рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдорд╛рдирдХ рд╕рдорд╛рдзрд╛рди рдПрдХрд╛рдзрд┐рдХ рдЗрдВрдЯрд░рд╕рд░реНрд╡рд┐рд╕ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдПрдХ рдкреИрдХреЗрдЬ рдореЗрдВ рдкреИрдХ рдХрд░рдирд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдмреИрдЪрд┐рдВрдЧ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред

рдпрджрд┐ рдЖрдк рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдкреНрд░рджрд░реНрд╢рди рдпрд╛ рдХреЛрдб рд╕реНрдкрд╖реНрдЯрддрд╛ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдкрд░рд┐рдгрд╛рдореЛрдВ рд╕реЗ рдЦреБрд╢ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рддрд░реАрдХрд╛ рдХреЙрд▓ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХреЗ рд▓рд┐рдП рдЙрддрдирд╛ рдЖрд╕рд╛рди рдирд╣реАрдВ рд╣реИ рдЬрд┐рддрдирд╛ рдЖрдк рд╕реЛрдЪ рд╕рдХрддреЗ рд╣реИрдВред рд╡рд┐рднрд┐рдиреНрди рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдФрд░ рд╡рд┐рднрд┐рдиреНрди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ, рд╕рдорд╛рдзрд╛рди рдмрд╣реБрдд рднрд┐рдиреНрди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдореИрдВ рдХрдИ рджреГрд╖реНрдЯрд┐рдХреЛрдгреЛрдВ рдХреЗ рдлрд╛рдпрджреЗ рдФрд░ рдиреБрдХрд╕рд╛рди рджрд┐рдЦрд╛рдКрдВрдЧрд╛ред

рдкреНрд░рджрд░реНрд╢рди рдкрд░рд┐рдпреЛрдЬрдирд╛

рд╕реНрдкрд╖реНрдЯрддрд╛ рдХреЗ рд▓рд┐рдП, рдЖрдЗрдП рдЙрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реЗрд╡рд╛рдУрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рджреЗрдЦреЗрдВ рдЬрд┐рд╕ рдкрд░ рдореИрдВ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реВрдВред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдордВрдЪ рдЪрдпрди рдХреА рд╡реНрдпрд╛рдЦреНрдпрд╛рдЦрд╝рд░рд╛рдм рдкреНрд░рджрд░реНрд╢рди рдХреА рд╕рдорд╕реНрдпрд╛ рдХрд╛рдлреА рд╕рд╛рдорд╛рдиреНрдп рд╣реИ рдФрд░ рдпрд╣ рдХрд┐рд╕реА рд╡рд┐рд╢рд┐рд╖реНрдЯ рднрд╛рд╖рд╛ рдпрд╛ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддреА рд╣реИред рдпрд╣ рдЖрд▓реЗрдЦ рд╕рдорд╕реНрдпрд╛рдУрдВ рдФрд░ рд╕рдорд╛рдзрд╛рдиреЛрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдкреНрд░рд┐рдВрдЧ + рдХреЛрдЯрд▓рд┐рди рдХреЛрдб рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред рдХреЛрдЯрд▓рд┐рди рдЬрд╛рд╡рд╛ рдФрд░ рд╕реА# рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рд▓рд┐рдП рд╕рдорд╛рди рд░реВрдк рд╕реЗ рд╕рдордЭрдиреЗ рдпреЛрдЧреНрдп (рдпрд╛ рд╕рдордЭ рд╕реЗ рдмрд╛рд╣рд░) рд╣реИ, рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХреЛрдб рдЬрд╛рд╡рд╛ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЕрдзрд┐рдХ рдХреЙрдореНрдкреИрдХреНрдЯ рдФрд░ рд╕рдордЭрдиреЗ рдпреЛрдЧреНрдп рд╣реИред рд╢реБрджреНрдз рдЬрд╛рд╡рд╛ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рд╕рдордЭрдирд╛ рдЖрд╕рд╛рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдХреЛрдЯрд▓рд┐рди рдХреЗ рдХрд╛рд▓реЗ рдЬрд╛рджреВ рд╕реЗ рдмрдЪреВрдВрдЧрд╛ рдФрд░ рдХреЗрд╡рд▓ рд╕рдлреЗрдж рдЬрд╛рджреВ (рд▓реЛрдореНрдмреЛрдХ рдХреА рднрд╛рд╡рдирд╛ рдореЗрдВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛ред рдХреБрдЫ рд╡рд┐рд╕реНрддрд╛рд░ рд╡рд┐рдзрд┐рдпрд╛рдВ рд╣реЛрдВрдЧреА, рд▓реЗрдХрд┐рди рд╡реЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рднреА рдЬрд╛рд╡рд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЗ рд▓рд┐рдП рд╕реНрдерд┐рд░ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдПрдХ рдЫреЛрдЯреА рд╕реА рдЪреАрдиреА рд╣реЛрдЧреА рдЬреЛ рдбрд┐рд╢ рдХреЗ рд╕реНрд╡рд╛рдж рдХреЛ рдЦрд░рд╛рдм рдирд╣реАрдВ рдХрд░реЗрдЧреАред
рдПрдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдЕрдиреБрдореЛрджрди рд╕реЗрд╡рд╛ рд╣реИ. рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рдПрдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЙрд╕реЗ рдЪрд░реНрдЪрд╛ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рдХреЗ рджреМрд░рд╛рди рд╕рдВрдкрд╛рджрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЕрдВрддрддрдГ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдкрд░ рд╕рд╣рдорддрд┐ рд╣реЛрддреА рд╣реИред рдЕрдиреБрдореЛрджрди рд╕реЗрд╡рд╛ рд╕реНрд╡рдпрдВ рджрд╕реНрддрд╛рд╡реЗрдЬреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдЬрд╛рдирддреА рд╣реИ: рдпрд╣ рдХреЗрд╡рд▓ рдЫреЛрдЯреЗ рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдЕрдиреБрдореЛрджрдирдХрд░реНрддрд╛рдУрдВ рдХреА рдмрд╛рддрдЪреАрдд рд╣реИ рдЬрд┐рди рдкрд░ рд╣рдо рдпрд╣рд╛рдВ рд╡рд┐рдЪрд╛рд░ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗред

рддреЛ, рдЙрдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдореЗрдВ рдкреНрд░рддрд┐рднрд╛рдЧрд┐рдпреЛрдВ рдХреЗ рдкреВрд░реНрд╡рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд╕реЗрдЯ рдХреЗ рд╕рд╛рде рдЪреИрдЯ рд░реВрдо (рджрд╕реНрддрд╛рд╡реЗрдЬреЛрдВ рдХреЗ рдЕрдиреБрд░реВрдк) рд╣реИрдВред рдирд┐рдпрдорд┐рдд рдЪреИрдЯ рдХреА рддрд░рд╣, рд╕рдВрджреЗрд╢реЛрдВ рдореЗрдВ рдЯреЗрдХреНрд╕реНрдЯ рдФрд░ рдлрд╝рд╛рдЗрд▓реЗрдВ рд╣реЛрддреА рд╣реИрдВ рдФрд░ рдЗрдиреНрд╣реЗрдВ рдЙрддреНрддрд░ рдпрд╛ рдЕрдЧреНрд░реЗрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

data class ChatMessage(
  // nullable ╤В╨░╨║ ╨║╨░╨║ ╨┐╨╛╤П╨▓╨╗╤П╨╡╤В╤Б╤П ╤В╨╛╨╗╤М╨║╨╛ ╨┐╨╛╤Б╨╗╨╡ persist
  val id: Long? = null,
  /** ╨б╤Б╤Л╨╗╨║╨░ ╨╜╨░ ╨░╨▓╤В╨╛╤А╨░ */
  val author: UserReference,
  /** ╨б╨╛╨╛╨▒╤Й╨╡╨╜╨╕╨╡ */
  val message: String,
  /** ╨б╤Б╤Л╨╗╨║╨╕ ╨╜╨░ ╨░╤В╤В╨░╤З╨╕ */
  // ╨╕╨╖-╨╖╨░ ╨╛╤Б╨╛╨▒╨╡╨╜╨╜╨╛╤Б╤В╨╡╨╣ ╤Б╨▓╤П╨╖╨║╨╕ JPA+╨б╨г╨С╨Ф ╨┐╤А╨╛╤Й╨╡ ╨┐╨╛╨┤╨┤╨╡╤А╨╢╨╕╨▓╨░╤В╤М ╨╕ null, ╨╕ ╨┐╤Г╤Б╤В╤Л╨╡ ╤Б╨┐╨╕╤Б╨║╨╕
  val files: List<FileReference>? = null,
  /** ╨Х╤Б╨╗╨╕ ╤П╨▓╨╗╤П╨╡╤В╤Б╤П ╨╛╤В╨▓╨╡╤В╨╛╨╝, ╤В╨╛ ╨╖╨┤╨╡╤Б╤М ╨▒╤Г╨┤╨╡╤В ╨╛╤А╨╕╨│╨╕╨╜╨░╨╗ */
  val replyTo: ChatMessage? = null,
  /** ╨Х╤Б╨╗╨╕ ╤П╨▓╨╗╤П╨╡╤В╤Б╤П ╨┐╨╡╤А╨╡╤Б╤Л╨╗╨║╨╛╨╣, ╤В╨╛ ╨╖╨┤╨╡╤Б╤М ╨▒╤Г╨┤╨╡╤В ╨╛╤А╨╕╨│╨╕╨╜╨░╨╗ */
  val forwardFrom: ChatMessage? = null
)

рдлрд╝рд╛рдЗрд▓ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд▓рд┐рдВрдХ рдЕрдиреНрдп рдбреЛрдореЗрди рдХреЗ рд▓рд┐рдВрдХ рд╣реИрдВред рдпрд╣рд╛рдБ рд╣рдо рдЗрд╕ рддрд░рд╣ рд░рд╣рддреЗ рд╣реИрдВ:

typealias FileReference Long
typealias UserReference Long

рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдХреЛ Keycloak рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ REST рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣реА рдмрд╛рдд рдлрд╛рдЗрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рднреА рд▓рд╛рдЧреВ рд╣реЛрддреА рд╣реИ: рдлрд╝рд╛рдЗрд▓реЗрдВ рдФрд░ рдЙрдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдПрдХ рдЕрд▓рдЧ рдлрд╝рд╛рдЗрд▓ рднрдВрдбрд╛рд░рдг рд╕реЗрд╡рд╛ рдореЗрдВ рд░рд╣рддреА рд╣реИред

рдЗрди рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╕рднреА рдХреЙрд▓ рд╣реИрдВ рднрд╛рд░реА рдЕрдиреБрд░реЛрдз. рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ рдЗрди рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдкрд░рд┐рд╡рд╣рди рдХрд░рдиреЗ рдХрд╛ рдУрд╡рд░рд╣реЗрдб рдХрд┐рд╕реА рддреГрддреАрдп-рдкрдХреНрд╖ рд╕реЗрд╡рд╛ рджреНрд╡рд╛рд░рд╛ рд╕рдВрд╕рд╛рдзрд┐рдд рд╣реЛрдиреЗ рдореЗрдВ рд▓рдЧрдиреЗ рд╡рд╛рд▓реЗ рд╕рдордп рд╕реЗ рдХрд╣реАрдВ рдЕрдзрд┐рдХ рд╣реИред рд╣рдорд╛рд░реА рдкрд░реАрдХреНрд╖рдг рдмреЗрдВрдЪреЛрдВ рдкрд░, рдРрд╕реА рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдп рдХреЙрд▓ рд╕рдордп 100 рдПрдордПрд╕ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдЗрди рдирдВрдмрд░реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред

рд╣рдореЗрдВ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕рд╛рде рдЕрдВрддрд┐рдо N рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд░рд▓ REST рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╛рдиреА, рд╣рдорд╛рд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ рдлреНрд░рдВрдЯрдПрдВрдб рдореЗрдВ рд╕рдВрджреЗрд╢ рдореЙрдбрд▓ рд▓рдЧрднрдЧ рд╕рдорд╛рди рд╣реИ рдФрд░ рд╕рднреА рдбреЗрдЯрд╛ рднреЗрдЬрдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИред рдлреНрд░рдВрдЯ-рдПрдВрдб рдореЙрдбрд▓ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ рдлрд╝рд╛рдЗрд▓ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд▓рд┐рдВрдХ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдиреНрд╣реЗрдВ рдереЛрдбрд╝рд╛ рдбрд┐рдХреНрд░рд┐рдкреНрдЯреЗрдб рд░реВрдк рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

/** ╨Т ╤В╨░╨║╨╛╨╝ ╨▓╨╕╨┤╨╡ ╨╛╤В╨┤╨░╤О╤В╤Б╤П ╤Б╤Б╤Л╨╗╨║╨╕ ╨╜╨░ ╤Б╤Г╤Й╨╜╨╛╤Б╤В╨╕ ╨┤╨╗╤П ╤Д╤А╨╛╨╜╤В╨░ */
data class ReferenceUI(
  /** ╨Ш╨┤╨╡╨╜╤В╨╕╤Д╨╕╨║╨░╤В╨╛╤А ╨┤╨╗╤П url */
  val ref: String,
  /** ╨Т╨╕╨┤╨╕╨╝╨╛╨╡ ╨┐╨╛╨╗╤М╨╖╨╛╨▓╨░╤В╨╡╨╗╤О ╨╜╨░╨╖╨▓╨░╨╜╨╕╨╡ ╤Б╤Б╤Л╨╗╨║╨╕ */
  val name: String
)
data class ChatMessageUI(
  val id: Long,
  /** ╨б╤Б╤Л╨╗╨║╨░ ╨╜╨░ ╨░╨▓╤В╨╛╤А╨░ */
  val author: ReferenceUI,
  /** ╨б╨╛╨╛╨▒╤Й╨╡╨╜╨╕╨╡ */
  val message: String,
  /** ╨б╤Б╤Л╨╗╨║╨╕ ╨╜╨░ ╨░╤В╤В╨░╤З╨╕ */
  val files: List<ReferenceUI>,
  /** ╨Х╤Б╨╗╨╕ ╤П╨▓╨╗╤П╤В╤Б╤П ╨╛╤В╨▓╨╡╤В╨╛╨╝, ╤В╨╛ ╨╖╨┤╨╡╤Б╤М ╨▒╤Г╨┤╨╡╤В ╨╛╤А╨╕╨│╨╕╨╜╨░╨╗ */
  val replyTo: ChatMessageUI? = null,
  /** ╨Х╤Б╨╗╨╕ ╤П╨▓╨╗╤П╤В╤Б╤П ╨┐╨╡╤А╨╡╤Б╤Л╨╗╨║╨╛╨╣, ╤В╨╛ ╨╖╨┤╨╡╤Б╤М ╨▒╤Г╨┤╨╡╤В ╨╛╤А╨╕╨│╨╕╨╜╨░╨╗ */
  val forwardFrom: ChatMessageUI? = null
)

рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

interface ChatRestApi {
  fun getLast(nInt): List<ChatMessageUI>
}

рдпреВрдЖрдИ рдкреЛрд╕реНрдЯрдлрд╝рд┐рдХреНрд╕ рдХрд╛ рдЕрд░реНрде рд╣реИ рдлреНрд░рдВрдЯрдПрдВрдб рдХреЗ рд▓рд┐рдП рдбреАрдЯреАрдУ рдореЙрдбрд▓, рдпрд╛рдиреА, рд╣рдореЗрдВ рдЖрд░рдИрдПрд╕рдЯреА рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХреНрдпрд╛ рд╕реЗрд╡рд╛ рджреЗрдиреА рдЪрд╛рд╣рд┐рдПред

рдпрд╣рд╛рдВ рдЖрд╢реНрдЪрд░реНрдп рдХреА рдмрд╛рдд рдпрд╣ рд╣реЛ рд╕рдХрддреА рд╣реИ рдХрд┐ рд╣рдо рдХреЛрдИ рдЪреИрдЯ рдЖрдИрдбреА рдкрд╛рд╕ рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЪреИрдЯрдореИрд╕реЗрдЬ/рдЪреИрдЯрдореИрд╕реЗрдЬрдпреВрдЖрдИ рдореЙрдбрд▓ рдореЗрдВ рднреА рдХреЛрдИ рдирд╣реАрдВ рд╣реИред рдореИрдВрдиреЗ рдЬрд╛рдирдмреВрдЭрдХрд░ рдРрд╕рд╛ рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рдХреЛрдб рдХреЛ рдЕрд╡реНрдпрд╡рд╕реНрдерд┐рдд рди рдХрд┐рдпрд╛ рдЬрд╛рдП (рдЪреИрдЯ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдорд╛рди рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рд╣реИ)ред

рджрд╛рд░реНрд╢рдирд┐рдХ рд╡рд┐рд╖рдпрд╛рдВрддрд░ChatMessageUI рдХреНрд▓рд╛рд╕ рдФрд░ ChatRestApi.getLast рд╡рд┐рдзрд┐ рджреЛрдиреЛрдВ рд╕реВрдЪреА рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдЬрдм рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рдПрдХ рдСрд░реНрдбрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╕реЗрдЯ рд╣реЛрддрд╛ рд╣реИред рдпрд╣ рдЬреЗрдбреАрдХреЗ рдореЗрдВ рдЦрд░рд╛рдм рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реНрддрд░ рдкрд░ рддрддреНрд╡реЛрдВ рдХреЗ рдХреНрд░рдо рдХреЛ рдШреЛрд╖рд┐рдд рдХрд░рдирд╛ (рдЬреЛрдбрд╝рдиреЗ рдФрд░ рд╣рдЯрд╛рдиреЗ рдХреЗ рджреМрд░рд╛рди рдСрд░реНрдбрд░ рдХреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░рдирд╛) рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдЗрд╕рд▓рд┐рдП рдЙрди рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд╕реВрдЪреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЖрдо рдмрд╛рдд рд╣реЛ рдЧрдИ рд╣реИ рдЬрд╣рд╛рдВ рдПрдХ рдСрд░реНрдбрд░ рдХрд┐рдП рдЧрдП рд╕реЗрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ (рдПрдХ LinkedHashSet рднреА рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдирд╣реАрдВ рд╣реИ)ред
рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╕реАрдорд╛: рд╣рдо рдорд╛рди рд▓реЗрдВрдЧреЗ рдХрд┐ рдЙрддреНрддрд░реЛрдВ рдпрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рдгреЛрдВ рдХреА рдХреЛрдИ рд▓рдВрдмреА рд╢реНрд░реГрдВрдЦрд▓рд╛ рдирд╣реАрдВ рд╣реИред рдпрд╛рдиреА рд╡реЗ рдореМрдЬреВрдж рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЙрдирдХреА рд▓рдВрдмрд╛рдИ рддреАрди рд╕рдВрджреЗрд╢реЛрдВ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реИред рд╕рдВрджреЗрд╢реЛрдВ рдХреА рдкреВрд░реА рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХреЛ рдлреНрд░рдВрдЯрдПрдВрдб рдкрд░ рдкреНрд░реЗрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛рдУрдВ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдПрдкреАрдЖрдИ рд╣реИрдВ:

interface ChatMessageRepository {
  fun findLast(nInt): List<ChatMessage>
}
data class FileHeadRemote(
  val id: FileReference,
  val name: String
)
interface FileRemoteApi {
  fun getHeadById(idFileReference): FileHeadRemote
  fun getHeadsByIds(idSet<FileReference>): Set<FileHeadRemote>
  fun getHeadsByIds(idList<FileReference>): List<FileHeadRemote>
  fun getHeadsByChat(): List<FileHeadRemote>
}
data class UserRemote(
  val id: UserReference,
  val name: String
)
interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote>
  fun getUsersByIds(idList<UserReference>): List<UserRemote>
}

рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛рдПрдБ рд╢реБрд░реВ рдореЗрдВ рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдкреНрд░рджрд╛рди рдХрд░рддреА рд╣реИрдВ, рдФрд░ рджреЛрдиреЛрдВ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ: рд╕реЗрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ (рддрддреНрд╡реЛрдВ рдХреЗ рдХреНрд░рдо рдХреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд┐рдП рдмрд┐рдирд╛, рдЕрджреНрд╡рд┐рддреАрдп рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде) рдФрд░ рд╕реВрдЪреА рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ (рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ - рдСрд░реНрдбрд░ рд╕рдВрд░рдХреНрд╖рд┐рдд рд╣реИ)ред

рд╕рд░рд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди

рдЕрдиреБрднрд╡рд╣реАрди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди

рд╣рдорд╛рд░реЗ REST рдирд┐рдпрдВрддреНрд░рдХ рдХрд╛ рдкрд╣рд▓рд╛ рдЕрдиреБрднрд╡рд╣реАрди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:

class ChatRestController(
  private val messageRepository: ChatMessageRepository,
  private val userRepository: UserRemoteApi,
  private val fileRepository: FileRemoteApi
) : ChatRestApi {
  override fun getLast(nInt) =
    messageRepository.findLast(n)
      .map it.toFrontModel() }
  
  private fun ChatMessage.toFrontModel(): ChatMessageUI =
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = userRepository.getUserById(author).toFrontReference(),
      message = message,
      files = files?.let files ->
        fileRepository.getHeadsByIds(files)
          .map it.toFrontReference() }
      } ?: listOf(),
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
}

рд╕рдм рдХреБрдЫ рдмрд╣реБрдд рд╕реНрдкрд╖реНрдЯ рд╣реИ, рдФрд░ рдпрд╣ рдПрдХ рдмрдбрд╝рд╛ рдкреНрд▓рд╕ рд╣реИред

рд╣рдо рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдмреИрдЪреЛрдВ рдореЗрдВ рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реА рдЙрддреНрдкрд╛рджрдХрддрд╛ рдХрд╛ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ?

рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрджреЗрд╢ рдХреЗ рд▓рд┐рдП, рд▓реЗрдЦрдХ рдлрд╝реАрд▓реНрдб рдкрд░ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП UserRemoteApi рдкрд░ рдПрдХ рдХреЙрд▓ рдХреА рдЬрд╛рдПрдЧреА рдФрд░ рд╕рднреА рд╕рдВрд▓рдЧреНрди рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП FileRemoteApi рдкрд░ рдПрдХ рдХреЙрд▓ рдХреА рдЬрд╛рдПрдЧреАред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдЬреИрд╕реЗ рдмрд╕ рдпрд╣реА рд╣реИ. рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдЪреИрдЯрдореИрд╕реЗрдЬ рдХреЗ рд▓рд┐рдП рдлреЙрд░рд╡рд░реНрдбрдлреНрд░реЙрдо рдФрд░ рд░рд┐рдкреНрд▓рд╛рдИрдЯреВ рдлрд╝реАрд▓реНрдб рдЗрд╕ рддрд░рд╣ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЕрдирд╛рд╡рд╢реНрдпрдХ рдХреЙрд▓ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред рд▓реЗрдХрд┐рди рдЙрдиреНрд╣реЗрдВ ChatMessageUI рдореЗрдВ рдмрджрд▓рдиреЗ рд╕реЗ рд░рд┐рдХрд░реНрд╕рди рд╣реЛ рдЬрд╛рдПрдЧрд╛, рдпрд╛рдиреА рдХреЙрд▓ рдХрд╛рдЙрдВрдЯрд░ рдХрд╛рдлреА рдмрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рдкрд╣рд▓реЗ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рд╣реИ, рдЖрдЗрдП рдорд╛рди рд▓реЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдиреЗрд╕реНрдЯрд┐рдВрдЧ рдирд╣реАрдВ рд╣реИ рдФрд░ рд╢реНрд░реГрдВрдЦрд▓рд╛ рддреАрди рд╕рдВрджреЗрд╢реЛрдВ рддрдХ рд╕реАрдорд┐рдд рд╣реИред

рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдореЗрдВ рдкреНрд░рддрд┐ рд╕рдВрджреЗрд╢ рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рджреЛ рд╕реЗ рдЫрд╣ рдХреЙрд▓ рдФрд░ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рдкреВрд░реЗ рдкреИрдХреЗрдЬ рдХреЗ рд▓рд┐рдП рдПрдХ рдЬреЗрдкреАрдП рдХреЙрд▓ рдорд┐рд▓реЗрдЧреАред рдХреЙрд▓ рдХреА рдХреБрд▓ рд╕рдВрдЦреНрдпрд╛ 2*N+1 рд╕реЗ 6*N+1 рддрдХ рднрд┐рдиреНрди-рднрд┐рдиреНрди рд╣реЛрдЧреАред рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЗрдХрд╛рдЗрдпреЛрдВ рдореЗрдВ рдпрд╣ рдХрд┐рддрдирд╛ рд╣реИ? рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдПрдХ рдкреЗрдЬ рдХреЛ рд░реЗрдВрдбрд░ рдХрд░рдиреЗ рдореЗрдВ 20 рд╕рдВрджреЗрд╢ рд▓рдЧрддреЗ рд╣реИрдВред рдЗрдиреНрд╣реЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ 4 рд╕реЗрдХрдВрдб рд╕реЗ 10 рд╕реЗрдХрдВрдб рддрдХ рдХрд╛ рд╕рдордп рд▓рдЧреЗрдЧрд╛ред рднрдпрд╛рдирдХ! рдореИрдВ рдЗрд╕реЗ 500 рдПрдордПрд╕ рдХреЗ рднреАрддрд░ рд░рдЦрдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред рдФрд░ рдЪреВрдВрдХрд┐ рдЙрдиреНрд╣реЛрдВрдиреЗ рдлреНрд░рдВрдЯрдПрдВрдб рдореЗрдВ рдирд┐рд░реНрдмрд╛рдз рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдмрдирд╛рдиреЗ рдХрд╛ рд╕рдкрдирд╛ рджреЗрдЦрд╛ рдерд╛, рдЗрд╕рд▓рд┐рдП рдЗрд╕ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд░реНрд╢рди рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЛ рджреЛрдЧреБрдирд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдкреЗрд╢реЗрд╡рд░реЛрдВ:

  1. рдХреЛрдб рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдФрд░ рд╕реНрд╡-рджрд╕реНрддрд╛рд╡реЗрдЬреАрдХрд░рдг (рдПрдХ рд╕рд╣рд╛рдпрддрд╛ рдЯреАрдо рдХрд╛ рд╕рдкрдирд╛) рд╣реИред
  2. рдХреЛрдб рд╕рд░рд▓ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЕрдкрдиреЗ рдкреИрд░реЛрдВ рдкрд░ рдХреБрд▓реНрд╣рд╛рдбрд╝реА рдорд╛рд░рдиреЗ рдХрд╛ рд▓рдЧрднрдЧ рдХреЛрдИ рдЕрд╡рд╕рд░ рдирд╣реАрдВ рд╣реИред
  3. рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХрд┐рд╕реА рд╡рд┐рджреЗрд╢реА рдЪреАрдЬрд╝ рдХреА рддрд░рд╣ рдирд╣реАрдВ рджрд┐рдЦрддреА рд╣реИ рдФрд░ рдЗрд╕реЗ рддрд░реНрдХ рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рд░реВрдк рд╕реЗ рдПрдХреАрдХреГрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред
  4. рддрд░реНрдХ рдкрд░рд┐рд╡рд░реНрддрди рдЖрд╕рд╛рдиреА рд╕реЗ рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗ рдФрд░ рд╕реНрдерд╛рдиреАрдп рд╣реЛрдВрдЧреЗред

рдХрдо:

рдмрд╣реБрдд рдЫреЛрдЯреЗ рдкреИрдХреЗрдЯреЛрдВ рдХреЗ рдХрд╛рд░рдг рднрдпрд╛рдирдХ рдкреНрд░рджрд░реНрд╢рдиред

рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдЕрдХреНрд╕рд░ рд╕рд░рд▓ рд╕реЗрд╡рд╛рдУрдВ рдпрд╛ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдореЗрдВ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдпрджрд┐ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░рдиреЗ рдХреА рдЧрддрд┐ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ, рддреЛ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рдЬрдЯрд┐рд▓ рдмрдирд╛рдирд╛ рд╢рд╛рдпрдж рд╣реА рдЗрд╕рдХреЗ рд▓рд╛рдпрдХ рд╣реИред рд╕рд╛рде рд╣реА, рд╣рдорд╛рд░реА рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд░реНрд╢рди рднрдпрд╛рдирдХ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреА рдкреНрд░рдпреЛрдЬреНрдпрддрд╛ рдХрд╛ рджрд╛рдпрд░рд╛ рдмрд╣реБрдд рд╕рдВрдХреАрд░реНрдг рд╣реИред

рдЕрдиреБрднрд╡рд╣реАрди рд╕рдорд╛рдирд╛рдВрддрд░ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг

рдЖрдк рд╕рднреА рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - рдЗрд╕рд╕реЗ рдЖрдкрдХреЛ рд╕рдВрджреЗрд╢реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╕рдордп рдореЗрдВ рд░реИрдЦрд┐рдХ рд╡реГрджреНрдзрд┐ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдорд┐рд▓ рд╕рдХреЗрдЧрд╛ред рдпрд╣ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЕрдЪреНрдЫрд╛ рдорд╛рд░реНрдЧ рдирд╣реАрдВ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдмрд╛рд╣реНрдп рд╕реЗрд╡рд╛ рдкрд░ рдЕрддреНрдпрдзрд┐рдХ рднрд╛рд░ рдкрдбрд╝реЗрдЧрд╛ред

рд╕рдорд╛рдирд╛рдВрддрд░ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИ:

override fun getLast(nInt) =
  messageRepository.findLast(n).parallelStream()
    .map it.toFrontModel() }
    .collect(toList())

рд╕рдорд╛рдирд╛рдВрддрд░ рд╕рдВрджреЗрд╢ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдореЗрдВ рдЖрджрд░реНрд╢ рд░реВрдк рд╕реЗ 300-700 рдПрдордПрд╕ рдорд┐рд▓рддреЗ рд╣реИрдВ, рдЬреЛ рдПрдХ рд╕рд░рд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдмрд╣реБрдд рдмреЗрд╣рддрд░ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдкрд░реНрдпрд╛рдкреНрдд рддреЗрдЬрд╝ рдирд╣реАрдВ рд╣реИред

рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рд╛рде, userRepository рдФрд░ fileRepository рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕рдордХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬреЛ рдмрд╣реБрдд рдХреБрд╢рд▓ рдирд╣реАрдВ рд╣реИред рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдХреЙрд▓ рд▓реЙрдЬрд┐рдХ рдореЗрдВ рдХрд╛рдлреА рдмрджрд▓рд╛рд╡ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХрдВрдкреНрд▓реАрд╢рдирд╕реНрдЯреЗрдЬ (рдЙрд░реНрдл рдХрдВрдкреНрд▓реАрдЯреЗрдмрд▓рдлреНрдпреВрдЪрд░) рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ:

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  CompletableFuture.supplyAsync {
    userRepository.getUserById(author).toFrontReference()
  }.thenCombine(
    files?.let {
      CompletableFuture.supplyAsync {
        fileRepository.getHeadsByIds(files).map it.toFrontReference() }
      }
    } ?: CompletableFuture.completedFuture(listOf())
  ) authorfiles ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }.get()!!

рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рд╛рд░рдВрдн рдореЗрдВ рд╕рд░рд▓ рдореИрдкрд┐рдВрдЧ рдХреЛрдб рдХрдо рд╕рдордЭ рдореЗрдВ рдЖрдиреЗ рд▓рдЧрд╛ рд╣реИред рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╣рдореЗрдВ рдХреЙрд▓ рдХреЛ рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛рдУрдВ рд╕реЗ рдЕрд▓рдЧ рдХрд░рдирд╛ рдерд╛ рдЬрд╣рд╛рдВ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпреЗ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдмреБрд░рд╛ рдирд╣реАрдВ рд╣реИ. рд▓реЗрдХрд┐рди рдХреЙрд▓реЛрдВ рдХрд╛ рд╕рдВрдпреЛрдЬрди рдмрд╣реБрдд рд╕реБрдВрджрд░ рдирд╣реАрдВ рджрд┐рдЦрддрд╛ рд╣реИ рдФрд░ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ "рдиреВрдбрд▓" рдЬреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИред

рдпрджрд┐ рдЖрдк рдХреЛрд░рдЖрдЙрдЯрд┐рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╕рдм рдХреБрдЫ рдЕрдзрд┐рдХ рд╕рднреНрдп рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛:

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  join(
    userRepository.getUserById(author).toFrontReference() },
    files?.let fileRepository.getHeadsByIds(files)
      .map it.toFrontReference() } } ?: listOf() }
  ).let (author, files) ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }

рдХрд╣рд╛рдБ:

fun <ABjoin(a: () -> Ab: () -> B) =
  runBlocking(IO{
    awaitAll(async a() }async b() })
  }.let {
    it[0as to it[1as B
  }

рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рд░реВрдк рд╕реЗ, рдЗрд╕ рддрд░рд╣ рдХреЗ рд╕рдорд╛рдирд╛рдВрддрд░ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рд╣рдореЗрдВ 200-400 рдПрдордПрд╕ рдорд┐рд▓реЗрдЧрд╛, рдЬреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╣рдорд╛рд░реА рдЕрдкреЗрдХреНрд╖рд╛рдУрдВ рдХреЗ рдХрд░реАрдм рд╣реИред

рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдЗрддрдирд╛ рдЕрдЪреНрдЫрд╛ рд╕рдорд╛рдирд╛рдВрддрд░реАрдХрд░рдг рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ, рдФрд░ рднреБрдЧрддрд╛рди рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдХреАрдордд рдХрд╛рдлреА рдХреНрд░реВрд░ рд╣реИ: рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдХреЗрд╡рд▓ рдХреБрдЫ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдХрд╛рдо рдХрд░рдиреЗ рд╕реЗ, рд╕реЗрд╡рд╛рдУрдВ рдкрд░ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреА рдмреМрдЫрд╛рд░ рд╣реЛ рдЬрд╛рдПрдЧреА, рдЬрд┐рдиреНрд╣реЗрдВ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╕ 4 рдПрд╕ рдореЗрдВ рд▓реМрдЯ рдЖрдПрдВрдЧреЗред

рдРрд╕реА рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдореЗрд░рд╛ рдкрд░рд┐рдгрд╛рдо 1300 рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП 1700-20 рдПрдордПрд╕ рд╣реИред рдпрд╣ рдкрд╣рд▓реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рддреЗрдЬрд╝ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

рд╕рдорд╛рдирд╛рдВрддрд░ рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рдЙрдкрдпреЛрдЧрдпрджрд┐ рддреГрддреАрдп-рдкрдХреНрд╖ рд╕реЗрд╡рд╛рдПрдБ рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдкреНрд░рджрд╛рди рдирд╣реАрдВ рдХрд░рддреА рд╣реИрдВ рддреЛ рдХреНрдпрд╛ рд╣реЛрдЧрд╛? рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдк рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рдЕрдВрджрд░ рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рдХрдореА рдХреЛ рдЫрд┐рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ:

interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toSet())
  fun getUsersByIds(idList<UserReference>): List<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toList())
}

рдпрджрд┐ рдЖрдк рднрд╡рд┐рд╖реНрдп рдХреЗ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рджреЗрдЦрдиреЗ рдХреА рдЖрд╢рд╛ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдпрд╣ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИред
рдкреЗрд╢реЗрд╡рд░реЛрдВ:

  1. рд╕рдВрджреЗрд╢-рдЖрдзрд╛рд░рд┐рдд рд╕рдорд╛рдирд╛рдВрддрд░ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░реЗрдВред
  2. рдЕрдЪреНрдЫреА рдорд╛рдкрдиреАрдпрддрд╛.

рд╡рд┐рдкрдХреНрд╖:

  1. рд╡рд┐рднрд┐рдиреНрди рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддреЗ рд╕рдордп рдбреЗрдЯрд╛ рдЕрдзрд┐рдЧреНрд░рд╣рдг рдХреЛ рдЙрд╕рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рд╕реЗ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ред
  2. рддреГрддреАрдп-рдкрдХреНрд╖ рд╕реЗрд╡рд╛рдУрдВ рдкрд░ рдмрдврд╝рд╛ рд╣реБрдЖ рднрд╛рд░ред

рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рдпреЛрдЬреНрдпрддрд╛ рдХрд╛ рджрд╛рдпрд░рд╛ рд▓рдЧрднрдЧ рдЕрдиреБрднрд╡рд╣реАрди рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рдорд╛рди рд╣реА рд╣реИред рдпрджрд┐ рдЖрдк рджреВрд╕рд░реЛрдВ рдХреЗ рдмреЗрд░рд╣рдо рд╢реЛрд╖рдг рдХреЗ рдХрд╛рд░рдг рдЕрдкрдиреА рд╕реЗрд╡рд╛ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдХрдИ рдЧреБрдирд╛ рдмрдврд╝рд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рддреЛ рд╕рдорд╛рдирд╛рдВрддрд░ рдЕрдиреБрд░реЛрдз рдкрджреНрдзрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдкреНрд░рджрд░реНрд╢рди 2,5 рдЧреБрдирд╛ рдмрдврд╝ рдЧрдпрд╛, рд▓реЗрдХрд┐рди рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИред

рдХреИрд╢рд┐рдВрдЧ

рдЖрдк рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЬреЗрдкреАрдП рдХреА рднрд╛рд╡рдирд╛ рд╕реЗ рдХреИрд╢рд┐рдВрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛рдиреА рдкреНрд░рд╛рдкреНрдд рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдПрдХ рд╕рддреНрд░ рдХреЗ рднреАрддрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдЙрдиреНрд╣реЗрдВ рджреЛрдмрд╛рд░рд╛ рдкреНрд░рд╛рдкреНрдд рди рдХрд░реЗрдВ (рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рд╕рд╣рд┐рдд)ред рдЖрдк рдРрд╕реЗ рдХреИрд╢ рд╕реНрд╡рдпрдВ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЖрдк рд╕реНрдкреНрд░рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЗрд╕рдХреЗ @Cacheable рдХреЗ рд╕рд╛рде рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рд╛рде рд╣реА рдЖрдк рд╣рдореЗрд╢рд╛ EhCache рдЬреИрд╕реЗ рддреИрдпрд╛рд░ рдХреИрд╢ рдХрд╛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реЛрдЧреА рдХрд┐ рдХреИрд╢ рдХреЗрд╡рд▓ рддрднреА рдЙрдкрдпреЛрдЧреА рд╣реЛрддреЗ рд╣реИрдВ рдЬрдм рдЙрдирдореЗрдВ рд╣рд┐рдЯ рд╣реЛрдВред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд▓реЗрдЦрдХ рдХреНрд╖реЗрддреНрд░ рдкрд░ рд╣рд┐рдЯ рдХреА рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ (рдорд╛рди рд▓реАрдЬрд┐рдП, 50%), рд▓реЗрдХрд┐рди рдлрд╝рд╛рдЗрд▓реЛрдВ рдкрд░ рдХреЛрдИ рд╣рд┐рдЯ рдирд╣реАрдВ рд╣реЛрдЧреАред рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреБрдЫ рд╕реБрдзрд╛рд░ рдкреНрд░рджрд╛рди рдХрд░реЗрдЧрд╛, рд▓реЗрдХрд┐рди рдпрд╣ рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рдореМрд▓рд┐рдХ рдкрд░рд┐рд╡рд░реНрддрди рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ (рдФрд░ рд╣рдореЗрдВ рдПрдХ рд╕рдлрд▓рддрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ)ред

рдЗрдВрдЯрд░рд╕реЗрд╢рди (рд▓рдВрдмреЗ) рдХреИрд╢ рдХреЗ рд▓рд┐рдП рдЬрдЯрд┐рд▓ рдЕрдорд╛рдиреНрдпрдХрд░рдг рддрд░реНрдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдЬрд┐рддрдиреА рджреЗрд░ рд╕реЗ рдЖрдк рдЗрдВрдЯрд░рд╕реЗрд╢рди рдХреИрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рджрд░реНрд╢рди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВрдЧреЗ, рдЙрддрдирд╛ рдмреЗрд╣рддрд░ рд╣реЛрдЧрд╛ред

рдкреЗрд╢реЗрд╡рд░реЛрдВ:

  1. рдХреЛрдб рдмрджрд▓реЗ рдмрд┐рдирд╛ рдХреИрд╢рд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░реЗрдВред
  2. рдЙрддреНрдкрд╛рджрдХрддрд╛ рдХрдИ рдЧреБрдирд╛ рдмрдврд╝ рдЧрдИ (рдХреБрдЫ рдорд╛рдорд▓реЛрдВ рдореЗрдВ)ред

рд╡рд┐рдкрдХреНрд╖:

  1. рдЧрд▓рдд рддрд░реАрдХреЗ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдкрд░ рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рдХрдореА рдХреА рд╕рдВрднрд╛рд╡рдирд╛ред
  2. рдмрдбрд╝реА рдореЗрдореЛрд░реА рдУрд╡рд░рд╣реЗрдб, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд▓рдВрдмреЗ рдХреИрд╢ рдХреЗ рд╕рд╛рдеред
  3. рдЬрдЯрд┐рд▓ рдЕрдорд╛рдиреНрдпрдХрд░рдг, рддреНрд░реБрдЯрд┐рдпрд╛рдБ рдЬрд┐рдирдореЗрдВ рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдХрдард┐рди-рд╕реЗ-рдкреБрдирд░реБрддреНрдкрд╛рджрди рд╕рдорд╕реНрдпрд╛рдПрдВ рдкреИрджрд╛ рд╣реЛрдВрдЧреАред

рдмрд╣реБрдд рдмрд╛рд░, рдХреИрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреЗрд╡рд▓ рдбрд┐рдЬрд╝рд╛рдЗрди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╢реАрдШреНрд░рддрд╛ рд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЖрдкрдХреЛ рд╣рдореЗрд╢рд╛ рдЙрдирдХреЗ рд╕рд╛рде рд╕рд╛рд╡рдзрд╛рдиреА рд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдкрд╣рд▓реЗ рдкрд░рд┐рдгрд╛рдореА рдкреНрд░рджрд░реНрд╢рди рд▓рд╛рдн рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рд╣реА рдХреЛрдИ рдирд┐рд░реНрдгрдп рд▓реЗрдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдХреИрд╢ рд▓рдЧрднрдЧ 25% рдХреА рдкреНрд░рджрд░реНрд╢рди рд╡реГрджреНрдзрд┐ рдкреНрд░рджрд╛рди рдХрд░реЗрдЧрд╛ред рд╡рд╣реАрдВ, рдХреИрд╢ рдХреЗ рдХрд╛рдлреА рдиреБрдХрд╕рд╛рди рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдпрд╣рд╛рдВ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ред

рдкрд░рд┐рдгрд╛рдо

рдЗрд╕рд▓рд┐рдП, рд╣рдордиреЗ рдПрдХ рдРрд╕реА рд╕реЗрд╡рд╛ рдХреЗ рд╕рд░рд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬреЛ рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИ, рдФрд░ рдЗрд╕реЗ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рдХреБрдЫ рд╕рд░рд▓ рддрд░реАрдХреЗ рднреАред

рдЗрди рд╕рднреА рддрд░реАрдХреЛрдВ рдХрд╛ рдореБрдЦреНрдп рд▓рд╛рдн рд╕рд░рд▓рддрд╛ рд╣реИ, рдЬрд┐рд╕рдХреЗ рдХрдИ рд╕реБрдЦрдж рдкрд░рд┐рдгрд╛рдо рдорд┐рд▓рддреЗ рд╣реИрдВред

рдЗрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЖрдо рд╕рдорд╕реНрдпрд╛ рдЦрд░рд╛рдм рдкреНрд░рджрд░реНрд╢рди рд╣реИ, рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдкреИрдХреЗрдЯ рдХреЗ рдЖрдХрд╛рд░ рдХреЗ рдХрд╛рд░рдгред рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдпреЗ рд╕рдорд╛рдзрд╛рди рдЖрдкрдХреЗ рдЕрдиреБрд░реВрдк рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдЕрдзрд┐рдХ рдХрдЯреНрдЯрд░рдкрдВрдереА рддрд░реАрдХреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ рдЙрдЪрд┐рдд рд╣реИред

рдРрд╕реА рджреЛ рдореБрдЦреНрдп рджрд┐рд╢рд╛рдПрдБ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рдЖрдк рд╕рдорд╛рдзрд╛рди рдЦреЛрдЬ рд╕рдХрддреЗ рд╣реИрдВ:

  • рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрд╛рд░реНрдп (рдПрдХ рдЖрджрд░реНрд╢ рдмрджрд▓рд╛рд╡ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕ рдЖрд▓реЗрдЦ рдореЗрдВ рдЪрд░реНрдЪрд╛ рдирд╣реАрдВ рдХреА рдЧрдИ рд╣реИ);
  • рд╕рдордХрд╛рд▓рд┐рдХ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рдмрдирд╛рдП рд░рдЦрддреЗ рд╣реБрдП рдмреИрдЪреЛрдВ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ред

рдмреИрдЪреЛрдВ рдХреЗ рдмрдврд╝рдиреЗ рд╕реЗ рдмрд╛рд╣рд░реА рдХреЙрд▓реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдмрд╣реБрдд рдХрдо рд╣реЛ рдЬрд╛рдПрдЧреА рдФрд░ рд╕рд╛рде рд╣реА рдХреЛрдб рд╕рдордХрд╛рд▓рд┐рдХ рд░рд╣реЗрдЧрд╛ред рд▓реЗрдЦ рдХрд╛ рдЕрдЧрд▓рд╛ рднрд╛рдЧ рдЗрд╕реА рд╡рд┐рд╖рдп рдкрд░ рд╕рдорд░реНрдкрд┐рдд рд╣реЛрдЧрд╛ред

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝реЗрдВ