SlideShare a Scribd company logo
1 of 49
Download to read offline
Разработка API в Java-проекте:
как оказывать влияние на людей
и не приобрести врагов
Чашников Николай
программист
JetBrains
Nikolay.Chashnikov@jetbrains.com
Как возникает API
class B

class A
Как возникает API
class B

class A
Как возникает API
class B

class A
К чему приводят недостатки API
API неудачное, если
● его трудно понимать
● его неудобно использовать
● с ним легко допустить ошибку
● его проблематично менять
● оно недостаточно выразительно
Свойства хорошего API
● его легко понимать
● его удобно использовать
● оно защищает от ошибок
● его можно безболезненно менять
● оно достаточно мощное
В API — только необходимое
Добавить в API просто, убрать что-то из API
очень трудно.
Нельзя выделять что-то в API просто “чтобы
было”, “а вдруг понадобится”.
API не должно содержать реализацию
Все методы классов в API должны быть
● либо abstract
● либо возвращать значение по умолчанию
● либо делегироваться к другим методам
API
API не должно содержать реализацию
● отсутствие тел методов облегчает
читаемость
● отсутствие тел методов упрощает
наследование
● код, вынесенный в API, становится
частью контракта
Наследование от классов API
Для каждого интерфейса в API должно быть
чётко установлено, предполагается ли его
наследование пользователями API.
Разрешать наследование только при
необходимости.
Наследование от классов API
public abstract class Car {
private final String manufacturer;
private final String model;
public Car(String manufacturer, String model){
this.manufacturer = manufacturer;
this.model = model;
}
public abstract void playEngineRoar();
public String getManufacturer()
{ return manufacturer; }
public String getModel() { return model; }
}
Наследование от классов API
public class AudiQ7Diesel extends Car {
public AudiQ7Diesel() {
super("Audi", "Q7");
}
public void playEngineRoar() {
...
}
}
Наследование от классов API
public interface Car {
String getManufacturer();
String getModel();
CarEngine getEngine();
}
public interface CarEngine {
void playEngineRoar();
}
public interface CarFactory {
Car createCar(String model, String
manufacturer, CarEngine engine);
}
Запрещать всё, что не разрешено
● использовать наиболее закрытые
модификаторы доступа
● делать final всё, что не предполагается
переопределять
Ешьте своё API сами. Дважды
Параллельно с созданием API надо писать
минимум два примера его использования.
Мощь и простота использования
Easy things should be easy, and hard things
should be possible
Как проще всего прочитать в
String текст файла (в Java 6)?
byte[] bytes =
new byte[(int) file.length()];
DataInputStream input =
new DataInputStream(
new FileInputStream(file));
input.readFully(bytes);
input.close();
return new String(bytes, "UTF-8");
В Java 7 это стало проще
return new String(
Files.readAllBytes(file.toPath()),
StandardCharsets.UTF_8);
Упрощайте доступ к нужным методам
public interface Form {
/** use {@link Validators} */
void check();
}
public class Validators {
public static boolean isValidEmail(String s){…}
public static boolean isValidPhoneNumber
(String s) { … }
}
Упрощайте доступ к нужным методам
public class ContactsForm implements Form {
...
public void check() {
String phone = getPhoneNumberText();
if (!Validators.isValidPhoneNumber(phone)) {
...
}
}
...
}
Упрощайте доступ к нужным методам
public interface Form {
void check(Validators validators);
}
public interface Validators {
boolean isValidEmail(String s);
boolean isValidPhoneNumber(String s);
}
Упрощайте доступ к нужным методам
public class ContactsForm implements Form {
...
public void check(Validators validators) {
String phone = getPhoneNumberText();
if (!validators.isValidPhoneNumber(phone)) {
...
}
}
...
}
Защита от ошибок
● в случае ошибки падать как можно
раньше
○ в идеале — при компиляции

