|
Как защитить код
|
|||
---|---|---|---|
#18+
Добрый день. Тут делал ревью кода и обрати внимание что Senjor Java Developer - взял и снял аннотация @Transaction с ряда методов, сначала подумал что рефакторинг, потом понял что просто ошибка, аннотации вернул. Но вопрос остался как защитить код от таких изменений? Поведение должно быть такое если аннотации сняли - код должен не собираться, падать , делать все чтобы он не попал в продакшен. как делать? Любые идеи, подойдут. Может есть какая идея, плагин ? Спасибо . ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 14:53 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
как простой пример всем понятный в связях One-to-many - Parent --- Set<Child> делать метод Set<Child> getChilds(){ return Collections.unmodifiableSet(childs); } чтобы исключить добавление через add коллекции , а для добавления создавать отдельный метод А на уровне декларативного кода что-то такое можно придумать ? может тест хитрый написать ?? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 14:53 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Atum1, Написать тесты на spring-test ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 14:56 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
переходить на Scala и ФП) ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 15:06 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Именно поэтому я не люблю спринг, и всякую эту контейнерную шалаболду. По сути аннотации - это нетипизированный DSL внутри Java-приложения, факстически ни чем не отличаясь от какого-нибудь javascript. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 15:08 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
в любом случае у нас внутри код, который должен выполниться в одной транзакции - это и надо тестировать. а уж как это достигается, с помощью Transactional или условных beginTransaction/commitTransaction - дело третье. При определенном везении Transactional и вовсе не будет работать, так что его наличие или даже отсутствие ни о чем не говорит забыл никэто нетипизированный DSL внутри Java-приложения, факстически ни чем не отличаясь от какого-нибудь javascriptэто про Transactional или про return "redirect:/showresult/${id}" из соседнего топика? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 15:21 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
chpasha забыл никэто нетипизированный DSL внутри Java-приложения, факстически ни чем не отличаясь от какого-нибудь javascriptэто про Transactional или про return "redirect:/showresult/${id}" из соседнего топика? И про то и про другое. Хотя первоначально имелись ввиду любые runtime-аннотации ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 15:32 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Atum1, тесты надо написать, что падают, если сняли анотацию @Transaction и выполнять эти тесты на ветке перед мёржем и если они упали, то запрещать мёрж ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 15:50 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никИменно поэтому я не люблю спринг, и всякую эту контейнерную шалаболду. По сути аннотации - это нетипизированный DSL внутри Java-приложения, факстически ни чем не отличаясь от какого-нибудь javascript.да. Но жто декларативное управление транзакциями. Мейнстрим счас. Куда деваться. Аффтар! — показать ему что упало когда он снял аннотацию. - с разрешения руководства писать тесты на транзакции. Он ведь мог и connection.beginTran не написать. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 15:57 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Atum1, ты входишь в опасный виток разработки тестов когда сложность тестирования может превышать полученный полезный эффект. Если у тебя есть тесты которые закрепляют бизнес логику - то они должны работать. Если на @Transaction нельзя написать модульные ... интеграционные или performance тесты - то возможно они .... не нужны. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 16:01 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Atum1, ща насоветуют дичи... все уже давно изобретено: Код: java 1. 2. 3.
... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 16:06 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
maytonможет превышать полученный полезный эффект. особенно когда окажется, что Senior поудалял там аннотации не по ошибке ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 16:08 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Андрей ПанфиловAtum1, ща насоветуют дичи... все уже давно изобретено: Код: java 1. 2. 3.
Которое также легко удаляется пьяным сеньором ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 16:13 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
PetroNotC Sharpзабыл никИменно поэтому я не люблю спринг, и всякую эту контейнерную шалаболду. По сути аннотации - это нетипизированный DSL внутри Java-приложения, факстически ни чем не отличаясь от какого-нибудь javascript. Но жто декларативное управление транзакциями. Мейнстрим счас. Куда деваться. Есть куда деваться. Как раз вот статья вышла хорошая, но это нужно иметь кое-какие знания о ФП чтобы понять. Тыц Это конечно не совет автору все переписывать с нуля - просто чтоб знал как бывает иначе ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 16:18 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Я-бы ограничился обычным каментом. Типа - "Перед тем как удалять - хорошо подумай. Если все таки решил удалять подойди к Atum и спроси разрешения". Все. Баста. Решение на 0.001 story point. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 16:21 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Андрей ПанфиловAtum1, ща насоветуют дичи... все уже давно изобретено: Код: java 1. 2. 3.
Такая проверка в рантайме, если код сломан уже ничего не даст. Процесс ревью кода может помочь. А лучше иметь интеграционные или приемочные тесты. Но тут насколько есть ресурсы на написание таких тестов. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 16:33 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никЕсть куда деваться. Как раз вот статья вышла хорошая, но это нужно иметь кое-какие знания о ФП чтобы понять. Тыц Чет там какой-то обман кмк. Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
При этом у автора претензия: авторLack of precision. Without looking at the code in its entirety, we can’t be sure where transactions exactly begin and commit. An @Transactional method might define the transaction boundary, or might take part in a broader transaction. It’s not possible to differentiate between these two scenarios. Вот как смотря в код sendEmail я могу понять в транзакции он будет выполняться или нет? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 16:58 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никАндрей ПанфиловAtum1, ща насоветуют дичи... все уже давно изобретено: Код: java 1. 2. 3.
Которое также легко удаляется пьяным сеньорома зачем удалять? У нас же нет контракта вида "где-то должны стоять аннотации", а есть контракт вида "этот метод требует выполнения в транзакции", соответственно assert прекрасно этот контракт обеспечивает и никакие дополнительные тесты писать не нужно, достаточно то что есть (если конечно есть) запускать с -ea ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:03 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Андрей Панфилова зачем удалять? сеньор-то - пьяный. а в коде на Scala он и трезвый побоится удалять, разве что все скопом ;) ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:09 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Atum1Добрый день. Тут делал ревью кода и обрати внимание что Senjor Java Developer - взял и снял аннотация @Transaction с ряда методов, сначала подумал что рефакторинг, потом понял что просто ошибка, аннотации вернул. Но вопрос остался как защитить код от таких изменений? Поведение должно быть такое если аннотации сняли - код должен не собираться, падать , делать все чтобы он не попал в продакшен. как делать? Любые идеи, подойдут. Может есть какая идея, плагин ? Спасибо . поведение кода закрепляют тесты. ответ - надо покрыть код тестами. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:15 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
PetroNotC Sharpзабыл никИменно поэтому я не люблю спринг, и всякую эту контейнерную шалаболду. По сути аннотации - это нетипизированный DSL внутри Java-приложения, факстически ни чем не отличаясь от какого-нибудь javascript.да. Но жто декларативное управление транзакциями. Мейнстрим счас. Куда деваться. Аффтар! — показать ему что упало когда он снял аннотацию. - с разрешения руководства писать тесты на транзакции. Он ведь мог и connection.beginTran не написать. в модном слике никаких аннотаций транзакций нет (а жаль!) ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:16 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
maytonЯ-бы ограничился обычным каментом. Типа - "Перед тем как удалять - хорошо подумай. Если все таки решил удалять подойди к Atum и спроси разрешения". Все. Баста. Решение на 0.001 story point. ща мода пошла у некоторых не писать вообще принципиально никаких комментов по коду. потому что мартин так в своей книжке чистый код сказал. ))) у узбеков есть поговорка - попроси принести тюбетейку - они тебе принесут тюбетейку вместе с головой. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:19 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Андрей Панфилов Код: java 1. 2.
Вот как смотря в код sendEmail я могу понять в транзакции он будет выполняться или нет? Никак, но в этом и весь цимус, что вам это и не надо. sendEmail - утилитная функция, которую можно вызвать как с транзакции так и вне, ее тип просто говорит что это IO - то есть некий сайд эффект. Когда же ты делаешь композицию функций, а-ля insertToDb.flatMap(_ => sendEmail) - тип это выражения уже Coneection[A] - то есть нечто что будет выполнено только если ему предоставить коннекшен. А чтобы выполнить ConnectionIO - ты обязан предоставить Transactor, иначе не скомпилируется. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:23 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTне писать вообще принципиально никаких комментов по коду. потому что мартин так в своей книжке чистый код сказал Мартин ничего не говорил про "не писать принципиально" авторTherefore, though comments are sometimes necessary, we will expend significant energy to minimize them. Узбекская поговорка это только подтверждает ;) ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:25 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Андрей Панфиловзабыл никпропущено... Которое также легко удаляется пьяным сеньорома зачем удалять? У нас же нет контракта вида "где-то должны стоять аннотации", а есть контракт вида "этот метод требует выполнения в транзакции", соответственно assert прекрасно этот контракт обеспечивает и никакие дополнительные тесты писать не нужно, достаточно то что есть (если конечно есть) запускать с -ea Убедил, но проблема того что это детектится лишь в рантайме - остается, хотя лучше чем было ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:25 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
chpashaАндрей Панфилова зачем удалять? сеньор-то - пьяный. а в коде на Scala он и трезвый побоится удалять, разве что все скопом ;) В ФП фишка в том что компилятор за тебя контролирует типы,и да, ты не сможешь удалить вызов транзактора и при этом не поломать сборку. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:26 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTmaytonЯ-бы ограничился обычным каментом. Типа - "Перед тем как удалять - хорошо подумай. Если все таки решил удалять подойди к Atum и спроси разрешения". Все. Баста. Решение на 0.001 story point. ща мода пошла у некоторых не писать вообще принципиально никаких комментов по коду. потому что мартин так в своей книжке чистый код сказал. ))) у узбеков есть поговорка - попроси принести тюбетейку - они тебе принесут тюбетейку вместе с головой. Плохая мода. Но Роб Мартин прав в части того что каменды надо также суппортить как и код. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:26 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTповедение кода закрепляют тесты. ответ - надо покрыть код тестами. Лучший тест - это компиляция, которую не забудешь проранать ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:28 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никНикак, но в этом и весь цимус, что вам это и не надо. Чет какая-то жесть... - проблема: очень печально что мы не видим где транзакция начинается (в endpoint транзакции начинаются по канону) - решение: берем скалу, теперь мы все равно не знаем где начинается транзакция, но проблемы уже нет - теперь у нас жопа в другом месте забыл никА чтобы выполнить ConnectionIO - ты обязан предоставить Transactor, иначе не скомпилируется.Как по мне так никакой практической пользы тут нет, транзакции же определяют как мы должны работать с данными, а тут нам язык какую-то конвенцию придумывает. А что делать если определенное метод мне нужно вне транзакции запустить, а если нужно параллельную транзакцию открыть? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:39 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Андрей ПанфиловЧет какая-то жесть... - проблема: очень печально что мы не видим где транзакция начинается (в endpoint транзакции начинаются по канону) - решение: берем скалу, теперь мы все равно не знаем где начинается транзакция, но проблемы уже нет - теперь у нас жопа в другом месте Да с чего вдруг? На самом деле идея простая, но не сразу дается, когда переходишь со спринга(сам так тупил) Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27.
В целом - sendEmail, insertUser - маленькие кусочки реюзаемой логики, никаких cross-cutting concerns. В Контроллере ты компонуешь эти кусочки как вздумается, и когда тебе нужен результат(а не дескрипшен твоего действия) - передаешь туда транзактор, обычно это как раз в эндпоинтах контроллера. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:56 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Андрей ПанфиловКак по мне так никакой практической пользы тут нет, транзакции же определяют как мы должны работать с данными, а тут нам язык какую-то конвенцию придумывает. А что делать если определенное метод мне нужно вне транзакции запустить, а если нужно параллельную транзакцию открыть? Выполнить кусок кода вне транзакции не получится в любом случае. Если нужна параллельная - ну вызывай в другом потоке, транзактор тредсейф. А вообще звучит как "а ваша пила умеет сталь пилить?", хотелки какие-то непонятные, хотя прикол в том, что даже их без проблем можно реализовать ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 17:58 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никАндрей ПанфиловЧет какая-то жесть... - проблема: очень печально что мы не видим где транзакция начинается (в endpoint транзакции начинаются по канону) - решение: берем скалу, теперь мы все равно не знаем где начинается транзакция, но проблемы уже нет - теперь у нас жопа в другом месте Да с чего вдруг? На самом деле идея простая, но не сразу дается, когда переходишь со спринга(сам так тупил) Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27.
В целом - sendEmail, insertUser - маленькие кусочки реюзаемой логики, никаких cross-cutting concerns. В Контроллере ты компонуешь эти кусочки как вздумается, и когда тебе нужен результат(а не дескрипшен твоего действия) - передаешь туда транзактор, обычно это как раз в эндпоинтах контроллера. В данном случае (исходим из обсуждаемого примера) получается так: чтобы дернуть MailService мне его нужно его заврапить в ConnectionIO (там в статье пишут IO.to[ConnectionIO]), поэтому везде по приведенному коду мне нужно расставить этот .to[ConnectionIO] "чтобы скомпилировалось", дальше проходит время, я выхожу из запоя и принимаю решение что почту мне нафиг посылать не нужно прямо вот сейчас, а можно и через некоторое время, поэтому я иду и меняю реализацию MailService чтобы оно писало в БД вместо отправки почты, а потом бегаю по всему коду и убираю .to[ConnectionIO] потому что теперь не компилируется - какое-то сомнительное удовольствие кмк. забыл никВыполнить кусок кода вне транзакции не получится в любом случае. Если нужна параллельная - ну вызывай в другом потоке, транзактор тредсейф. А вообще звучит как "а ваша пила умеет сталь пилить?", хотелки какие-то непонятные, хотя прикол в том, что даже их без проблем можно реализоватьЗдрасьте, требования как требования (ну вот спринг же умеет, а он ориентирован на JSR 907, который не последние люди в мире жавы разрабатывали), да и вызов в другом потоке и открытие новой транзакции из текущего - это два совершенно разных паттерна. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 18:26 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
chpashaandreykaTне писать вообще принципиально никаких комментов по коду. потому что мартин так в своей книжке чистый код сказал Мартин ничего не говорил про "не писать принципиально" авторTherefore, though comments are sometimes necessary, we will expend significant energy to minimize them. Узбекская поговорка это только подтверждает ;) конечно не говорил. вернее, он говорил типа не пишите избыточные комменты и не пишите бесплезные комменты. но норот читает как "не пишите комменты". ))) и начинаются в ревью тёрки типа у тебя код говно потому что ты вон там коммент оставил. а не только в шапке через жавадог ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 18:57 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никandreykaTповедение кода закрепляют тесты. ответ - надо покрыть код тестами. Лучший тест - это компиляция, которую не забудешь проранать а причем в данном случае компиль? код то работает. просто он не так работает как ожидает тс. поведение кода контролируется тестами. имхо. про ваши фп как обходиться без тестов и вообще всё само я пока не вник. не у кого поучиться ) ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 18:59 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никАндрей ПанфиловЧет какая-то жесть... - проблема: очень печально что мы не видим где транзакция начинается (в endpoint транзакции начинаются по канону) - решение: берем скалу, теперь мы все равно не знаем где начинается транзакция, но проблемы уже нет - теперь у нас жопа в другом месте Да с чего вдруг? На самом деле идея простая, но не сразу дается, когда переходишь со спринга(сам так тупил) Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27.
В целом - sendEmail, insertUser - маленькие кусочки реюзаемой логики, никаких cross-cutting concerns. В Контроллере ты компонуешь эти кусочки как вздумается, и когда тебе нужен результат(а не дескрипшен твоего действия) - передаешь туда транзактор, обычно это как раз в эндпоинтах контроллера. так вот он я красавец. у меня есть юзкейс.ран(транзактор), а есть скажем юзкейс.ватеварелз(неТранзактар) и я такой модный программист - просто удаляю эту строку и подменяю другой. оно дальше допустим, работает но уже без транзакции. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 19:02 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никЕсть куда деваться. Как раз вот статья вышла хорошая, но это нужно иметь кое-какие знания о ФП чтобы понять. Тыц Спасибо, отличная статья. Идея о том, что из репозиториев можно возвращать DBIOAction[T] вмето Future[T] (у меня слик) и потом транзакционно интерпретировать в Application Service, лично для меня закрывает один из пробелов между классическим DDD и функциональным стилем. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.10.2019, 23:07 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никPetroNotC Sharpпропущено... Но жто декларативное управление транзакциями. Мейнстрим счас. Куда деваться. Есть куда деваться. Как раз вот статья вышла хорошая, но это нужно иметь кое-какие знания о ФП чтобы понять. Тыц Это конечно не совет автору все переписывать с нуля - просто чтоб знал как бывает иначеох боюсь это никому не надо. Так как усложняет. Надо 2 транзакции, пиши 2 потока или 2 раза beginTran. Всё. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 02:54 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
fixxerфункциональным стилем.а рвзве ФП стало распространено? ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 02:56 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
PetroNotC Sharpfixxerфункциональным стилем.а рвзве ФП стало распространено? В скале так точно. Но даже в джаве последние три года встречаю, в основном, реактивные стримы и Completable Future. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 10:13 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
fixxerPetroNotC Sharpпропущено... а рвзве ФП стало распространено? В скале так точно. Но даже в джаве последние три года встречаю, в основном, реактивные стримы и Completable Future. Если посмотреть более шИроко. То ФП давно уже вокруг вас. ФП - это не только программирование. Это декларативное описание грамматик и смыслов. Формы Бекуса Науэра BNF/EBNF. Xml-schema/DTD. Просто спеки для всяких DSL. И попытки втащить в языки программирования иммутабельность структур данных - это всё части ФП. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 10:30 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Atum1Любые идеи, подойдут. Как возможный вариант - на методы дао/репозитории вешать Transactional.MANDATORY ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 11:03 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
SpringManКак возможный вариант - на методы дао/репозитории вешать Transactional.MANDATORY С каким-нибудь тестом, разумеется. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 11:05 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
нужно понимать где у тебя в проекте вообще наставлены эти @Transactional если это, как обычно - в контроллере для доступа к слою сервисов - то я бы сделал отдельный слой, который отвечает только транзакции совместно с мавен-модулями. напирмер project | |- web (содержит контроллеры, имеет доступ только к интерфейсу core-api и DTOшки) | |- core api (содержит только интерфейс (какой нибудь BusinessService) и, вероятно, DTO) | |- core impl (содежит реализацию BusinessServiceImpl, весь класс помечен @Transactional, внутри редиректит логику уже в "настоящие" сервисы, вероятно конвертирует DTO в сущности JPA) тут конечно "лишнего" кода будет много Если конечно расстановка @Transactional имеет хаотичный характер - то, имхо, только интеграционные тесты) которые обращаются в систему через контроллеры ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 11:52 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Чувствую в этом топике рождается гоммункул. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 12:26 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Андрей ПанфиловВ данном случае (исходим из обсуждаемого примера) получается так: чтобы дернуть MailService мне его нужно его заврапить в ConnectionIO (там в статье пишут IO.to[ConnectionIO]), поэтому везде по приведенному коду мне нужно расставить этот .to[ConnectionIO] "чтобы скомпилировалось", дальше проходит время, я выхожу из запоя и принимаю решение что почту мне нафиг посылать не нужно прямо вот сейчас, а можно и через некоторое время, поэтому я иду и меняю реализацию MailService чтобы оно писало в БД вместо отправки почты, а потом бегаю по всему коду и убираю .to[ConnectionIO] потому что теперь не компилируется - какое-то сомнительное удовольствие кмк. Во-первых, тебе надо заворачивать MailService в ConnectionIO только в случае если ты хочешь вызвать его в рамках транзакции, в общем случае посылка email - это side-effect и должен быть обернут просто в IO. Верхний уровень программы выглядит примерно так: Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
Во-вторых, ты в чем-то прав, а именно в том что надо прикладывать усилия, чтобы код скопилировался. Но это происходит именно потому что мы прописываем в типе дополнительную информацию(а именно что коду нужно DB connection) - и если он не компилируется(ты поменял реализацию MailService) - то оно и не должно компилироваться, потому что коннекшен тебе не нужен. И это не недостаток а достоинство. Тебя же не возмущает, если ты заменишь String date на LocalDate date - и тебе надо поменять все места, где используется это поле "чтобы скомпилировалось"? С наскока это не понять, и даже за месяц. Никого не уговариваю, хотите верьте, хотите нет - но composable type-safe transactions существуют ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 12:56 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTзабыл никпропущено... Лучший тест - это компиляция, которую не забудешь проранать а причем в данном случае компиль? код то работает. просто он не так работает как ожидает тс. поведение кода контролируется тестами. имхо. про ваши фп как обходиться без тестов и вообще всё само я пока не вник. не у кого поучиться ) А в том что ты в типах можешь прописать дополнительную логику. Некоторые умельцы чисто на типах пилят игры в пятнашки. И эти типы будут проверяться компилятором. И не по твоему хотению, а всегда. Их невозможно обойти и невозможно "забыть" запустить перед коммитом ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 12:58 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTтак вот он я красавец. у меня есть юзкейс.ран(транзактор), а есть скажем юзкейс.ватеварелз(неТранзактар) и я такой модный программист - просто удаляю эту строку и подменяю другой. оно дальше допустим, работает но уже без транзакции. Не поянл, какую строку удаляешь и почему оно перестанет работать? Любая операция с базой имеет тип ConnectionIO - единственный способ вытянуть оттуда реальное значение - это предоставить транзактор. Если ты не предоставишь - у тебя будет просто объект типа ConnectionIO и ты его не сможешь никак заюзать. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:00 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
fixxerзабыл никЕсть куда деваться. Как раз вот статья вышла хорошая, но это нужно иметь кое-какие знания о ФП чтобы понять. Тыц Спасибо, отличная статья. Идея о том, что из репозиториев можно возвращать DBIOAction[T] вмето Future[T] (у меня слик) и потом транзакционно интерпретировать в Application Service, лично для меня закрывает один из пробелов между классическим DDD и функциональным стилем. А DDD никак не противоречит ФП, а очень даже хорошо вписывается, я уже приводил линку - вот неплохая книга. Functional-Reactive-Domain-Modeling ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:02 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
PetroNotC Sharpзабыл никпропущено... Есть куда деваться. Как раз вот статья вышла хорошая, но это нужно иметь кое-какие знания о ФП чтобы понять. Тыц Это конечно не совет автору все переписывать с нуля - просто чтоб знал как бывает иначеох боюсь это никому не надо. Так как усложняет. Надо 2 транзакции, пиши 2 потока или 2 раза beginTran. Всё. Что усложняет? В хорошо написанной программе - Что в ООП, что в ФП по факту будет один и тот же результат(прочитать что-то, записать, залогировать, изменить стейт системы, обработать ошибки). И тебе и там и там надо обработать ошибки, обернуть все в транзакцию, обработать отсутсвие данных и т.д. В случае ООП обычно начинается с красивого кода по happy-path, а проверки на нулл, обработка эксепшенов, всякие корнер - кейсы - это уже по мере тестирования. В случае ФП - у тебя код просто не скопилируется пока ты все это не пропишешь. Простота ООП иллюзорна и только расслабляет программиста, провоцируя его вовремя дэдлайнов на куяк куяк и в продакшен. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:09 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
PetroNotC Sharpfixxerфункциональным стилем.а рвзве ФП стало распространено? Да, идеи ФП проникают в Java, C# и т.д, а не наоборот, как минимум. Тебе 10 лет назад показать код на стримах - ты бы ворочал носом и говорил какое говно, у меня есть циклы ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:11 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
maytonfixxerпропущено... В скале так точно. Но даже в джаве последние три года встречаю, в основном, реактивные стримы и Completable Future. Если посмотреть более шИроко. То ФП давно уже вокруг вас. ФП - это не только программирование. Это декларативное описание грамматик и смыслов. Формы Бекуса Науэра BNF/EBNF. Xml-schema/DTD. Просто спеки для всяких DSL. И попытки втащить в языки программирования иммутабельность структур данных - это всё части ФП. Именно, так никто ж и не спорит. А что нового было изобретено за последние n лет в ООП? ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:13 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никТебе 10 лет назад показать код на стримах - ты бы ворочал носом и говорил какое говно, у меня есть циклытак и сейчас говорят ;) ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:29 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
chpashaзабыл никТебе 10 лет назад показать код на стримах - ты бы ворочал носом и говорил какое говно, у меня есть циклытак и сейчас говорят ;) сейчас на циклах имхо и есть говно. :) ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:44 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTсейчас на циклах имхо и есть говно. :) этой фразой ты только что удвоил кол-во страниц в этом топике на 2 ;) ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:48 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никandreykaTтак вот он я красавец. у меня есть юзкейс.ран(транзактор), а есть скажем юзкейс.ватеварелз(неТранзактар) и я такой модный программист - просто удаляю эту строку и подменяю другой. оно дальше допустим, работает но уже без транзакции. Не поянл, какую строку удаляешь и почему оно перестанет работать? Любая операция с базой имеет тип ConnectionIO - единственный способ вытянуть оттуда реальное значение - это предоставить транзактор. Если ты не предоставишь - у тебя будет просто объект типа ConnectionIO и ты его не сможешь никак заюзать. я к тому что ты можешь что то переписать или переопределить чтоб это стало опциональным требованием. а так имхо это вообще шаг назад. ты и в джаве мог написать метод типа файндолл или что угодно еще где обязательно надо передать объект типа какой нить транзакшн менеджер. и типа опа видишь теперь точно не забудешь. ога. и вот чтоб от этого бойлерплейта уйти придумали декларативный (декоративный? :)) способ с аннотацией. а то что сверху имхо это какой-то прошлый век. добро пожаловать в средневековье. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 13:49 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
chpashaзабыл никТебе 10 лет назад показать код на стримах - ты бы ворочал носом и говорил какое говно, у меня есть циклытак и сейчас говорят ;) Так и html предлагают из резалтсета формировать ^) Я кстати java-стримы тоже не люблю, как и опшионал там особо не юзаю. Потому что они перетянули лишь видимую часть, а не глубинную идею. Красота стримов и опшионалов раскрываются, когда у тебя есть монады и for-comprehension, спроси у андрейки ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 14:23 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTя к тому что ты можешь что то переписать или переопределить чтоб это стало опциональным требованием. Ну можешь да, software меняется, это естественно, так в чем собственно вопрос? andreykaTа так имхо это вообще шаг назад. ты и в джаве мог написать метод типа файндолл или что угодно еще где обязательно надо передать объект типа какой нить транзакшн менеджер. и типа опа видишь теперь точно не забудешь. ога. Так и надо делать. А потом появляется куча джунов, которые ни черта не понимают как это работает и ответы на стекфоверфлоу становятся похожи на - ну попробуй добавить аннотацию @Whatever. супер. Правда тут четко надо различать bl-compexity и infrastrcture-complexity. Управление транзакциями - это часть бизнес-логики, хочешь ты этого или нет. Делая ее неявной ты ступаешь на очень скользкую дорожку. andreykaTи вот чтоб от этого бойлерплейта уйти придумали декларативный (декоративный? :)) способ с аннотацией. а то что сверху имхо это какой-то прошлый век. добро пожаловать в средневековье. Все ошибаются, раньше я тоже думал что это круто. Любая runtime-аннотация это нетипизированная хрень, которую ни продеюажишь ни пофиксишь, зачем тебе java тогда вообще? Не для сильной типизации ли? А от бойлерплейта уйти можно многими способами, ты сам прекрасно знаешь насколько мощные implicits в scala. Вот тебе кусок логики, полностью обернутый в IO, но ты об этом врядли догадаешься просто посмотрев на код. (Тем не менее код абсолютно без сайд-эффектов) Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 14:51 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никchpashaпропущено... так и сейчас говорят ;) Так и html предлагают из резалтсета формировать ^) Я кстати java-стримы тоже не люблю, как и опшионал там особо не юзаю. Потому что они перетянули лишь видимую часть, а не глубинную идею. Красота стримов и опшионалов раскрываются, когда у тебя есть монады и for-comprehension, спроси у андрейки Стримы это вообще - последнее дело. Вот когда в айти входит очередной джун-вайтишник - то на собесе оказывается что он стримы знает а на циклах блджад ничего написать не может. Более того не понял идею зачем они вообще нужны. И кто педалит вообще идею о том что библитечная фича лучше языковой? Убил-бы. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 14:57 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
maytonСтримы это вообще - последнее дело. Вот когда в айти входит очередной джун-вайтишник - то на собесе оказывается что он стримы знает а на циклах блджад ничего написать не может. Более того не понял идею зачем они вообще нужны. Ну и зачем они нужны? Хотя слабо представляю как можно "знать" стримы и не знать циклы. Циклы - такой же анахронизм как и удаление памяти в C++ приложениях. И да, большинство джава джунов сильно удивятся вопросу про освобождение памяти. Что такое цикл? Это последовательность 1) берем размер коллекции // это будет повторяться во всех циклах в любом приложении 2) создаем счетчик от 0 до размера // это будет повторяться во всех циклах в любом приложении 3) берем элемент по текущему инджексу // это будет повторяться во всех циклах в любом приложении 4) исполняем кастомную логику 5) инкрементируем текущий индекс и проверяем закончили ли // это будет повторяться во всех циклах в любом приложении 6) если не закончили идем на пункт 1// это будет повторяться во всех циклах в любом приложении А что мы делаем если // это будет повторяться во всех циклах в любом приложении ?? Правильно - наворачиваем абстракцию, и передаем в нее параметром кастомную логику - someAbstraction(doWithElement) ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 15:19 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
mayton И кто педалит вообще идею о том что библитечная фича лучше языковой? Убил-бы. Зависит от. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 15:20 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никНу и зачем они нужны? Хотя слабо представляю как можно "знать" стримы и не знать циклы. Циклы - такой же анахронизм как и удаление памяти в C++ приложениях. И да, большинство джава джунов сильно удивятся вопросу про освобождение памяти. Основная идея описана здесь https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html Обратите также внимание на свойства non-interfering и stateless. От себя скажу что стримы в Java может быть и являются чем-то новым для Java-кодеров. Но для ФП это старый боян которому уже более полу-века. Отголоски ленивой обработки списков а особо важно что иммутабельных - это основа программирования вообще любой ФП парадигмы На ней строятся и циклы и логика и структуры данных. В Java streams введены в угоду какой-то части пользователей которые видели Scala и задались вопросом - а почему собсно у нас нет такой языковой возможности? Языковую им не дали. Но дали библиотеку. И дали синтаксис анонимных функций для удобства. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 15:27 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
maytonзабыл никНу и зачем они нужны? Хотя слабо представляю как можно "знать" стримы и не знать циклы. Циклы - такой же анахронизм как и удаление памяти в C++ приложениях. И да, большинство джава джунов сильно удивятся вопросу про освобождение памяти. Основная идея описана здесь https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html Обратите также внимание на свойства non-interfering и stateless. От себя скажу что стримы в Java может быть и являются чем-то новым для Java-кодеров. Но для ФП это старый боян которому уже более полу-века. Отголоски ленивой обработки списков а особо важно что иммутабельных - это основа программирования вообще любой ФП парадигмы На ней строятся и циклы и логика и структуры данных. В Java streams введены в угоду какой-то части пользователей которые видели Scala и задались вопросом - а почему собсно у нас нет такой языковой возможности? Языковую им не дали. Но дали библиотеку. И дали синтаксис анонимных функций для удобства. АА, ты про это? Ну да, я ж и говорю что в java стримы - это ни то ни се.. так, верхи идеи. В scala они и stateless и inferrable, это подразумевается само собой.. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 15:31 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Перепутал inferrable и non-interfering ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 15:37 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никchpashaпропущено... так и сейчас говорят ;) Так и html предлагают из резалтсета формировать ^) Я кстати java-стримы тоже не люблю, как и опшионал там особо не юзаю. Потому что они перетянули лишь видимую часть, а не глубинную идею. Красота стримов и опшионалов раскрываются, когда у тебя есть монады и for-comprehension, спроси у андрейки еще надо отметить что в скале фор это не тот фор что в жаве. вернее, можно использовать как ТОТ но используют для другого. т.е. в скале фор используется прям повсеместно )) с оговоркой не для итераций и каких то сайдеффектных действий а с целью уплощения вложенностей при работе с монадами. да. прям ненарадуюсь. но я вот не уверен что это прям ФП, мне почему то кажется что фп это всего лишь некоторый ряд ограничений. а повсеместное втыкание монад и прочего - это стиль и подход. ФП - парадайм. мы не можем переопределять мы не можем писать сайдэффекты мы всегда возвращаем значение операции. вроде всё. а как ты это сделаешь - ну дело твое. просто классическая джава не очень к этому склоняет. а так скала мне прям очень нравится но я чем больше ею пользуюсь тем больше понимаю что в ней СТОЛЬКО всего что изучать не переизучать. типа вот была джава. сидели программисты и думали вон она скучная хотим такую же но 100500 свистелок-перделок, чтоб не разобраться - и в комплекте. а.. окей - на те скалу ))) развлекайся бро. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 16:34 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTсидели программисты и думали вон она скучная хотим такую же но 100500 свистелок-перделок, чтоб не разобраться - и в комплекте. а.. окей - на те скалу ))) развлекайся бро напоминает анекдот про студента перед сдачей диплома и фею ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 16:37 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
забыл никandreykaTя к тому что ты можешь что то переписать или переопределить чтоб это стало опциональным требованием. Ну можешь да, software меняется, это естественно, так в чем собственно вопрос? andreykaTа так имхо это вообще шаг назад. ты и в джаве мог написать метод типа файндолл или что угодно еще где обязательно надо передать объект типа какой нить транзакшн менеджер. и типа опа видишь теперь точно не забудешь. ога. Так и надо делать. А потом появляется куча джунов, которые ни черта не понимают как это работает и ответы на стекфоверфлоу становятся похожи на - ну попробуй добавить аннотацию @Whatever. супер. Правда тут четко надо различать bl-compexity и infrastrcture-complexity. Управление транзакциями - это часть бизнес-логики, хочешь ты этого или нет. Делая ее неявной ты ступаешь на очень скользкую дорожку. andreykaTи вот чтоб от этого бойлерплейта уйти придумали декларативный (декоративный? :)) способ с аннотацией. а то что сверху имхо это какой-то прошлый век. добро пожаловать в средневековье. Все ошибаются, раньше я тоже думал что это круто. Любая runtime-аннотация это нетипизированная хрень, которую ни продеюажишь ни пофиксишь, зачем тебе java тогда вообще? Не для сильной типизации ли? А от бойлерплейта уйти можно многими способами, ты сам прекрасно знаешь насколько мощные implicits в scala. Вот тебе кусок логики, полностью обернутый в IO, но ты об этом врядли догадаешься просто посмотрев на код. (Тем не менее код абсолютно без сайд-эффектов) Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
у имплиситов другая беда (опять же на мой взгляд я не профи-скала и думаю что юзаю ее на 10% от возможностей), у них беда в том что оно где то как то может навеситься-переопределиться а ты и знать не будешь что за чухня происходит и почему. хорошо если ИДЕ подсветит. а если нет ну будешь клики нарезать. особенно если код незнакомый. насчет декораторов (мне кажется, это более верное название, практикуемое в ноде и несте) помню был движ несколько лет назад в сторону аспектно-ориентированного программирования. типа вот СОЛИД вот буква О вот АОП - это ж прям вот то что надо давайте расширять функционал без изменения базового кода. давайте вешать на него аспекты и аспекты на аспекты а потом еще аспекты. и опа. чо за фигня чо за макароны я вашу душу почему это тут происходит. )) вроде потом отъехали. и смотрю в новых фреймворках успешно идею похерили. а в старых рекомендуют юзать только для мониторинга и логирования. угу. так и с имплиситами. пока это забавно. а дальше - time will say ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 16:39 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
chpashaandreykaTсидели программисты и думали вон она скучная хотим такую же но 100500 свистелок-перделок, чтоб не разобраться - и в комплекте. а.. окей - на те скалу ))) развлекайся бро напоминает анекдот про студента перед сдачей диплома и фею программист жава: господи, эх поеб-ться бы! господь: на те скалу, еб-сь, сын мой. ты про это? ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 16:41 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaT у имплиситов другая беда (опять же на мой взгляд я не профи-скала и думаю что юзаю ее на 10% от возможностей), у них беда в том что оно где то как то может навеситься-переопределиться а ты и знать не будешь что за чухня происходит и почему. хорошо если ИДЕ подсветит. а если нет ну будешь клики нарезать. особенно если код незнакомый. так и с имплиситами. пока это забавно. а дальше - time will say В Scala3 попытаются решить эту проблему. На самом деле все дело в том что у имплиситов 4 варианта использования - и только один из них ведет к проблемам что ты описываешь. Они введут другое слово для этого, так будет понятнее. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 16:56 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
да? а как тебе переименование в импортах? :) ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 17:04 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTда? а как тебе переименование в импортах? :) Помню был проект где был class Document аж в трех разных пакетах. Типа xml.Document, и еще два штуки подобных. Ох и треш и содомия была когда все три надо было использовать в одном сорце. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 17:07 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
имплисит классы тоже тот еще кладезь. конечно не такой как переопределение или проброс значений, но там хоть ИДЕ справляется. фальшивые методы палочкой подрисовывает. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 17:11 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTпрограммист жава: господи, эх поеб-ться бы! господь: на те скалу, еб-сь, сын мой. ты про это? ага, в ночь перед релизом ;) ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 17:19 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
andreykaTда? а как тебе переименование в импортах? :) Юзал один раз, но реально надо было - ситуация 1-1 как mayton описывает. Никто ж не заставляет тебя перемиеновывать, а раз в году сгодится ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 17:21 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
Я не мог переименовать. Сторонние библиотеки. Со сложной лицензией. ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 17:33 |
|
Как защитить код
|
|||
---|---|---|---|
#18+
maytonЯ не мог переименовать. Сторонние библиотеки. Со сложной лицензией. в скале можно сделать так Код: java 1. 2. 3. 4. 5. 6.
Мы про это ... |
|||
:
Нравится:
Не нравится:
|
|||
02.10.2019, 18:09 |
|
|
start [/forum/topic.php?all=1&fid=59&tid=2121090]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
158ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
99ms |
get tp. blocked users: |
2ms |
others: | 14ms |
total: | 316ms |
0 / 0 |