Comments 32
Горшочек, не вари.

Серия №1. http://habrahabr.ru/post/273777/
Серия №2. http://habrahabr.ru/post/274449/

вопрос как раз в другом: как tribler помогает в изучении технологий и программированию вообще?
Если рассматривать просто как практику программирования, я ничего против не имею ) Но зачем делать то что никогда не кому не пригодится.
Само приложение — скорее всего не пригодится, но могут пригодиться знания и опыт.
args: Array<String>

эм… так массив или строка? строка массивов? массив строк?
Про Spring Boot и большие приложения просто так ляпнули, чтобы умней казаться?:) Может всё же добавите аргументацию, а то прочтёт Вас джуниор какой-нибудь, и будет потом ходить и рассказывать всем что бут не годится для больших приложений. Хотя, есть подозрение что и Вы это просто где-то подхватили
Вы этот комент ляпнули, чтобы показать, что умнее автора? Может вы почитаете внимательное и поймете, что во-первых, я не утверждаю, что бут для больших проектов не годится, что было бы неправдой, ибо занимаюсь как раз таким проектом, а лишь сказал, что он может осложнить жизнь, знание о чем, я «подхватил» из собственного опыта. И во-вторых, если бы вы не писали свой комментарий в непотребных для этого сообщества выражениях, я даже ответил бы вам по существу.
Спасибо за пример проектика на Котлине. Интересно было почитать код. Многое взял себе на заметку. Один только utils.kt чего стоит. Да и DateFormat в ThreadLocal я в первый раз вижу — класс!
1) Вы давно уже с Котлином работаете?
2) Какие еще проекты на Котлине можете посоветовать для углубленного изучения паттернов котлиновских?
3) Зачем написан собственный парсер CSV?
4) «У spring boot есть много особенностей, которые могут серьезно осложнить жизнь в больших проектах». Инетересно было бы узнать об этих особенностях.
Уточнение про 1-й вопрос. Интересует не только время, но и число на Котлине сделанных проектов.
Здорово, я рад, что статья оказалась полезной.
1) На работе я использую котлин не так давно и сравнительно немного, но в собственных нуждах постоянно и уже очень давно. Даже сам удивился насколько, когда увидел, что прошлая моя статья про котлин написана в 2012 году. Количество кода большое, но опенсорса не так много — у меня наверное можно только посмотреть прототип системы на базе libgdx на рективной тяге, там конечно кода сильно больше, но много и не очень качественного, который в планах в будущем улучшить.
2) Сейчас пишется достаточно много кода на котлине, но к сожалению какого-то конкретного проекта именно для изучения паттернов сейчас выделить не смогу.
3) В одном из рабочих проектов, нужен был парсер и до некоторого момента меня устраивала реализация от apache, но у него имелась проблема, связанная с тем, что у него все проблемы были IOException. А мне нужна была более тонкая обработка. В итоге получился парсер, который работает даже чуть быстрее, чем аналоги и с той системой ошибок, что была нужна мне. К тому же это был первый опыт написания кода такого рода на котлине.
4) Подробно расписывать долго, но если вкратце, то основная проблема бута в том, что он очень многие вещи делает неявно. От этого большой проект становится сложнее, чем мог бы быть. Из за этого приходится отказываться от многих «фишек» бута, которые для небольшого проекта позволяют очень серьёзно сократить количество беготни с конфигурированием стандартных наборов технологий. К тому же в больших проектах часто нужно какое-то специфическое поведение, которое идет в разрез с автоконфигурированием, от которого в итоге в большинстве мест пришлось отказаться, но время на попытку его использования было потрачено. Думаю, что начиная проект сразу со бутом, проблем будет меньше просто потому, что отказ от каких-то его особенностей будет происходить постепенно и по необходимости, но если ты пытаешься мигрировать большое приложение, то все эти «особенности» вылезают сразу. Отдельная песня — это спрингбутовый класслоадер (дело даже не столько в самом класслоадере, сколько в самом подходе хранения jar-ов внутри другого jar-а), который доставил нам большое количество приятных минут проведенных в отладке. И хотя класслоадеры — это всегда тонкая тема, нам в итоге пришлось отказаться от использования executable jar, из за особенностей взаимодействия с ним используемых библиотек. А мой пулреквест, который прикрывал небольшую дыру в JarURLConnection, в 1.3 так и не попал, что тоже грустно.
> 2) Сейчас пишется достаточно много кода на котлине, но к сожалению какого-то конкретного проекта именно для изучения паттернов сейчас выделить не смогу.