● не использовать String и boolean, если
есть более подходящие типы
● использовать generics вместо casts и
Object
● использовать аннотации @NotNull,
@Nullable
Слабая типизация
public interface AssortedData {
void putData(String key,
Object data);
Object getData(String key);
}
Сильная типизация
final class Key<T> {}
public interface AssortedData {
<T> void putData(Key<T> key,
T data);
<T> T getData(Key<T> key);
}
Как при использовании этого
класса можно ошибиться?
public class Shop {
private List<Order> orders
= new ArrayList<Order>();
private Order[] ordersArray;
public void addOrder(Order order)
{ orders.add(order); ordersArray = null; }
public Order[] getOrders() {
if (ordersArray == null)
ordersArray =
orders.toArray(new Order[orders.size()]);
return ordersArray;
}
}
Например, вот так
Order[] orders = shop.getOrders();
…
…
Arrays.sort(orders);
А вот как от этого защититься
public class Shop {
private List<Order> orders =
new ArrayList<Order>();
private List<Order> unmodifiableOrders =
Collections.unmodifiableList(orders);
public void addOrder(Order order) {
orders.add(order);
}
public List<Order> getOrders() {
return unmodifiableOrders;
}
}
Тот номер больше не пройдёт
List<Order> orders = shop.getOrders();
…
…
Collections.sort(orders);
//вылетит UnsupportedOperationException
Защита от ошибок
● избегать неявных ограничений
● использовать immutable объекты
Навязывать нужное поведение
public class DoNotOverrideEquals {
public final boolean equals(Object obj) {
return super.equals(obj);
}
public final int hashCode() {
return super.hashCode();
}
}
Навязывать нужное поведение
public abstract class MustOverrideEquals {
public abstract boolean equals(
Object obj);
public abstract int hashCode();
}
Изменение API
При изменении методов интерфейсов, от
которых не наследуется пользователь,
оставлять старые варианты с пометкой
deprecated.
Изменение API: наследование
public interface Cat {
void stroke();
}
Как добавить параметр в метод, не
ломая совместимости?
Изменение API: наследование
/** @deprecated
implement Cat2 instead */
public interface Cat {
void stroke();
}
public interface Cat2 extends Cat {
void stroke(double force);
}
Изменение API: наследование
if (cat instanceof Cat2) {
((Cat2)cat).stroke(0.5);
}
else {
cat.stroke();
}
Изменение API: наследование
public abstract class AbstractCat
implements Cat {
/** @deprecated override
stroke(double) instead */
public void stroke() {}
public void stroke(double force){
stroke();
}
}
Изменение API: наследование
Безопасное расширение интерфейсов, от
которых наследуется пользователь,
возможно только в случае, если у них есть
базовый класс, от которого все
наследуются.
Ждём Java 8 и default methods в
интерфейсах.
API в виде Internal DSL
Internal DSL (Domain Specific Language) —
код на Java, который не похож на обычный
Java-код
Обычные сеттеры
SearchQuery query =
new SearchQuery("java");
query.setSite("http://oracle.com");
query.setSortingCriteria(
SortingCriteria.RELEVANCE);
query.setMaximumResults(10);
SearchResult result = runSearch(query);
DSL на билдерах
SearchResult result =
search("java")
.onSite("http://oracle.com")
.sortByRelevance()
.returnFirst(10)
.run();
DSL на билдерах: реализация
public class SearchQuery {
private final String text;
private String site;
private SearchQuery(String text) { this.text = text; }
public static SearchQuery search(String text) {
return new SearchQuery(text);
}
public SearchQuery onSite(String site) {
this.site = site;
return this;
}
...
}
DSL на билдерах: сложный случай
Условие на место в синтаксическом дереве
в IntelliJ IDEA: http://tinyurl.com/intellij-api-1
DSL для описания XML
<web-app version="2.5">
<servlet>
<servlet-name>Sample</servlet-name>
<servlet-class>...</servlet-class>
</servlet>
</web-app>
DSL на интерфейсах
public interface WebApp {
Servlet addServlet();
List<Servlet> getServlets();
}
public interface Servlet {
String getServletName();
void setServletName(String name);
}
DSL на интерфейсах: реализация
java.lang.reflect.Proxy.newProxyInstance
(classLoader, interfaces, handler)
public interface InvocationHandler {
Object invoke(Object proxy, Method
method, Object[] args)
throws Throwable;
}
DSL на интерфейсах: реализация
AdvancedProxy в IntelliJ IDEA platform:
http://tinyurl.com/intellij-api-2
Правила разработки API
● в API — только необходимое
● реализации не место в API
● ограничивать наследование от классов API
○ выделять базовый класс для наследования

