Oc-windows.ru

IT Новости из мира ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Repository pattern java

Implementing the Repository pattern with JPA and Hibernate


The repository pattern is extremely popular. In its modern interpretation, it abstracts the data store and enables your business logic to define read and write operations on a logical level. It does that by providing a set of methods to read, persist, update and remove an entity from the underlying data store.

Old vs. modern interpretation

If you read Patterns of Enterprise Application Architecture by Martin Fowler et al., you will recognize the difference to the initial goal of the repository pattern. Its main goal was the abstraction of the database access code. JPA already provides this abstraction. So, there is no need for another layer that provides the same functionality.

That’s why the new interpretation of the pattern now provides a higher level of abstraction and hides all specifics of the data store. That enables you to replace a data store with a completely different one, e.g., a relational database with a NoSQL database. But what’s even more important, all database access methods for an entity are defined in the same repository and not in different parts of the business logic. That makes the implementation of your business logic and reusing queries or other database operations much easier.

Get this post as a free cheat sheet!

Explaining the repository pattern

The repository pattern is pretty simple. An interface defines the repository with all logical read and write operations for a specific entity. You can see an example of such a repository interface in the diagram.

The interface gets implemented by one or more classes that provide data store specific implementations of each interface method.

In my experience, it only rarely happens that you need to support more than one data store. So, you could argue that this pattern creates an overengineered persistence layer. But the interface abstraction also enables frameworks to generate huge parts of the required code.

Don’t want to read? You can watch it here!

Implementing the repository pattern

In most enterprise projects, you only need to define the repository interfaces. Spring Data JPA and Apache DeltaSpike Data can generate standard repository implementations for you. You just need to provide your own implementation, if your implementation gets especially complex. I will show you more of that in the following articles of this series.

But for now, let’s implement the repository pattern without any frameworks. That makes the pattern easier to understand and highlights the benefits of frameworks that generate repetitive parts of the implementation.

Defining the repository interface

Let’s implement the same BookRepository interface as I showed you in the diagram. It defines 4 methods that you can use to:

  • save a new or changed entity (Please keep in mind that Hibernate detects and persists all changes of managed entities automatically. So, you don’t need to call the save method after you changed any entity attributes),
  • delete an entity,
  • find an entity by its primary key and
  • find an entity by its title.

Implementing the repository with JPA and Hibernate

In the next step, you can implement the BookRepository interface. In this example, I only create a simple JPA-based implementation, that doesn’t rely on any other frameworks.

If you ever called a JPQL query or persisted an entity in your business layer, the code of my repository implementation should look familiar. There is no big difference between implementing these operations in your business code or as part of a repository implementation.

In this example, the only noticeable difference is the implementation of the saveBook(Book b) method. You can call this method to persist a new entity or to merge an existing one. So, you need to detect if the method got called with a new or an existing entity. In this example, I let Hibernate generate the primary key values. So, the id attribute of all new entities should be null. If it isn’t null, it should be an existing entity which then gets merged into the persistence context.

Get this post as a free cheat sheet!

Conclusion

The repository pattern is one of the most popular Java persistence patterns. It provides 2 main benefits:

  1. The pattern abstracts the data store and enables you to replace your data store without changing your business code.
  2. The repository improves the reusability of your persistence code, especially your queries, by encouraging you to implement all persistence operations in one place. That makes them easy to find and to reuse.

The implementation of the repository pattern is relatively simple. You need an interface that defines the persistence operations on a logical level. This interface gets implemented by one or more data store specific classes.

Как не надо использовать паттерн «Repository»

Обобщенный паттерн Репозиторий

Чтобы избежать недоразумений, давайте для начала проясним, что здесь имеется ввиду под понятием обобщенного репозитория. Видели ли вы когда-нибудь интерфейс вроде этого:

Или может вы видели его брата-близнеца, который имеет иной вариант метода Get:

Вдохновение для написания первого примера пришло из официальной документации Microsoft для ASP.NET MVC 4. Что же касательно второго примера, в Интернете вы можете найти бесконечное число блогов, описывающих именно этот вариант написания репозитория — иногда лишь с небольшими отличиями в виде возвращения IEnumerable вместо IQueryable . И в последнем случае часто еще и с дополнительным методом для генерации запросов. Что-то вроде этого:

Так что плохого в них, вы можете спросить? Почти ничего, если не считать плохое именование методов из примера Microsoft (здесь лучше было бы использовать Find и FindAll вместо Get и GetAll).