Кода пишется просто дико много, аж настолько, что Kotlin до сих пор отсутствует в районе сравнивалки openhub, а детальный просмотр приведенной ссылке на github показывает, что всего за прошлый месяц что-либо на Kotlin коммитили аж целых 14 разработчиков. Из этих 14 более-менее живых проектов именно на Kotlin там примерно половина, остальное — либо примеры и пробы пера, либо поддержка-Kotlin-как-еще-одного-таргета-в-системе-сборки, либо плагины IntelliJ.
Возможно, по ссылке «много кода» вы ожидаете гигабайты кода, но на мой взгляд то, что сейчас уже его активно использует сама JetBrains, делают специфические расширения такие проекты как rx, и создаются специфичные фреймворки вроде wasabi (при том, что релиза языка еще не было), уже позволяет сказать, что кода пишется достаточно много. Хотя в сравнении с java, конечно, этот объем ничтожен.
$.getJSON("/api/torrents?name=" + $('#search-text').val(), {}).done(function (response) {

Вроде как надо же значение параметра name эскейпить по urlEncode? А для этого есть:

$.getJSON("/api/torrents", { name: $('#search-text').val() }).done(function (response) {
Честно говоря, клиент я просто слепил на колене, потому что не собирался про него писать и уж тем более показывать его как пример разработки. Он был нужен, чтобы просто проверить работу сервиса. К слову, я сначала именно второй вариант использовал, но что-то не взлетело и я не желая тратить на это время, просто перенес в значение прямо в урл.
И еше вопрос, если можно: Почему не пользуетесь @ComponentScan, а объявляете все бины вручную?
Это вообще халиварная тема, но вот именно в этом приложении котлин наложил отпечаток своими отличиями от java. Сканирование компонентов вынуждает нас использовать инжекшн в поля, а в котлине это выглядит следующим образом:
@Autowired
private lateinit var someService:SomeService;


что делает немного больно мои глазам, к тому же вынуждает объявлять поля для инжекшена как var, что несколько «неаккуратненько». Во-вторых, конфигурирование всего в java-конфигах дает большую гибкость при инстанцировании бинов. Для сканированных же компонентов, мы можем только задать опциональность их добавления в конфигурацию по профилю или какому-то другому критерию. Ну и в-третьих, сами бины в таком подходе почти всегда получаются свободными от контейнера, что дает некоторый плюс к удобству тестирования.
Что немаловажно, такой подход создает некоторую буквальность в построении контекста — однозначно показывает намерения того, кто его писал и непосредственность восприятия. Что конечно несколько нивелируется бутом, но по крайней мере мой код подключается в общий контекст недвусмысленно. При действительно большом количестве бинов это может стать проблемой, опять же javaee нам этот паттерн навязывает, но в обычно решается некоторым структурированием, разнесением на разные конфигурации.
если необходимо кастомизировать аннотированный бин, его же можно «выкинуть» из сканера фильтром и прописать как надо. Ну, или наложить Bean*Processor на него, например BeanPostProcessor
Конечно, можно выкинуть фильтром или сделать профили, или кондишены, и это отлично работает, но сложнее и менее явно, чем написать java-код вроде такого:
@Bean
public SomeInterface someInterface(OurConfig config) {
    return config.getSomeProperty() == "someValue" ? new FirstImplementation() : new SecondImplementation();
}

пример, конечно утрирован, но смысл понятен. Особенно неприятно становится, когда нужно иметь несколько конфигураций с разными наборами бинов. Но хочу еще раз повториться, я ни в коем случае не отказываю подходу со сканированием компонентов в праве на жизнь. Более того, в проекте над которым я работаю сейчас, он активно используется. Так же я еще нашел достаточно удобным сканирование только избранных компонентов, например web-контроллеров и только в рамках определенного пакета.
зачем вам DI при таком, кхм, объявлении бинов?

я бы вместо параметра-флага someValue в конфиге указал бы имя класса для бина и создал бы из него бин через org.springframework.beans.BeanUtils#instantiate*
зачем вам DI при таком, кхм, объявлении бинов?

DI в таком подходе есть, просто он выше — на уровне конфигурации. А на уровне сервисов DI в таком подходе и не нужен.

я бы вместо параметра-флага someValue в конфиге указал бы имя класса для бина и создал бы из него бин через org.springframework.beans.BeanUtils#instantiate*

если конфиг совсем одевелопереный, то можно и так сделать, а если это какой-нибудь параметр devMode, который аффектит сразу серию бинов разным образом? А еще часто бывает в больших системах, что необходимые настройки связаны с бизнес-логикой и из за этого параметр влияет сразу на много бинов.
параметр devMode, это две конфигурации для озвученного вами Spring Boot — одна для devMode=true, другая для devMode=false, сделанная через профиль.

А если это иные флаги (не devMode), то делается два бина с @Conditional. Я к тому, что я бы не стал через «условие? один_класс: другой_класс» создавать бин
На @Conditional сделан весь бут, что и делает его использование таким неявным. А на счет devMode — тут вопрос неоднозначный, потому что так же как и параметры бизнес-логики он может влиять на такие нюансы конфигурации разных сущностей, что к ним не так просто подлезть просто объявив разные конфигурации, к тому же получится, что в одну конфигурацию будут напиханы разные никак друг с другом не связаные бины. И не совсем понимаю, чем ситуация с созданием бина по условию хуже, чем испольование @Conditional? Вот, возьмем реальную ситуацию, мне нужно было по параметру использовать кешированный вариант бина и обычный. Для этого в конфигурации я написал что-то вроде:
    @Bean
    public open fun headerRepository(sourceConfig: SourceConfig, fileSystem:FileSystem): HeaderRepository {
        val repository = FileHeaderRepository(fileSystem, sourceConfig.sourceDirectory)

        return if (sourceConfig.cacheHeaders) CachedHeaderRepositoryWrapper(repository) else repository
    }

наверняка, я смог бы решить это и другим способом, но зачем, если это можно сделать так просто?
Спасибо за ответы. Я буквально на днях открыл для себя Котлин и должен признаться, что приятно удивлен.
Кстати, я только что попробовал на одном из примеров отпробовать иньекцию и очень даже всё отлично отработало:

@RestController
class GreetingController @Autowired constructor (val greetingService: GreetingService) {
...

и лэйтиниты не понадобились.

Начиная с 4-го спринга рекомендуется именно иньекция через конструктор.
Да, как раз хотел про это написать, это вполне рабочий способ, если используешь скан, но он не очень хорошо подходит для способа о котором писал я — ведь в java-конфиге конструктор вызываешь руками.
Похоже мы как-то друг друга не понимэ. Ваше утверждение «Сканирование компонентов вынуждает нас использовать инжекшн в поля» неверно. Сканирование не вынуждает использовать иньекцию в поля. Конструкторная инъекция работает с тем же успехом (как я только что отпробовал).
Ну да, я об этом и хотел сказать своим комментарием выше — что это моё утверждение — неверное. Оно актуально только для определения бинов через джаваконфиг.
Only those users with full accounts are able to leave comments. Log in, please.