●
●
●
●
●

ешьте своё API сами; дважды
типичные задачи должны решаться просто
в случае ошибки падать как можно раньше
использовать мощь системы типов
подумать о DSL
Вопросы?
Если возникнут позже, пишите
Nikolay.Chashnikov@jetbrains.com

More Related Content

What's hot

Тестирование программного обеспечения: что, зачем и почему?
Тестирование программного обеспечения: что, зачем и почему?Тестирование программного обеспечения: что, зачем и почему?
Тестирование программного обеспечения: что, зачем и почему?Marat Akhin
 
Custom Language Plugin for JetBrains IDEA
Custom Language Plugin for JetBrains IDEACustom Language Plugin for JetBrains IDEA
Custom Language Plugin for JetBrains IDEAAlexander Zastashkov
 
Полнота тестирования ПО
Полнота тестирования ПОПолнота тестирования ПО
Полнота тестирования ПОMarat Akhin
 
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETОпыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETGoSharp
 
Проблема тестовых входных данных
Проблема тестовых входных данныхПроблема тестовых входных данных
Проблема тестовых входных данныхMarat Akhin
 
Случайное тестирование
Случайное тестированиеСлучайное тестирование
Случайное тестированиеMarat Akhin
 
Отладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программОтладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программTatyanazaxarova
 
Тестирование ПО (2016)
Тестирование ПО (2016)Тестирование ПО (2016)
Тестирование ПО (2016)Marat Akhin
 
AOP and Design Patterns (GoF)
AOP and Design Patterns (GoF)AOP and Design Patterns (GoF)
AOP and Design Patterns (GoF)Andrey Gordienkov
 
Aspect Oriented Programming and Design Patterns
Aspect Oriented Programming and Design PatternsAspect Oriented Programming and Design Patterns
Aspect Oriented Programming and Design PatternsAndrey Gordienkov
 
«Пуленепробиваемый фронтенд: разработка под React на TypeScript», Станислав П...
«Пуленепробиваемый фронтенд: разработка под React на TypeScript», Станислав П...«Пуленепробиваемый фронтенд: разработка под React на TypeScript», Станислав П...
«Пуленепробиваемый фронтенд: разработка под React на TypeScript», Станислав П...MoscowJS
 
Дебаггинг
ДебаггингДебаггинг
ДебаггингMarat Akhin
 
Разработка модуля для отладки приложений на языке ActionScript 3 в среде Visu...
Разработка модуля для отладки приложений на языке ActionScript 3 в среде Visu...Разработка модуля для отладки приложений на языке ActionScript 3 в среде Visu...
Разработка модуля для отладки приложений на языке ActionScript 3 в среде Visu...Rinat Shaikhutdinov
 
C++ осень 2012 лекция 6
C++ осень 2012 лекция 6C++ осень 2012 лекция 6
C++ осень 2012 лекция 6Technopark
 
Postman тестирование api v1.0 (1)
Postman тестирование api v1.0 (1)Postman тестирование api v1.0 (1)
Postman тестирование api v1.0 (1)DataArt
 
Тестовый оракул: что, где, когда
Тестовый оракул: что, где, когдаТестовый оракул: что, где, когда
Тестовый оракул: что, где, когдаMarat Akhin
 
Проблема наблюдаемости
Проблема наблюдаемостиПроблема наблюдаемости
Проблема наблюдаемостиMarat Akhin
 
09 - Java. Тестирование Java-программ
09 - Java. Тестирование Java-программ09 - Java. Тестирование Java-программ
09 - Java. Тестирование Java-программRoman Brovko
 
анализ кода: от проверки стиля до автоматического тестирования
анализ кода: от проверки стиля до автоматического тестированияанализ кода: от проверки стиля до автоматического тестирования
анализ кода: от проверки стиля до автоматического тестированияRuslan Shevchenko
 

What's hot (20)

Тестирование программного обеспечения: что, зачем и почему?
Тестирование программного обеспечения: что, зачем и почему?Тестирование программного обеспечения: что, зачем и почему?
Тестирование программного обеспечения: что, зачем и почему?
 