Но «почти ничего» — это далеко не то же самое, что «ничего». Первую проблему, которую я здесь вижу, так это нарушение Принципа Сегрегации Интерфейсов (Interface Segregation Principle). Они выражают полный набор CRUD-операций даже для тех сущностей, для которых операции удаления не имеют никакого смысла (к примеру, когда вы деактивируете пользователей вместо удаления их записей из базы данных). Но эта проблема может быть решена при помощи просто разбиения на три интерфейса — для чтения, обновления и удаления записей.

Реальная проблема, которую мы здесь имеем, заключается в некорректном использовании. Оригинальная идея заключается в том, что интерфейсы должны быть использованы в качестве базовых для ваших пользовательских интерфейсов. Что-то вроде этого:

Ваши обработчики событий и сервисы (клиенты пользовательских репозиториев) должны сами определять нужные методы и помещать их в пользовательские интерфейсы.

Это в теории. К сожалению, за свою карьеру мне довольно часто приходилось видеть несколько иную картину:

Читать еще:  Как удалить файл чтобы нельзя было восстановить

Кто-то создал рабочую реализацию IGenericRepository. Что хуже в этой реализации, так это то, что эта имплементация почти всегда регистрируется в IoC-контейнере и может быть внедрена в ваши обработчики команд и сервисы точно так же, как и любая другая зависимость.

Код выглядит достаточно красиво и чисто. На самом деле — нет. Почему именно так — скажу немного позже. Теперь же я бы хотел поговорить об одном из решений неправильной интерпретации GenericRepository многих разработчиков. Само решение выглядит примерно так (диалог на code-review):

Джим Сеньор: вы когда-либо слышали, что NHibernate ISession или DbSet из Entity Framework на самом деле репозитории? А то, что вы только что создали — всего лишь небольшая обертка над ISession или DbSet? Де-факто, мы можем отказаться от этого обобщенного репозитория и просто использовать DbSet — результат будет аналогичным. Единственное, в чем IGenericRepository действительно полезен — так это в том, что он скрывает большую часть ненужных для нас методов, которыми обладает DbSet.

Джонни Джуниор: да, в этом действительно есть смысл. Я полагаю, использование обобщенного репозитория в нашем случае было лишним (счастливо возвращаемся к написанию программы…)

Как по мне, что GenericRepository , что DbSet – в большинстве ситуаций их использование лишнее (ну разве что вы пишите наиболее заCRUDженное приложение в своей жизни). Почему? Вот почему:

  • Единственный способ убедиться, что все LINQ-запросы будут верно преобразованы в SQL — это протестировать их на том же типе базы данных, что находятся в продакшине. Кроме того, в таком случае задача написания интеграционных тестов становится достаточно затруднительной. К примеру, взглянем на код:

Чтобы выполнить эти запросы, должны быть соблюдены два условия. За счет этого интеграционный тест становится менее читабельным. Теперь же давайте представим, что этот метод помещен в метод репозитория. Теперь в тесте нам нужно просто вызвать метод репозитория и проверить результат — просто, не так ли?

  • Я уверен, вы согласитесь, что LINQ-предикаты внутри сервисов нельзя использовать повторно и они имеют плохую тенденцию повторяться на протяжении всего кода. Даже если программист желает извлечь запрос в свой собственный метод, обычно это будет приватный метод конкретного сервиса. Инкапсуляция запросов внутри методов репозитория приведет к большей читабельности кода и в значительной мере упростить его использование.
  • LINQ-предикаты не именуются. Как правило, единственный способ узнать, что же, собственно говоря, делает наш запрос (без углубления в его логику), так это имя переменной-результата. К сожалению, искусство информативного именования переменных постигается с опытом, а поскольку в нашей индустрии полно начинающих программистов, мы имеем дело с переменными вроде result, ordersToProcess или просто — orders. Создавая обертку над запросами в виде метода репозитория, это автоматически обязывает разработчика дать этому самому методу конкретное имя. Даже если это имя не из лучших, в последствии провести небольшой рефакторинг не составит труда!
  • Порой, по причине скорости, мы вынуждены доставать данные из базы посредством чистого SQL. Подумайте, вы действительно хотите в своей бизнес-логике работать с такими низкоуровневыми сущностями, как DbConnection или SqlException? Подобный код лучше прятать за методами репозиториями.

Никаких обобщений — только конкретные репозитории

Перед тем как начать разработку репозитория, необходимо определить его интерфейс. Интерфейс должен содержать только те методы, которые нужны конечным клиентам. Другими словами, если никому не нужно удалять сущности данного типа, нет никакого смысла в написании функционала для их удаления.

