api design done right: some guidelines which every programmer should probably know
Post on 13-Apr-2018
240 Views
Preview:
TRANSCRIPT
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
1/25
API Design Done RightSome guidelines which every programmer should probably know
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
2/25
API Design Done WRONG
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
3/25
Copyright Reaktor 2011
publicintcountBigCustomers() {
Connection connection = null;
try{
connection = DriverManager.getConnection("jdbc:h2:mem:");
PreparedStatement statement = connection
.prepareStatement("SELECT COUNT(*) FROM CUSTOMERS WHERE REVENUE > ?");
// Do indexes start from 0 or 1?
statement.setLong(1, 1000000L);
ResultSet resultSet = statement.executeQuery();
resultSet.next();
// Do indexes start from 0 or 1?
intresult = resultSet.getInt(1);
returnresult;
} catch(SQLException e) {
// Checked exception - ouch!
thrownewRuntimeException(e);
} finally{
try{
if(connection != null&& !connection.isClosed()) {
connection.close();
} } catch(SQLException e) {
// Checked exception - aargh
thrownewRuntimeException(e);
}
}
}
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
4/25
Copyright Reaktor 2011
publicintcountBigCustomers() {
Connection connection = null;
try{
connection = DriverManager.getConnection("jdbc:h2:mem:");
PreparedStatementstatement = connection
.prepareStatement("SELECT COUNT(*) FROM CUSTOMERS WHERE REVENUE > ?");
// Do indexes start from 0 or 1?
statement.setLong(1,1000000L);
ResultSet resultSet = statement.executeQuery();
resultSet.next();
// Do indexes start from 0 or 1?
intresult = resultSet.getInt(1);
returnresult;
} catch (SQLException e) {
// Checked exception - ouch!
thrownewRuntimeException(e);
} finally {
try{
if(connection != null && !connection.isClosed()) {
connection.close();
} } catch (SQLException e) {
// Checked exception - aargh
thrownewRuntimeException(e);
}
}
}
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
5/25
Copyright Reaktor 2011 Confidential
publicintcountBigCustomers() {
JdbcTemplate jdbc = newJdbcTemplate(newSingleConnectionDataSource(
"jdbc:h2:mem:", false));
returnjdbc.queryForInt(
"SELECT COUNT(*) FROM CUSTOMERS WHERE REVENUE > ?", 1000000L);
}
A bit better way
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
6/25
Copyright Reaktor 2011
Why API Design Matters
Usually write-once,
read/learn many times
by many different people
Every piece of code has an API
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
7/25
Copyright Reaktor 2011
Why API Design Matters
Bad API usually leads to bad client code
Bad API design tends to infect all abovelayers
http://www.flickr.com/photos/bamshad/1469713774/sizes/s/in/photostream/
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
8/25
Copyright Reaktor 2011
API is a User Interface
The same principles apply
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
9/25
Copyright Reaktor 2011
API is a User Interface
The purpose and usages must be known
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
10/25
Copyright Reaktor 2011
API is a User Interface
Make correct usage easy
Make wrong usage hard
(or impossible)
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
11/25
Copyright Reaktor 2011
Good API
Intuitive
Easy to learn from simple examples
Self explanatory
Effort minimizing
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
12/25
Copyright Reaktor 2011
Levels of abstraction
publicintcountBigCustomers() {
Connection connection = null;
try{
connection = DriverManager.getConnection
("jdbc:h2:mem:");
PreparedStatement statement = connection
.prepareStatement("SELECT COUNT(*)
FROM CUSTOMERS WHERE REVENUE > ?");
// Do indexes start from 0 or 1?
statement.setLong(1, 1000000L);
ResultSet resultSet = statement.executeQuery();
resultSet.next();
// Do indexes start from 0 or 1? intresult = resultSet.getInt(1);
returnresult;
} catch(SQLException e) {
// Checked exception - ouch!
thrownew RuntimeException(e);
} finally{
try{
if(connection != null&& !
connection.isClosed()) {
connection.close();
}
} catch(SQLException e) {
// Checked exception - aargh thrownewRuntimeException(e);
}
}
}
publicintcountBigCustomers() {
JdbcTemplate jdbc = newJdbcTemplate(newSingleConnectionDataSource(
"jdbc:h2:mem:", false));
returnjdbc.queryForInt(
"SELECT COUNT(*) FROM CUSTOMERS WHERE REVENUE > ?", 1000000L);
}
JDBC API Spring API
Good abstraction level for low-level library code, bad for
application code
Good abstraction level forapplication code
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
13/25
Copyright Reaktor 2011
Levels of abstraction
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
14/25
Copyright Reaktor 2011
Client perspective with TDD@RunWith(Enclosed.class)
publicclassOrderBuilderTest {
publicstaticclassWhenBuildingOrderWithTwoProducts {
privateOrder order;
@Before
publicvoidsetUp() {
// API as an user interface - how user of the API would
create an order order= newOrderBuilder(CustomerId.FANBOY_CUSTOMER)
.with(ProductId.JPHONE_6, 4)
.with(ProductId.CONSTELLATION_TABLET, 2)
.build();
}
@Test publicvoidorderHasTwoRows() {
assertThat(order.orderRows().size(), is(2));
}
}
}
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
15/25
Copyright Reaktor 2011
Simplicity
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
16/25
Copyright Reaktor 2011
Object initialization
An object should be in valid, usable stateimmediately.
Component c = newComponent();
// Here the component cannot be used
// yet, since it is not initialized,
// i.e. it is in an invalid state.
c.initialize(newConfiguration());
// Only now the component can be used.
BAD!!!
Component c = newComponent(new
Configuration());
// Now the component can be used
// immediately. BETTER
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
17/25
Copyright Reaktor 2011
Object initialization
Use builders or factories for more complexinitializations
order= newOrderBuilder(CustomerId.FANBOY_CUSTOMER)
.with(ProductId.JPHONE_6, 4)
.with(ProductId.CONSTELLATION_TABLET, 2)
.build();
// default visibility
// we can only create objects with valid state
Order(CustomerId customerId, List orderRows) {
this.customerId= customerId;
this.orderRows= Collections.unmodifiableList(orderRows);
}
publicclassOrderBuilder {
publicOrderBuilder(CustomerId customerId) { ... }
publicOrderBuilder with(ProductId productId, intquantity) { ... }
publicOrder build() { ...}
}
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
18/25
Copyright Reaktor 2011
Object state
It should be impossible to get an object in anillegal state.
Object should be in a valid state between
any method calls.
Fail fast if the method call would leave the
object in an invalid state.
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
19/25
Copyright Reaktor 2011
Object state
Prefer immutability
publicclassOrder {
privatefinalCustomerId customerId;
privatefinalList orderRows;
Order(CustomerId customerId, List orderRows) {
this.customerId= customerId;
this.orderRows= Collections.unmodifiableList(orderRows);
}
}
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
20/25
Copyright Reaktor 2011
Atomic operations
// User must explicitly begin transaction...c.beginTransaction();
// ...do their stuff...
c.doSomething();
// ...and remember to commit...
c.commit();
// ...but what if something fails in between?
c.doInTransaction(newCallback() {
@Override
publicvoidexecute(Component c) {
// Method doInTransaction() takes
// care oftransaction management
// and error handling
c.doSomething();
}
});
BAD!!!
BETTER
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
21/25
Copyright Reaktor 2011
Visibility and packages in Java
Domain class name is the package name:packagemyapp.domain.order;
All services, interfaces and implementation
related to this domain class in the samepackage.
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
22/25
Copyright Reaktor 2011
Visibility and packages in Java
Public visibility:domain class,
interfaces for services,
builders, ...
publicclassOrder { ...
public interface OrderRepository { ...
public class OrderBuilder { ...
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
23/25
Copyright Reaktor 2011
Visibility and packages in JavaDefault visibility:
domain object constructors,
implementation classes
// domain object constructor
Order(CustomerId customerId, List orderRows) { ...
// repository implementation
classJdbcOrderRepository implementsOrderRepository { ...
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
24/25
Copyright Reaktor 2011
Domain Specific Languages
Counting two weeks from a given date:
publicDate twoWeeksFrom(Date beginning) {
// You have to create a
// separate Calendar object...
Calendar calendar = Calendar.getInstance(); // And modify its state...
calendar.setTime(beginning);
// And modify its state a little more...
calendar.add(Calendar.DAY_OF_MONTH, 14);
// ...before you get the answer.
returncalendar.getTime();
}
publicDateTime twoWeeksFrom(DateTime beginning) {
returnbeginning.plusWeeks(2);
}
Standard Java Calendar API
Joda-Time
Monday, September 12, 2011
-
7/26/2019 API Design Done Right: Some guidelines which every programmer should probably know
25/25
Copyright Reaktor 2011
Thank you!
Jari Mkel
Ville Peurala
mailto:ville.peurala@reaktor.fimailto:ville.peurala@reaktor.fimailto:jari.makela@reaktor.fimailto:jari.makela@reaktor.fi
top related