Custom Language Plugin for JetBrains IDEA
Custom Language Plugin for JetBrains IDEACustom Language Plugin for JetBrains IDEA
Custom Language Plugin for JetBrains IDEA
 
Полнота тестирования ПО
Полнота тестирования ПОПолнота тестирования ПО
Полнота тестирования ПО
 
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NETОпыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
Опыт разработки сложных клиент-серверных приложений на TypeScript и ASP.NET
 
Проблема тестовых входных данных
Проблема тестовых входных данныхПроблема тестовых входных данных
Проблема тестовых входных данных
 
Случайное тестирование
Случайное тестированиеСлучайное тестирование
Случайное тестирование
 
Отладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программОтладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программ
 
Тестирование ПО (2016)
Тестирование ПО (2016)Тестирование ПО (2016)
Тестирование ПО (2016)
 
AOP and Design Patterns (GoF)
AOP and Design Patterns (GoF)AOP and Design Patterns (GoF)
AOP and Design Patterns (GoF)
 
Aspect Oriented Programming and Design Patterns
Aspect Oriented Programming and Design PatternsAspect Oriented Programming and Design Patterns
Aspect Oriented Programming and Design Patterns
 
«Пуленепробиваемый фронтенд: разработка под React на TypeScript», Станислав П...
«Пуленепробиваемый фронтенд: разработка под React на TypeScript», Станислав П...«Пуленепробиваемый фронтенд: разработка под React на TypeScript», Станислав П...
«Пуленепробиваемый фронтенд: разработка под React на TypeScript», Станислав П...
 
Дебаггинг
ДебаггингДебаггинг
Дебаггинг
 
Разработка модуля для отладки приложений на языке ActionScript 3 в среде Visu...
Разработка модуля для отладки приложений на языке ActionScript 3 в среде Visu...Разработка модуля для отладки приложений на языке ActionScript 3 в среде Visu...
Разработка модуля для отладки приложений на языке ActionScript 3 в среде Visu...
 
C++ осень 2012 лекция 6
C++ осень 2012 лекция 6C++ осень 2012 лекция 6
C++ осень 2012 лекция 6
 
Postman тестирование api v1.0 (1)
Postman тестирование api v1.0 (1)Postman тестирование api v1.0 (1)
Postman тестирование api v1.0 (1)
 
Тестовый оракул: что, где, когда
Тестовый оракул: что, где, когдаТестовый оракул: что, где, когда
Тестовый оракул: что, где, когда
 
Проблема наблюдаемости
Проблема наблюдаемостиПроблема наблюдаемости
Проблема наблюдаемости
 
Tdd php
Tdd phpTdd php
Tdd php
 
09 - Java. Тестирование Java-программ
09 - Java. Тестирование Java-программ09 - Java. Тестирование Java-программ
09 - Java. Тестирование Java-программ
 
анализ кода: от проверки стиля до автоматического тестирования
анализ кода: от проверки стиля до автоматического тестированияанализ кода: от проверки стиля до автоматического тестирования
анализ кода: от проверки стиля до автоматического тестирования
 

Similar to API design in java project

паттерны программирования
паттерны программированияпаттерны программирования
паттерны программированияguestfc8ae0
 
Виталий Каторгин, Wamba
Виталий Каторгин, WambaВиталий Каторгин, Wamba
Виталий Каторгин, WambaOntico
 
C# Desktop. Занятие 12.
C# Desktop. Занятие 12.C# Desktop. Занятие 12.
C# Desktop. Занятие 12.Igor Shkulipa
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.Igor Shkulipa
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Yandex
 
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf Conference
 
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.Fedor Malyshkin
 
C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.Igor Shkulipa
 
Java 9: what is there beyond modularization
Java 9: what is there beyond modularizationJava 9: what is there beyond modularization
Java 9: what is there beyond modularizationIvan Krylov
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Vladimir Kochetkov
 
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»Yulia Tsisyk
 
Java весна 2013 лекция 8
Java весна 2013 лекция 8Java весна 2013 лекция 8
Java весна 2013 лекция 8Technopark
 
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNgДело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNgIT61
 