Если вы боитесь закончить среди разных имен для базовых CRUD-операций — таких как Delete в одном репозитории и Remove в другом — вы можете создать полезные интерфейсы типа ICanDeleteEntity , ICanUpdateEntity и так далее. В таком случае конкретный репозиторий будет реализовывать только действительно нужные из них.

Ни один из методов репозитория не должен возвращать IQueryable . Также убедитесь, что репозиторий не возвращает IQueryable , скрытые за IEnumerable . Всегда вызывайте ToList() или ToArray() дабы «материализовать» значения, придав им более конкретный тип данных.

Как только заходит речь о реализации репозитория, вы можете наследовать абстрактный класс GenericRepository . Если угодно — можно также использовать напрямую ISession и DbSet. Не важно, какой подход вы выбираете. Помните: любые «лишние» в данном контексте методы — по типу Delete из базового класса — будут скрыты за интерфейсом репозитория.

Также не забывайте, что ваш репозиторий не несет ответственности за транзакции базы данных. Лучше всего эта концепция реализуется при помощи паттерна Unit Of Work. Этот паттерн уже реализован в рамках ISession и DatabaseContext. Все, что нам нужно — это хороший интерфейс над ними:

Для большинства веб-приложений чтобы начать транзакцию через IUnitOfWork в виде начала запроса и Commit / Rollback в конце запроса — этого функционала вполне достаточно. Так же подобное может быть достигнуто при помощи фильтров действий или декораторов обработчиков / сервисов.

Пример репозитория, созданного при соблюдении всех приведенных рекомендаций:

Сейчас все стало ясно, но давайте еще раз проясним. Каждый метод наших репозиториев должен быть учтен по крайней мере одним интеграционным тестом, который должен использовать тот же тип базы данных, что и продакшн. Всегда используйте интеграционные тесты для проверки своих репозиториев.

Немного о недостатках

Не существует роз без шипов, и представленный выше подход — не исключение. Некоторые из них можно решить, используя отличимую от трехуровневой архитектуру. Наиболее часто с конкретными репозиториями возникали следующие проблемы:

  • За длительное время репозитории могут набрать большое количество Find-методов. Достаточно часто эти методы похожи друг на друга. Есть два способа это предотвратить. Один из них — это группировка нескольких Find-методов в один общий. Этот метод должен принимать object, что представляет собой критерий запроса. Пример:

Чтобы создать запрос с критерием запроса, мы строим набор критериев шаг за шагом:

Зачастую слишком большие репозитории обрастают целой плеядой различных сервисов. Вы можете избежать этого при помощи чего-то, что я называю CQRS-light. Отличием от полной версии является использование тех же таблиц как для чтения, так и для записи. Используя эту технологию, мы можем использовать ту же самую ORM как для чтения, так и для записи. Обращаться же к CQRS только в тех случаях, когда приложение в этом действительно нуждается (например, при обработке 80+ колонок, с использованием 20+ join). Диаграмма ниже представляет типичную архитектуру CQRS-приложения:

Ключевые принципы CQRS-light следующие:

  • Деление всех действий пользователя на две категории. Первая категория — действия, изменяющие систему. К примеру, оформление заказа в интернет-магазине. Вторая категория — действия, систему не трогающие. К примеру, просмотр списка товаров. Первая категория пишет — это команды, другая — читает, это запросы.
  • Обработчики запросов для доступа к данным могут использовать только репозитории. Доступ к данным может осуществяться посредством любой технологии. Обычная конфигурация включает в себя ORM для чтения-записи, ORM для записи и микро-ORM для чтения (вроде Dapper) или же ORM для записи и чистый SQL для чтения.
  • Обработчики команд для доступа и изменения данных могут использовать только репозитории. Для получения данных из базы обработчики команд не должны использовать обработчики запросов. Если обработчик команд должен выполнить комплексный запрос и этот запрос должен получить ответ от обработчика запроса, вы должны продублировать логику этого обработчика запроса и поместить его как в обработчик запроса, так и в метод репозитория (операции чтения и записи должны быть разделены).
  • Обработчики запросов тестируются только в интеграционных тестах. Для обработчиков команд существуют юнит и — опционально — также интеграционные тесты.
Читать еще:  Java sql sqlexception

CQRS даже в своей легкой форме — сама по себе объемная тема и заслуживает отдельного блога.