Java осень 2014 занятие 5
Java осень 2014 занятие 5Java осень 2014 занятие 5
Java осень 2014 занятие 5Technopark
 
C# Desktop. Занятие 02.
C# Desktop. Занятие 02.C# Desktop. Занятие 02.
C# Desktop. Занятие 02.Igor Shkulipa
 
Inroducing SAP ABAP - Presentation with basics SAP ABAP
Inroducing SAP ABAP - Presentation with basics SAP ABAPInroducing SAP ABAP - Presentation with basics SAP ABAP
Inroducing SAP ABAP - Presentation with basics SAP ABAPmikhailshurgulaya
 

Similar to API design in java project (20)

паттерны программирования
паттерны программированияпаттерны программирования
паттерны программирования
 
Виталий Каторгин, Wamba
Виталий Каторгин, WambaВиталий Каторгин, Wamba
Виталий Каторгин, Wamba
 
C# Desktop. Занятие 12.
C# Desktop. Занятие 12.C# Desktop. Занятие 12.
C# Desktop. Занятие 12.
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
 
Design Principles
Design PrinciplesDesign Principles
Design Principles
 
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
 
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
 
C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.
 
Java 9: what is there beyond modularization
Java 9: what is there beyond modularizationJava 9: what is there beyond modularization
Java 9: what is there beyond modularization
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!
 
Java 9 - кратко о новом
Java 9 -  кратко о новомJava 9 -  кратко о новом
Java 9 - кратко о новом
 
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
 
Java весна 2013 лекция 8
Java весна 2013 лекция 8Java весна 2013 лекция 8
Java весна 2013 лекция 8
 
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNgДело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
 
Aspect Oriented Approach
Aspect Oriented ApproachAspect Oriented Approach
Aspect Oriented Approach
 
Java осень 2014 занятие 5
Java осень 2014 занятие 5Java осень 2014 занятие 5
Java осень 2014 занятие 5
 
java 8
java 8java 8
java 8
 
C# Desktop. Занятие 02.
C# Desktop. Занятие 02.C# Desktop. Занятие 02.
C# Desktop. Занятие 02.
 
Inroducing SAP ABAP - Presentation with basics SAP ABAP
Inroducing SAP ABAP - Presentation with basics SAP ABAPInroducing SAP ABAP - Presentation with basics SAP ABAP
Inroducing SAP ABAP - Presentation with basics SAP ABAP
 

More from chashnikov

Lambdas in java 8
Lambdas in java 8Lambdas in java 8
Lambdas in java 8chashnikov
 
Statis code analysis
Statis code analysisStatis code analysis
Statis code analysischashnikov
 
Java compilers and IDEs
Java compilers and IDEsJava compilers and IDEs
Java compilers and IDEschashnikov
 
Plugin development for intelli j platform
Plugin development for intelli j platformPlugin development for intelli j platform
Plugin development for intelli j platformchashnikov
 
Effective coding in IntelliJ IDEA
Effective coding in IntelliJ IDEAEffective coding in IntelliJ IDEA
Effective coding in IntelliJ IDEAchashnikov
 
IntelliJ IDEA: architecture, performance, development process
IntelliJ IDEA: architecture, performance, development processIntelliJ IDEA: architecture, performance, development process
IntelliJ IDEA: architecture, performance, development processchashnikov
 

More from chashnikov (6)

Lambdas in java 8
Lambdas in java 8Lambdas in java 8
Lambdas in java 8
 
Statis code analysis
Statis code analysisStatis code analysis
Statis code analysis
 
Java compilers and IDEs
Java compilers and IDEsJava compilers and IDEs
Java compilers and IDEs
 
Plugin development for intelli j platform
Plugin development for intelli j platformPlugin development for intelli j platform
Plugin development for intelli j platform
 
Effective coding in IntelliJ IDEA
Effective coding in IntelliJ IDEAEffective coding in IntelliJ IDEA
Effective coding in IntelliJ IDEA
 
IntelliJ IDEA: architecture, performance, development process
IntelliJ IDEA: architecture, performance, development processIntelliJ IDEA: architecture, performance, development process
IntelliJ IDEA: architecture, performance, development process
 

API design in java project

  • 1. Разработка API в Java-проекте: как оказывать влияние на людей и не приобрести врагов Чашников Николай программист JetBrains Nikolay.Chashnikov@jetbrains.com
  • 5. К чему приводят недостатки API API неудачное, если ● его трудно понимать ● его неудобно использовать ● с ним легко допустить ошибку ● его проблематично менять ● оно недостаточно выразительно
  • 6. Свойства хорошего API ● его легко понимать ● его удобно использовать ● оно защищает от ошибок ● его можно безболезненно менять ● оно достаточно мощное
  • 7. В API — только необходимое Добавить в API просто, убрать что-то из API очень трудно. Нельзя выделять что-то в API просто “чтобы было”, “а вдруг понадобится”.
  • 8. API не должно содержать реализацию Все методы классов в API должны быть ● либо abstract ● либо возвращать значение по умолчанию ● либо делегироваться к другим методам API
  • 9. API не должно содержать реализацию ● отсутствие тел методов облегчает читаемость ● отсутствие тел методов упрощает наследование ● код, вынесенный в API, становится частью контракта
  • 10. Наследование от классов API Для каждого интерфейса в API должно быть чётко установлено, предполагается ли его наследование пользователями API. Разрешать наследование только при необходимости.
  • 11. Наследование от классов API public abstract class Car { private final String manufacturer; private final String model; public Car(String manufacturer, String model){ this.manufacturer = manufacturer; this.model = model; } public abstract void playEngineRoar(); public String getManufacturer() { return manufacturer; } public String getModel() { return model; } }
  • 12. Наследование от классов API public class AudiQ7Diesel extends Car { public AudiQ7Diesel() { super("Audi", "Q7"); } public void playEngineRoar() { ... } }
  • 13. Наследование от классов API public interface Car { String getManufacturer(); String getModel(); CarEngine getEngine(); } public interface CarEngine { void playEngineRoar(); } public interface CarFactory { Car createCar(String model, String manufacturer, CarEngine engine); }
  • 14. Запрещать всё, что не разрешено ● использовать наиболее закрытые модификаторы доступа ● делать final всё, что не предполагается переопределять
  • 15. Ешьте своё API сами. Дважды Параллельно с созданием API надо писать минимум два примера его использования.
  • 16. Мощь и простота использования Easy things should be easy, and hard things should be possible
  • 17. Как проще всего прочитать в String текст файла (в Java 6)? byte[] bytes = new byte[(int) file.length()]; DataInputStream input = new DataInputStream( new FileInputStream(file)); input.readFully(bytes); input.close(); return new String(bytes, "UTF-8");
  • 18. В Java 7 это стало проще return new String( Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
  • 19. Упрощайте доступ к нужным методам public interface Form { /** use {@link Validators} */ void check(); } public class Validators { public static boolean isValidEmail(String s){…} public static boolean isValidPhoneNumber (String s) { … } }
  • 20. Упрощайте доступ к нужным методам public class ContactsForm implements Form { ... public void check() { String phone = getPhoneNumberText(); if (!Validators.isValidPhoneNumber(phone)) { ... } } ... }
  • 21. Упрощайте доступ к нужным методам public interface Form { void check(Validators validators); } public interface Validators { boolean isValidEmail(String s); boolean isValidPhoneNumber(String s); }
  • 22. Упрощайте доступ к нужным методам public class ContactsForm implements Form { ... public void check(Validators validators) { String phone = getPhoneNumberText(); if (!validators.isValidPhoneNumber(phone)) { ... } } ... }
  • 23. Защита от ошибок ● в случае ошибки падать как можно раньше ○ в идеале — при компиляции ● не использовать String и boolean, если есть более подходящие типы ● использовать generics вместо casts и Object ● использовать аннотации @NotNull, @Nullable
  • 24. Слабая типизация public interface AssortedData { void putData(String key, Object data); Object getData(String key); }
  • 25. Сильная типизация final class Key<T> {} public interface AssortedData { <T> void putData(Key<T> key, T data); <T> T getData(Key<T> key); }
  • 26. Как при использовании этого класса можно ошибиться? public class Shop { private List<Order> orders = new ArrayList<Order>(); private Order[] ordersArray; public void addOrder(Order order) { orders.add(order); ordersArray = null; } public Order[] getOrders() { if (ordersArray == null) ordersArray = orders.toArray(new Order[orders.size()]); return ordersArray; } }
  • 27. Например, вот так Order[] orders = shop.getOrders(); … … Arrays.sort(orders);
  • 28. А вот как от этого защититься public class Shop { private List<Order> orders = new ArrayList<Order>(); private List<Order> unmodifiableOrders = Collections.unmodifiableList(orders); public void addOrder(Order order) { orders.add(order); } public List<Order> getOrders() { return unmodifiableOrders; } }
  • 29. Тот номер больше не пройдёт List<Order> orders = shop.getOrders(); … … Collections.sort(orders); //вылетит UnsupportedOperationException
  • 30. Защита от ошибок ● избегать неявных ограничений ● использовать immutable объекты
  • 31. Навязывать нужное поведение public class DoNotOverrideEquals { public final boolean equals(Object obj) { return super.equals(obj); } public final int hashCode() { return super.hashCode(); } }
  • 32. Навязывать нужное поведение public abstract class MustOverrideEquals { public abstract boolean equals( Object obj); public abstract int hashCode(); }
  • 33. Изменение API При изменении методов интерфейсов, от которых не наследуется пользователь, оставлять старые варианты с пометкой deprecated.
  • 34. Изменение API: наследование public interface Cat { void stroke(); } Как добавить параметр в метод, не ломая совместимости?
  • 35. Изменение API: наследование /** @deprecated implement Cat2 instead */ public interface Cat { void stroke(); } public interface Cat2 extends Cat { void stroke(double force); }
  • 36. Изменение API: наследование if (cat instanceof Cat2) { ((Cat2)cat).stroke(0.5); } else { cat.stroke(); }
  • 37. Изменение API: наследование public abstract class AbstractCat implements Cat { /** @deprecated override stroke(double) instead */ public void stroke() {} public void stroke(double force){ stroke(); } }
  • 38. Изменение API: наследование Безопасное расширение интерфейсов, от которых наследуется пользователь, возможно только в случае, если у них есть базовый класс, от которого все наследуются. Ждём Java 8 и default methods в интерфейсах.
  • 39. API в виде Internal DSL Internal DSL (Domain Specific Language) — код на Java, который не похож на обычный Java-код
  • 40. Обычные сеттеры SearchQuery query = new SearchQuery("java"); query.setSite("http://oracle.com"); query.setSortingCriteria( SortingCriteria.RELEVANCE); query.setMaximumResults(10); SearchResult result = runSearch(query);
  • 41. DSL на билдерах SearchResult result = search("java") .onSite("http://oracle.com") .sortByRelevance() .returnFirst(10) .run();
  • 42. DSL на билдерах: реализация public class SearchQuery { private final String text; private String site; private SearchQuery(String text) { this.text = text; } public static SearchQuery search(String text) { return new SearchQuery(text); } public SearchQuery onSite(String site) { this.site = site; return this; } ... }
  • 43. DSL на билдерах: сложный случай Условие на место в синтаксическом дереве в IntelliJ IDEA: http://tinyurl.com/intellij-api-1
  • 44. DSL для описания XML <web-app version="2.5"> <servlet> <servlet-name>Sample</servlet-name> <servlet-class>...</servlet-class> </servlet> </web-app>
  • 45. DSL на интерфейсах public interface WebApp { Servlet addServlet(); List<Servlet> getServlets(); } public interface Servlet { String getServletName(); void setServletName(String name); }
  • 46. DSL на интерфейсах: реализация java.lang.reflect.Proxy.newProxyInstance (classLoader, interfaces, handler) public interface InvocationHandler { Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
  • 47. DSL на интерфейсах: реализация AdvancedProxy в IntelliJ IDEA platform: http://tinyurl.com/intellij-api-2
  • 48. Правила разработки API ● в API — только необходимое ● реализации не место в API ● ограничивать наследование от классов API ○ выделять базовый класс для наследования ● ● ● ● ● ешьте своё API сами; дважды типичные задачи должны решаться просто в случае ошибки падать как можно раньше использовать мощь системы типов подумать о DSL
  • 49. Вопросы? Если возникнут позже, пишите Nikolay.Chashnikov@jetbrains.com