Теперь же давайте вернемся к теме недостатков паттерна конкретного репозитория. Другой недостаток, о котором я бы хотел упомянуть, заключается в нежелательной миграции бизнес-логики в определение запросов. К примеру, даже такой простой запрос:

содержит часть бизнес-логики, описывающей необходимые параметры, дабы заказ стал активным. Как правило, ORM не позволяет нам инкапсулировать такие части логики в отдельные свойства, как IsActive.

Что нам здесь нужно, так это паттерн спецификации. Теперь наш запрос в форме паттерна спецификации будет выглядеть так:

Repository Design Pattern

While developing Android applications in most of them you need to persist data in some kind of storage. In most cases this storage will be SQLite. Probably you want to access data in readable and easy way. What do you do then? Yes… you look for nice looking ORM. You can start to create classes for tables and design all possible method you’re likely to use:

Does it look familiar? Is it wrong? Well, no, but can be better.

Instead of god >Single Responsibility Rule and use Repository Design Pattern instead. Following the definition ( http://martinfowler.com/eaaCatalog/repository.html):

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes

Let’s start with base definition of Repository:

As you can see I replaced Criteria with Specification. Basically it’s the same, but Specification seems to be more independent from where you’re going to store the data. While using it, I found it extremely useful to add two additional methods:

It’s really what you need. In almost all applications you need to store more than one item and remove a couple of them. RDP should make your live easier, shouldn’t it?

There is also Specification interface which is only regular marker interface. Once we’ve defined what the repository is, we can start to use Specifications:

Basic implementation of Repository for SQLite can be for instance:

This can be a way simpler by using lambdas or Kotlin ❤. For this example I’ve deliberately added only implementation of add and query methods because other methods will look very similar. It’s more than sure, you’ve noticed Mapper interface. Its responsibility is to map one object to another. In this case I found it really useful. While using RDP, mapper classes help to keep you focused on what’s important.

To be able to query a database or any other storage we will need an implementation of Specification. Here it goes (couple of them, actually):

Specifications are really simple and in most cases has only one method. You can add as many Specifications as you want, without modifying DAO classes. Moreover testing is simpler. We stick to interfaces, so it can be easily mocked and replaced. You can provide some fake data too, while mapping Repository itself. Can you imagine how those Specification classes are easy to read comparing to veryyyy long DAO?

Repository fits quite good to MVP, but can be easily used in other classes too. By using Dagger you need to define which implementation of Repository you want to use in one place.

Let’s complicate it a little bit

OK. Requirements has changed. You can no longer use SQLite. You’re cool and therefore you’ll be using Realm.

// me waiting for your yelling

What happens when you’ve implemented application by using DAOs? You have to refactor a tons of >Repository Design Pattern is your friend, though. All what you need to do is to implement Repository and Specifications to fit new requirements (let’s stick to Realm). That’s all. You will not be digging in other classes. Take a look at brand new implementation:

There is a new Specification, as well:

And an example implementation of just created RealmSpecification:

Now, you’re ready to use Realm instead of SQLite without modifying any unrelated class (do you remember how dependency has been defined in Presenter?).

Bonus

There is also one more extra use case. You can use RDP also to prov >CacheSpecification e.g.:

and use it along with others:

What’s important, not all of your specifications need to implement all interfaces. If only NewsBy >CacheSpecification by NewsByCategorySpecification.

Your code is cleaner now, your teammates love you, kittens not gonna die, and even if you left company the next guy will not kill you, even if he’s psychopath.

ТОП-20 популярных Java-репозиториев на Github

Мы заглянули на GitHub и отобрали двадцатку популярных Java-репозиториев: от книг по Java до инструментов разработчика – на любой вкус.

В этой подборке только самые звездные и востребованные проекты на языке программирования Java. Чтобы вам было удобнее, мы разбили их на несколько групп. Посмотрим, что сейчас популярно в Java-мире.

Концепции и сниппеты

Обучающие и справочные проекты всегда востребованы: джунам нужно постигать основы, миддлам – разбираться в сложных концепциях, сеньорам – освежать знания. Разумеется, эта подборка не могла обойтись без подобных Java-репозиториев.

iluwatar/java-design-patterns

Самый популярный Java-репозиторий на GitHub – коллекция паттернов проектирования всех видов и мастей.

Паттерны – это лучшие практики организации проектов, которые упрощают и ускоряют процесс разработки. Они представляют собой хорошо продуманные и протестированные решения самых распространенных задач программирования. Паттерны учитывают много мелочей, о которых вы легко можете забыть, и спасают от распространенных и глупых ошибок.

Каждый паттерн в репозитории, будь он моно или нет, содержит подробное описание и примеры реализации на Java.

Читать еще:  Программа восстановления данных после форматирования жесткого диска

kdn251/interviews

Здесь собраны популярные вопросы с технических интервью и, разумеется, ответы на них. Темы затронуты самые разные:

  • структуры данных;
  • популярные алгоритмы и их эффективность;
  • общие концепции программирования.

В репозитории много ссылок на полезные текстовые материалы и видеолекции.

winterbe/java8-tutorial

Подробное руководство по Java 8, шаг за шагом описывающее все возможности и особенности языка. Короткие демонстрационные примеры отлично показывают основные концепции. Минимум текста, максимум наглядности. Репозиторий может служить и учебником, и справочником.

TheAlgorithms/Java

Коллекция популярных и не очень алгоритмов, реализованных на Java. Тут можно найти решение для любой задачи программирования: сортировки, поиска, сжатия, конвертации и т. д.

Не все из этих алгоритмов удобны и оптимальны, иногда можно найти в стандартной библиотеке Java примеры получше. Однако для демонстрационных и образовательных целей этот репозиторий подходит замечательно.

Фреймворки и библиотеки

Иногда желание создать собственный велосипед невозможно побороть, для остальных случаев существуют готовые решения. Вот 9 самых популярных Java-репозиториев с фреймворками и библиотеками.

ReactiveX/RxJava

Второй по звездности на GitHub Java-репозиторий – библиотека RxJava, основанная на API ReactiveX. Она позволяет писать асинхронные событийно-управляемые программы для виртуальной Java машины, поддерживает последовательности событий и их комбинации. В основе работы лежит классический паттерн Наблюдатель, только вместо одного объекта используется целый поток данных.

C RxJava можно больше не беспокоиться о низкоуровневом распараллеливании, синхронизации, потокобезопасности и обработке ошибок.

spring-projects/spring-boot

Spring Boot – это замечательный инструмент, который облегчает создание Spring-приложений и в целом работу с платформой Spring. Его основная задача – отвлечь вас от формирования инфраструктуры приложения и дать возможность сконцентрироваться на бизнес-логике. А инфраструктуру он построит за вас.

Spring Boot не изменяет ваш код и не создает новый. Он лишь динамически применяет все необходимые для приложения настройки.

google/guava

Проверенная временем библиотека ядра от Google, включающая в себя массу полезных инструментов и утилит для всех задач программирования. Особенно хороша Guava в работе с упорядоченными коллекциями. Функции сравнения и сортировки в библиотеке проработаны замечательно.

spring-projects/spring-framework

Один из самых популярных Java-фреймворков. Spring предоставляет разработчику огромные возможности и большую свободу действий, поддерживает самые разные сценарии и архитектуры приложений. Подробное описание проекта, его возможности и Java примеры использования вы можете найти в официальной документации.

apache/incubator-dubbo

Высокопроизводительная распределенная RPC-платформа с открытым исходным кодом и прозрачным интерфейсом. Три составляющие Dubbo:

  • удаленное взаимодействие и синхронизация обмена сообщениями;
  • кластеризация и интеллектуальная балансировка нагрузки;
  • реестр каталогов для автоматической регистрации служб и публикации подписки на события.

alibaba/fastjson

Библиотека для быстрого преобразования любых произвольных Java-объектов в JSON-представление и обратно. Поддерживает даже объекты со сложной структурой (глубокими иерархиями наследования и использованием универсальных типов).

FastJson улучшает производительность сервера и клиента и позволяет использовать для объектов любые пользовательские представления.

libgdx/libgdx

Полноценный фреймворк для гейм-девелопмента, написанный в основном на Java (некоторые компоненты на C и C++). Работа основана на платформонезависимом OpenGL, поэтому libgdx поддерживает практически все существующие платформы и позволяет легко переносить проект между ними.

mybatis/mybatis-3

MyBatis SQL mapper упрощает использование реляционной базы данных с объектно-ориентированными приложениями. MyBatis связывает объекты с помощью хранимых процедур или SQL-выражений используя XML-дескриптор или аннотации.

Самое большое преимущество MyBatis data mapper перед другими инструментами объектно-реляционного сопоставления – это простота.

Java примеры кода использования фреймворка ищите в его официальной документации.

eclipse-vertx/vert.x

Набор инструментов для создания реактивных приложений для виртуальной Java машины. Vert.x имеет очень простую модель параллелизма, высокую производительность, модульную структуру и легко масштабируется между ядрами системы.

Фреймворк решает такие низкоуровневые задачи, как поддержка протоколов HTTP, TCP и доступ к файловой системе.

Android

Мобильная разработка – одно из самых перспективных направлений IT, и развивается она стремительными темпами. Поэтому на GitHub очень много Java-репозиториев с Android-проектами.

PhilJay/MPAndroidChart

Мощная, производительная и удобная в использовании Android-библиотека для визуализации данных. Позволяет создавать диаграммы и графики всех сортов на любой вкус:

  • гистограммы (вертикальные, горизонтальные, с накоплением, сгруппированные),
  • секторные,
  • линейные,
  • лепестковые,
  • кружковые,
  • диаграммы рассеяния,
  • японские свечи и др.

zxing/zxing

Android-библиотека с открытым исходным кодом для сканирования штрихкодов.

В настоящее время проект находится в режиме поддержки и не принимает новых дополнений и изменений.

ZXing («zebra crossing») умеет работать с самыми разными 1D и 2D кодами: Codabar, QR, EAN, Aztec, PDF 417 и др.

skylot/jadx

Декомпилятор Android-приложений в Java-код, способный обрабатывать DEX-, APK-, JAR- и CLASS-файлы. Инструмент имеет версию для командной строки, а также GUI-интерфейс. В репозитории подробно описан процесс установки утилиты и Java приемы работы с ней.

android10/Android-CleanArchitecture

Демонстрационный образец Android-приложения с грамотно выстроенной чистой архитектурой. Как оно создавалось, вы можете узнать из серии статей владельца репозитория:

google/ExoPlayer

Медиа-плеер для Android-приложений, способный воспроизводить видео- и аудиофайлы локально и через Интернет. Отличная альтернатива от Google для Android MediaPlayer API с дополнительными возможностями.

ExoPlayer легко настраивается и расширяется с помощью дополнений из Play Store.

realm/realm-java

База данных, созданная специально для работы непосредственно внутри телефонов, планшетов и других мобильных устройств на Android.

Простой и интуитивно понятный API позволяет очень быстро начать работу с базой. Благодаря своей простоте Realm не требует ORM-решений: данные предоставляются в виде объектов и запрашиваются кодом.

Это современный, надежный и высокопроизводительный продукт, он определенно заслуживает вашего внимания.

mikepenz/MaterialDrawer

Простая в использовании и гибкая дизайн-библиотека для выдвигающихся панелей в стиле Material Design в Android-приложениях.

MaterialDrawer интегрируется в ваш проект за 5 минут, имеет интуитивно понятный API и обеспечивает большое количество настроек и вариантов оформления. Умеет работать с векторными иконками и шрифтами, динамически изменять цвета, поддерживает RTL.

Инструменты разработки

SeleniumHQ/selenium

Selenium – проект, объединяющий множество инструментов для автоматизации браузеров. Он совместим со всеми основными веб-обозревателями.

Основное применение Selenium – тестирование веб-приложений. Кроме того он может использоваться для парсинга страниц.

jenkinsci/jenkins

Jenkins – самый популярный сервис автоматизации процесса разработки ПО. Более 1000 плагинов могут автоматизировать практически все, что вы способны придумать:

  • сборку проекта;
  • запуск тестов и формирование отчетов;
  • статический анализ кодовой базы;
  • развертывание проекта.

Jenkins берет на себя рутинные повторяющиеся задачи, а вы получаете много освободившегося времени для решения действительно важных задач.

orhanobut/logger

Простой, красивый и мощный логгер для Android-проектов. Такой инструмент всегда пригодится.

mockito/mockito

Этот имитационный фреймворк для модульного тестирования основан на библиотеке Shipkit и постоянно дорабатывается. Он позволяет создавать заглушки для реальных классов и интерфейсов и даже подключать к реальным классам «шпионов».

Великолепный API Mockito позволяет работать в сотрудничестве с другими утилитами тестирования, расширять их и оборачивать в пользовательскую логику.

Поисковый движок

elastic/elasticsearch

Elasticsearch – это распределенная поисковая система c огромными возможностями и третий по звездности среди Java-репозиториев на GitHub.

Поиск поддерживает многопоточность, несколько индексов, горизонтально масштабируется.

Продукт находится в свободном доступе (есть также платная подписка) и используется крупнейшими веб-сайтами.

Ссылка на основную публикацию
Adblock
detector