SlideShare a Scribd company logo
1 of 61
Download to read offline
Let's make a contract:
the art of designing a
Java API
by Mario Fusco
mario.fusco@gmail.com
@mariofusco
What is an API?
What is an API?
An API is what a
developer uses to
achieve some task
What is an API?
What is an API?
An API is a contract between
its implementors and its users
And why should I care?
We are all API designers
Our software doesn't work in
isolation, but becomes
useful only when it interacts
with other software written
by other developers
Basic Principles
●
Intuitive
●
Understandable
●
Learnable
●
Discoverable
●
Consistent
●
Self-defensive
●
Concise
●
Easy to use
●
Minimal
●
Orthogonal
●
Idiomatic
●
Flexible
●
Evolvable
●
Well documented
●
Right level of abstraction
●
Correct use of the type system
●
Limited number of entry-points
●
Respect the principle of least astonishment
Best Practices
&
Practical Hints
Write meaningful Javadocs
Write meaningful Javadocs
Write meaningful Javadocs
Write meaningful Javadocs
Convenience methods
Use overloading judiciously
and sparingly
Convenience methods
Use overloading judiciously
and sparingly
Primitives often cause
methods proliferation
{
Convenience methods
Use overloading judiciously
and sparingly
Are these all
necessary?
Primitives often cause
methods proliferation
{
Convenience methods
public interface StockOrder {
void sell(String symbol, double price, int quantity);
void buy(String symbol, int quantity, double price);
void buy(String symbol, int quantity, double price, double commission);
void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission);
}
What’s wrong with this?
Convenience methods
public interface StockOrder {
void sell(String symbol, double price, int quantity);
void buy(String symbol, int quantity, double price);
void buy(String symbol, int quantity, double price, double commission);
void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission);
}
Too many overloads
What’s wrong with this?
Convenience methods
public interface StockOrder {
void sell(String symbol, double price, int quantity);
void buy(String symbol, int quantity, double price);
void buy(String symbol, int quantity, double price, double commission);
void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission);
}
Too many overloads
Inconsistent argument order
What’s wrong with this?
Convenience methods
Long arguments lists (especially of same type)
public interface StockOrder {
void sell(String symbol, double price, int quantity);
void buy(String symbol, int quantity, double price);
void buy(String symbol, int quantity, double price, double commission);
void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission);
}
Too many overloads
Inconsistent argument order
What’s wrong with this?
Convenience methods
Long arguments lists (especially of same type)
public interface StockOrder {
void sell(String symbol, double price, int quantity);
void buy(String symbol, int quantity, double price);
void buy(String symbol, int quantity, double price, double commission);
void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission);
}
public interface StockOrder {
void sell(String symbol, int quantity, Price price);
void buy(String symbol, int quantity, Price price);
}
Too many overloads
Inconsistent argument order
What’s wrong with this?
How to do better
Consider static
factories
public interface Price {
static Price price( double price ) {
if (price < 0) return Malformed.INSTANCE;
return new Fixed(price);
}
static Price price( double minPrice, double maxPrice ) {
if (minPrice > maxPrice) return Malformed.INSTANCE;
return new Range(minPrice, maxPrice);
}
class Fixed implements Price {
private final double price;
private Fixed( double price ) {
this.price = price;
}
}
class Range implements Price {
private final double minPrice;
private final double maxPrice;
private Range( double minPrice, double maxPrice ) {
this.minPrice = minPrice;
this.maxPrice = maxPrice;
}
}
enum Malformed implements Price { INSTANCE }
}
➢
nicer syntax for users
(no need of new
keyword)
Consider static
factories
public interface Price {
static Price price( double price ) {
if (price < 0) return Malformed.INSTANCE;
return new Fixed(price);
}
static Price price( double minPrice, double maxPrice ) {
if (minPrice > maxPrice) return Malformed.INSTANCE;
return new Range(minPrice, maxPrice);
}
class Fixed implements Price {
private final double price;
private Fixed( double price ) {
this.price = price;
}
}
class Range implements Price {
private final double minPrice;
private final double maxPrice;
private Range( double minPrice, double maxPrice ) {
this.minPrice = minPrice;
this.maxPrice = maxPrice;
}
}
enum Malformed implements Price { INSTANCE }
}
➢
nicer syntax for users
(no need of new
keyword)
➢
can return different
subclasses
Consider static
factories
public interface Price {
static Price price( double price ) {
if (price < 0) return Malformed.INSTANCE;
return new Fixed(price);
}
static Price price( double minPrice, double maxPrice ) {
if (minPrice > maxPrice) return Malformed.INSTANCE;
return new Range(minPrice, maxPrice);
}
class Fixed implements Price {
private final double price;
private Fixed( double price ) {
this.price = price;
}
}
class Range implements Price {
private final double minPrice;
private final double maxPrice;
private Range( double minPrice, double maxPrice ) {
this.minPrice = minPrice;
this.maxPrice = maxPrice;
}
}
enum Malformed implements Price { INSTANCE }
}
➢
nicer syntax for users
(no need of new
keyword)
➢
can return different
subclasses
➢
can check
preconditions and
edge cases returning
different
implementations
accordingly
Promote fluent API
public interface Price {
Price withCommission(double commission);
Price gross();
}
public interface Price {
void setCommission(double commission);
void setGross();
}
Promote fluent API
public interface Price {
Price withCommission(double commission);
Price gross();
}
stockOrder.buy( "IBM", 100, price(150.0).withCommission(0.7).gross() );
public interface Price {
void setCommission(double commission);
void setGross();
}
Price price = price(150.0);
price.setCommission(0.7);
price.setGross();
stockOrder.buy( "IBM", 100, price );
Promote fluent API
public interface Price {
Price withCommission(double commission);
Price gross();
}
stockOrder.buy( "IBM", 100, price(150.0).withCommission(0.7).gross() );
public interface Price {
void setCommission(double commission);
void setGross();
}
Price price = price(150.0);
price.setCommission(0.7);
price.setGross();
stockOrder.buy( "IBM", 100, price );
Concatenate multiple invocations
Use result directly
Promote fluent API
Streams are a very
nice and convenient
example of fluent API
Promote fluent API
Streams are a very
nice and convenient
example of fluent API
Promote fluent API
Name consistency???
Streams are a very
nice and convenient
example of fluent API
Use the weakest possible type
public String concatenate( ArrayList<String> strings ) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append( s );
}
return sb.toString();
}
Use the weakest possible type
public String concatenate( ArrayList<String> strings ) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append( s );
}
return sb.toString();
}
Do I care of the actual
List implementation?
Use the weakest possible type
public String concatenate( List<String> strings ) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append( s );
}
return sb.toString();
}
Use the weakest possible type
public String concatenate( List<String> strings ) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append( s );
}
return sb.toString();
}
Do I care of the
elements’ order?
Use the weakest possible type
public String concatenate( Collection<String> strings ) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append( s );
}
return sb.toString();
}
Use the weakest possible type
public String concatenate( Collection<String> strings ) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append( s );
}
return sb.toString();
}
Do I care of the
Collection’s size?
Use the weakest possible type
public String concatenate( Iterable<String> strings ) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append( s );
}
return sb.toString();
}
Using the weakest possible type...
public String concatenate( Iterable<String> strings ) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append( s );
}
return sb.toString();
}
… enlarges the applicability of your method, avoiding to restrict your client
to a particular implementation or forcing it to perform an unnecessary and
potentially expensive copy operation if the input data exists in other forms
Use the weakest possible type
also for returned value
public List<Address> getFamilyAddresses( Person person ) {
List<Address> addresses = new ArrayList<>();
addresses.add(person.getAddress());
for (Person sibling : person.getSiblings()) {
addresses.add(sibling.getAddress());
}
return addresses;
}
Use the weakest possible type
also for returned value
public List<Address> getFamilyAddresses( Person person ) {
List<Address> addresses = new ArrayList<>();
addresses.add(person.getAddress());
for (Person sibling : person.getSiblings()) {
addresses.add(sibling.getAddress());
}
return addresses;
}
Is the order of this List
meaningful for client?
Use the weakest possible type
also for returned value
public List<Address> getFamilyAddresses( Person person ) {
List<Address> addresses = new ArrayList<>();
addresses.add(person.getAddress());
for (Person sibling : person.getSiblings()) {
addresses.add(sibling.getAddress());
}
return addresses;
}
Is the order of this List
meaningful for client?
… and shouldn’t we maybe return only
the distinct addresses?
Yeah, that will be easy let’s do this!
Use the weakest possible type
also for returned value
public List<Address> getFamilyAddresses( Person person ) {
Set<Address> addresses = new HashSet<>();
addresses.add(person.getAddress());
for (Person sibling : person.getSiblings()) {
addresses.add(sibling.getAddress());
}
return addresses;
}
It should be enough to
change this List into a Set
Use the weakest possible type
also for returned value
public List<Address> getFamilyAddresses( Person person ) {
Set<Address> addresses = new HashSet<>();
addresses.add(person.getAddress());
for (Person sibling : person.getSiblings()) {
addresses.add(sibling.getAddress());
}
return addresses;
}
It should be enough to
change this List into a Set
But this doesn’t
compile :(
Use the weakest possible type
also for returned value
public List<Address> getFamilyAddresses( Person person ) {
Set<Address> addresses = new HashSet<>();
addresses.add(person.getAddress());
for (Person sibling : person.getSiblings()) {
addresses.add(sibling.getAddress());
}
return addresses;
}
It should be enough to
change this List into a Set
But this doesn’t
compile :(
and I cannot change the returned type to
avoid breaking backward compatibility :(((
Use the weakest possible type
also for returned value
public List<Address> getFamilyAddresses( Person person ) {
Set<Address> addresses = new HashSet<>();
addresses.add(person.getAddress());
for (Person sibling : person.getSiblings()) {
addresses.add(sibling.getAddress());
}
return new ArrayList<>( addresses );
}
I’m obliged to uselessly create an expensive
copy of data before returning them
Use the weakest possible type
also for returned value
public Collection<Address> getFamilyAddresses( Person person ) {
List<Address> addresses = new ArrayList<>();
addresses.add(person.getAddress());
for (Person sibling : person.getSiblings()) {
addresses.add(sibling.getAddress());
}
return addresses;
}
Returning a more generic type (if this is acceptable
for your client) provides better flexibility in future
Support lambdas
public interface Listener {
void beforeEvent(Event e);
void afterEvent(Event e);
}
class EventProducer {
public void registerListener(Listener listener) {
// register listener
}
}
public interface Listener {
void beforeEvent(Event e);
void afterEvent(Event e);
}
public interface Listener {
void beforeEvent(Event e);
void afterEvent(Event e);
}
EventProducer producer = new EventProducer();
producer.registerListener( new Listener() {
@Override
public void beforeEvent( Event e ) {
// ignore
}
@Override
public void afterEvent( Event e ) {
System.out.println(e);
}
} );
Support lambdas
class EventProducer {
public void registerBefore(BeforeListener before) {
// register listener
}
public void registerAfter(AfterListener after) {
// register listener
}
}
@FunctionalInterface
interface BeforeListener {
void beforeEvent( Event e );
}
@FunctionalInterface
interface AfterListener {
void afterEvent( Event e );
}
EventProducer producer = new EventProducer();
producer.registerAfter( System.out::println );
Taking functional interfaces as
argument of your API enables
clients to use lambdas
Support lambdas
class EventProducer {
public void registerBefore(Consumer<Event> before) {
// register listener
}
public void registerAfter(Consumer<Event> after) {
// register listener
}
}
@FunctionalInterface
interface BeforeListener {
void beforeEvent( Event e );
}
@FunctionalInterface
interface AfterListener {
void afterEvent( Event e );
}
EventProducer producer = new EventProducer();
producer.registerAfter( System.out::println );
Taking functional interfaces as
argument of your API enables
clients to use lambdas
In many cases you don’t need
to define your own functional
interfaces and use Java’s one
Optional – the mother of all bikeshedding
Optional – the mother of all bikeshedding
Principle of least
astonishment???
"If a necessary feature has a high
astonishment factor, it may be
necessary to redesign the feature."
- Cowlishaw, M. F. (1984). "The
design of the REXX language"
Optional – the mother of all bikeshedding
Principle of least
astonishment???
Wrong default
Optional – the mother of all bikeshedding
Principle of least
astonishment???
Wrong default
This could be removed if
the other was correctly
implemented
API design is an
iterative process
and there could
be different points
of view ...
… that could be
driven by the fact
that different
people may
weigh possible
use cases
differently...
… or even see
use cases to
which you didn’t
think at all
Also a good API
has many
different
characteristics ...
… and they
could be
conflicting so you
may need to
trade off one to
privilege another
What should
always drive the
final decision is
the intent of the
API … but even
there it could be
hard to find an
agreement
●
Write lots of tests and examples against your API
●
Discuss it with colleagues and end users
●
Iterates multiple times to eliminate
➢
Unclear intentions
➢
Duplicated or redundant code
➢
Leaky abstraction
API design is an
iterative process
●
Write lots of tests and examples against your API
●
Discuss it with colleagues and end users
●
Iterates multiple times to eliminate
➢
Unclear intentions
➢
Duplicated or redundant code
➢
Leaky abstraction
Practice Dogfeeding
API design is an
iterative process
And that’s all
what you were
getting wrong :)
… questions?
Mario Fusco
Red Hat – Principal Software Engineer
mario.fusco@gmail.com
twitter: @mariofusco

More Related Content

What's hot

AngularJS CheatSheet
AngularJS CheatSheetAngularJS CheatSheet
AngularJS CheatSheetAbdul Basit
 
Function Applicative for Great Good of Palindrome Checker Function - Polyglot...
Function Applicative for Great Good of Palindrome Checker Function - Polyglot...Function Applicative for Great Good of Palindrome Checker Function - Polyglot...
Function Applicative for Great Good of Palindrome Checker Function - Polyglot...Philip Schwarz
 
FParsec Hands On - F#unctional Londoners 2014
FParsec Hands On -  F#unctional Londoners 2014FParsec Hands On -  F#unctional Londoners 2014
FParsec Hands On - F#unctional Londoners 2014Phillip Trelford
 
Scala categorytheory
Scala categorytheoryScala categorytheory
Scala categorytheoryKnoldus Inc.
 
2 kotlin vs. java: what java has that kotlin does not
2  kotlin vs. java: what java has that kotlin does not2  kotlin vs. java: what java has that kotlin does not
2 kotlin vs. java: what java has that kotlin does notSergey Bandysik
 
Functional Programming With Scala
Functional Programming With ScalaFunctional Programming With Scala
Functional Programming With ScalaKnoldus Inc.
 
Learning Functional Programming Without Growing a Neckbeard
Learning Functional Programming Without Growing a NeckbeardLearning Functional Programming Without Growing a Neckbeard
Learning Functional Programming Without Growing a NeckbeardKelsey Gilmore-Innis
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)Scott Wlaschin
 
Introduction to Client-Side Javascript
Introduction to Client-Side JavascriptIntroduction to Client-Side Javascript
Introduction to Client-Side JavascriptJulie Iskander
 
Library functions in c++
Library functions in c++Library functions in c++
Library functions in c++Neeru Mittal
 
Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Heiko Behrens
 
Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskellnebuta
 
FP 201 - Unit 6
FP 201 - Unit 6FP 201 - Unit 6
FP 201 - Unit 6rohassanie
 

What's hot (20)

AngularJS CheatSheet
AngularJS CheatSheetAngularJS CheatSheet
AngularJS CheatSheet
 
Clojure basics
Clojure basicsClojure basics
Clojure basics
 
Function Applicative for Great Good of Palindrome Checker Function - Polyglot...
Function Applicative for Great Good of Palindrome Checker Function - Polyglot...Function Applicative for Great Good of Palindrome Checker Function - Polyglot...
Function Applicative for Great Good of Palindrome Checker Function - Polyglot...
 
FParsec Hands On - F#unctional Londoners 2014
FParsec Hands On -  F#unctional Londoners 2014FParsec Hands On -  F#unctional Londoners 2014
FParsec Hands On - F#unctional Londoners 2014
 
Scala categorytheory
Scala categorytheoryScala categorytheory
Scala categorytheory
 
2 kotlin vs. java: what java has that kotlin does not
2  kotlin vs. java: what java has that kotlin does not2  kotlin vs. java: what java has that kotlin does not
2 kotlin vs. java: what java has that kotlin does not
 
10. funtions and closures IN SWIFT PROGRAMMING
10. funtions and closures IN SWIFT PROGRAMMING10. funtions and closures IN SWIFT PROGRAMMING
10. funtions and closures IN SWIFT PROGRAMMING
 
Functional Programming With Scala
Functional Programming With ScalaFunctional Programming With Scala
Functional Programming With Scala
 
Learning Functional Programming Without Growing a Neckbeard
Learning Functional Programming Without Growing a NeckbeardLearning Functional Programming Without Growing a Neckbeard
Learning Functional Programming Without Growing a Neckbeard
 
Computer Programming- Lecture 5
Computer Programming- Lecture 5 Computer Programming- Lecture 5
Computer Programming- Lecture 5
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
Introduction to Client-Side Javascript
Introduction to Client-Side JavascriptIntroduction to Client-Side Javascript
Introduction to Client-Side Javascript
 
Monadic Java
Monadic JavaMonadic Java
Monadic Java
 
Library functions in c++
Library functions in c++Library functions in c++
Library functions in c++
 
Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009
 
Go &lt;-> Ruby
Go &lt;-> RubyGo &lt;-> Ruby
Go &lt;-> Ruby
 
Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskell
 
Scala functions
Scala functionsScala functions
Scala functions
 
FP 201 - Unit 6
FP 201 - Unit 6FP 201 - Unit 6
FP 201 - Unit 6
 
Lecture 7
Lecture 7Lecture 7
Lecture 7
 

Similar to Let's make a contract: The art of designing a Java API | DevNation Tech Talk

Complete Notes on Angular 2 and TypeScript
Complete Notes on Angular 2 and TypeScriptComplete Notes on Angular 2 and TypeScript
Complete Notes on Angular 2 and TypeScriptEPAM Systems
 
An introduction to functional programming with Swift
An introduction to functional programming with SwiftAn introduction to functional programming with Swift
An introduction to functional programming with SwiftFatih Nayebi, Ph.D.
 
TypeScript Presentation - Jason Haffey
TypeScript Presentation - Jason HaffeyTypeScript Presentation - Jason Haffey
TypeScript Presentation - Jason HaffeyRalph Johnson
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?Nikita Popov
 
Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Fwdays
 
Reflection in Go
Reflection in GoReflection in Go
Reflection in Gostrikr .
 
Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentationVan Huong
 
MongoDB World 2019: BSON Transpilers: Transpiling from Any Language to Any La...
MongoDB World 2019: BSON Transpilers: Transpiling from Any Language to Any La...MongoDB World 2019: BSON Transpilers: Transpiling from Any Language to Any La...
MongoDB World 2019: BSON Transpilers: Transpiling from Any Language to Any La...MongoDB
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimizedWoody Pewitt
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondMario Fusco
 
SeriesTester.classpathSeriesTester.project SeriesT.docx
SeriesTester.classpathSeriesTester.project  SeriesT.docxSeriesTester.classpathSeriesTester.project  SeriesT.docx
SeriesTester.classpathSeriesTester.project SeriesT.docxlesleyryder69361
 
Milano JS Meetup - Gabriele Petronella - Codemotion Milan 2016
Milano JS Meetup -  Gabriele Petronella - Codemotion Milan 2016Milano JS Meetup -  Gabriele Petronella - Codemotion Milan 2016
Milano JS Meetup - Gabriele Petronella - Codemotion Milan 2016Codemotion
 
TypeScript by Howard
TypeScript by HowardTypeScript by Howard
TypeScript by HowardLearningTech
 
Howard type script
Howard   type scriptHoward   type script
Howard type scriptLearningTech
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongMario Fusco
 

Similar to Let's make a contract: The art of designing a Java API | DevNation Tech Talk (20)

Functional Programming with C#
Functional Programming with C#Functional Programming with C#
Functional Programming with C#
 
Complete Notes on Angular 2 and TypeScript
Complete Notes on Angular 2 and TypeScriptComplete Notes on Angular 2 and TypeScript
Complete Notes on Angular 2 and TypeScript
 
An introduction to functional programming with Swift
An introduction to functional programming with SwiftAn introduction to functional programming with Swift
An introduction to functional programming with Swift
 
TypeScript Presentation - Jason Haffey
TypeScript Presentation - Jason HaffeyTypeScript Presentation - Jason Haffey
TypeScript Presentation - Jason Haffey
 
Computer programming 2 Lesson 10
Computer programming 2  Lesson 10Computer programming 2  Lesson 10
Computer programming 2 Lesson 10
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?
 
Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"
 
Legacy is Good
Legacy is GoodLegacy is Good
Legacy is Good
 
Reflection in Go
Reflection in GoReflection in Go
Reflection in Go
 
Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentation
 
MongoDB World 2019: BSON Transpilers: Transpiling from Any Language to Any La...
MongoDB World 2019: BSON Transpilers: Transpiling from Any Language to Any La...MongoDB World 2019: BSON Transpilers: Transpiling from Any Language to Any La...
MongoDB World 2019: BSON Transpilers: Transpiling from Any Language to Any La...
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimized
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
 
Introducing dimensional
Introducing dimensionalIntroducing dimensional
Introducing dimensional
 
SeriesTester.classpathSeriesTester.project SeriesT.docx
SeriesTester.classpathSeriesTester.project  SeriesT.docxSeriesTester.classpathSeriesTester.project  SeriesT.docx
SeriesTester.classpathSeriesTester.project SeriesT.docx
 
Milano JS Meetup - Gabriele Petronella - Codemotion Milan 2016
Milano JS Meetup -  Gabriele Petronella - Codemotion Milan 2016Milano JS Meetup -  Gabriele Petronella - Codemotion Milan 2016
Milano JS Meetup - Gabriele Petronella - Codemotion Milan 2016
 
TypeScript by Howard
TypeScript by HowardTypeScript by Howard
TypeScript by Howard
 
Howard type script
Howard   type scriptHoward   type script
Howard type script
 
Chapter 03
Chapter 03Chapter 03
Chapter 03
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 

More from Red Hat Developers

DevNation Tech Talk: Getting GitOps
DevNation Tech Talk: Getting GitOpsDevNation Tech Talk: Getting GitOps
DevNation Tech Talk: Getting GitOpsRed Hat Developers
 
Exploring the power of OpenTelemetry on Kubernetes
Exploring the power of OpenTelemetry on KubernetesExploring the power of OpenTelemetry on Kubernetes
Exploring the power of OpenTelemetry on KubernetesRed Hat Developers
 
GitHub Makeover | DevNation Tech Talk
GitHub Makeover | DevNation Tech TalkGitHub Makeover | DevNation Tech Talk
GitHub Makeover | DevNation Tech TalkRed Hat Developers
 
Quinoa: A modern Quarkus UI with no hassles | DevNation tech Talk
Quinoa: A modern Quarkus UI with no hassles | DevNation tech TalkQuinoa: A modern Quarkus UI with no hassles | DevNation tech Talk
Quinoa: A modern Quarkus UI with no hassles | DevNation tech TalkRed Hat Developers
 
Extra micrometer practices with Quarkus | DevNation Tech Talk
Extra micrometer practices with Quarkus | DevNation Tech TalkExtra micrometer practices with Quarkus | DevNation Tech Talk
Extra micrometer practices with Quarkus | DevNation Tech TalkRed Hat Developers
 
Event-driven autoscaling through KEDA and Knative Integration | DevNation Tec...
Event-driven autoscaling through KEDA and Knative Integration | DevNation Tec...Event-driven autoscaling through KEDA and Knative Integration | DevNation Tec...
Event-driven autoscaling through KEDA and Knative Integration | DevNation Tec...Red Hat Developers
 
Integrating Loom in Quarkus | DevNation Tech Talk
Integrating Loom in Quarkus | DevNation Tech TalkIntegrating Loom in Quarkus | DevNation Tech Talk
Integrating Loom in Quarkus | DevNation Tech TalkRed Hat Developers
 
Quarkus Renarde 🦊♥: an old-school Web framework with today's touch | DevNatio...
Quarkus Renarde 🦊♥: an old-school Web framework with today's touch | DevNatio...Quarkus Renarde 🦊♥: an old-school Web framework with today's touch | DevNatio...
Quarkus Renarde 🦊♥: an old-school Web framework with today's touch | DevNatio...Red Hat Developers
 
Containers without docker | DevNation Tech Talk
Containers without docker | DevNation Tech TalkContainers without docker | DevNation Tech Talk
Containers without docker | DevNation Tech TalkRed Hat Developers
 
Distributed deployment of microservices across multiple OpenShift clusters | ...
Distributed deployment of microservices across multiple OpenShift clusters | ...Distributed deployment of microservices across multiple OpenShift clusters | ...
Distributed deployment of microservices across multiple OpenShift clusters | ...Red Hat Developers
 
DevNation Workshop: Object detection with Red Hat OpenShift Data Science [Mar...
DevNation Workshop: Object detection with Red Hat OpenShift Data Science [Mar...DevNation Workshop: Object detection with Red Hat OpenShift Data Science [Mar...
DevNation Workshop: Object detection with Red Hat OpenShift Data Science [Mar...Red Hat Developers
 
Dear security, compliance, and auditing: We’re sorry. Love, DevOps | DevNatio...
Dear security, compliance, and auditing: We’re sorry. Love, DevOps | DevNatio...Dear security, compliance, and auditing: We’re sorry. Love, DevOps | DevNatio...
Dear security, compliance, and auditing: We’re sorry. Love, DevOps | DevNatio...Red Hat Developers
 
11 CLI tools every developer should know | DevNation Tech Talk
11 CLI tools every developer should know | DevNation Tech Talk11 CLI tools every developer should know | DevNation Tech Talk
11 CLI tools every developer should know | DevNation Tech TalkRed Hat Developers
 
A Microservices approach with Cassandra and Quarkus | DevNation Tech Talk
A Microservices approach with Cassandra and Quarkus | DevNation Tech TalkA Microservices approach with Cassandra and Quarkus | DevNation Tech Talk
A Microservices approach with Cassandra and Quarkus | DevNation Tech TalkRed Hat Developers
 
GitHub Actions and OpenShift: ​​Supercharging your software development loops...
GitHub Actions and OpenShift: ​​Supercharging your software development loops...GitHub Actions and OpenShift: ​​Supercharging your software development loops...
GitHub Actions and OpenShift: ​​Supercharging your software development loops...Red Hat Developers
 
To the moon and beyond with Java 17 APIs! | DevNation Tech Talk
To the moon and beyond with Java 17 APIs! | DevNation Tech TalkTo the moon and beyond with Java 17 APIs! | DevNation Tech Talk
To the moon and beyond with Java 17 APIs! | DevNation Tech TalkRed Hat Developers
 
Profile your Java apps in production on Red Hat OpenShift with Cryostat | Dev...
Profile your Java apps in production on Red Hat OpenShift with Cryostat | Dev...Profile your Java apps in production on Red Hat OpenShift with Cryostat | Dev...
Profile your Java apps in production on Red Hat OpenShift with Cryostat | Dev...Red Hat Developers
 
Kafka at the Edge: an IoT scenario with OpenShift Streams for Apache Kafka | ...
Kafka at the Edge: an IoT scenario with OpenShift Streams for Apache Kafka | ...Kafka at the Edge: an IoT scenario with OpenShift Streams for Apache Kafka | ...
Kafka at the Edge: an IoT scenario with OpenShift Streams for Apache Kafka | ...Red Hat Developers
 
Kubernetes configuration and security policies with KubeLinter | DevNation Te...
Kubernetes configuration and security policies with KubeLinter | DevNation Te...Kubernetes configuration and security policies with KubeLinter | DevNation Te...
Kubernetes configuration and security policies with KubeLinter | DevNation Te...Red Hat Developers
 
Level-up your gaming telemetry using Kafka Streams | DevNation Tech Talk
Level-up your gaming telemetry using Kafka Streams | DevNation Tech TalkLevel-up your gaming telemetry using Kafka Streams | DevNation Tech Talk
Level-up your gaming telemetry using Kafka Streams | DevNation Tech TalkRed Hat Developers
 

More from Red Hat Developers (20)

DevNation Tech Talk: Getting GitOps
DevNation Tech Talk: Getting GitOpsDevNation Tech Talk: Getting GitOps
DevNation Tech Talk: Getting GitOps
 
Exploring the power of OpenTelemetry on Kubernetes
Exploring the power of OpenTelemetry on KubernetesExploring the power of OpenTelemetry on Kubernetes
Exploring the power of OpenTelemetry on Kubernetes
 
GitHub Makeover | DevNation Tech Talk
GitHub Makeover | DevNation Tech TalkGitHub Makeover | DevNation Tech Talk
GitHub Makeover | DevNation Tech Talk
 
Quinoa: A modern Quarkus UI with no hassles | DevNation tech Talk
Quinoa: A modern Quarkus UI with no hassles | DevNation tech TalkQuinoa: A modern Quarkus UI with no hassles | DevNation tech Talk
Quinoa: A modern Quarkus UI with no hassles | DevNation tech Talk
 
Extra micrometer practices with Quarkus | DevNation Tech Talk
Extra micrometer practices with Quarkus | DevNation Tech TalkExtra micrometer practices with Quarkus | DevNation Tech Talk
Extra micrometer practices with Quarkus | DevNation Tech Talk
 
Event-driven autoscaling through KEDA and Knative Integration | DevNation Tec...
Event-driven autoscaling through KEDA and Knative Integration | DevNation Tec...Event-driven autoscaling through KEDA and Knative Integration | DevNation Tec...
Event-driven autoscaling through KEDA and Knative Integration | DevNation Tec...
 
Integrating Loom in Quarkus | DevNation Tech Talk
Integrating Loom in Quarkus | DevNation Tech TalkIntegrating Loom in Quarkus | DevNation Tech Talk
Integrating Loom in Quarkus | DevNation Tech Talk
 
Quarkus Renarde 🦊♥: an old-school Web framework with today's touch | DevNatio...
Quarkus Renarde 🦊♥: an old-school Web framework with today's touch | DevNatio...Quarkus Renarde 🦊♥: an old-school Web framework with today's touch | DevNatio...
Quarkus Renarde 🦊♥: an old-school Web framework with today's touch | DevNatio...
 
Containers without docker | DevNation Tech Talk
Containers without docker | DevNation Tech TalkContainers without docker | DevNation Tech Talk
Containers without docker | DevNation Tech Talk
 
Distributed deployment of microservices across multiple OpenShift clusters | ...
Distributed deployment of microservices across multiple OpenShift clusters | ...Distributed deployment of microservices across multiple OpenShift clusters | ...
Distributed deployment of microservices across multiple OpenShift clusters | ...
 
DevNation Workshop: Object detection with Red Hat OpenShift Data Science [Mar...
DevNation Workshop: Object detection with Red Hat OpenShift Data Science [Mar...DevNation Workshop: Object detection with Red Hat OpenShift Data Science [Mar...
DevNation Workshop: Object detection with Red Hat OpenShift Data Science [Mar...
 
Dear security, compliance, and auditing: We’re sorry. Love, DevOps | DevNatio...
Dear security, compliance, and auditing: We’re sorry. Love, DevOps | DevNatio...Dear security, compliance, and auditing: We’re sorry. Love, DevOps | DevNatio...
Dear security, compliance, and auditing: We’re sorry. Love, DevOps | DevNatio...
 
11 CLI tools every developer should know | DevNation Tech Talk
11 CLI tools every developer should know | DevNation Tech Talk11 CLI tools every developer should know | DevNation Tech Talk
11 CLI tools every developer should know | DevNation Tech Talk
 
A Microservices approach with Cassandra and Quarkus | DevNation Tech Talk
A Microservices approach with Cassandra and Quarkus | DevNation Tech TalkA Microservices approach with Cassandra and Quarkus | DevNation Tech Talk
A Microservices approach with Cassandra and Quarkus | DevNation Tech Talk
 
GitHub Actions and OpenShift: ​​Supercharging your software development loops...
GitHub Actions and OpenShift: ​​Supercharging your software development loops...GitHub Actions and OpenShift: ​​Supercharging your software development loops...
GitHub Actions and OpenShift: ​​Supercharging your software development loops...
 
To the moon and beyond with Java 17 APIs! | DevNation Tech Talk
To the moon and beyond with Java 17 APIs! | DevNation Tech TalkTo the moon and beyond with Java 17 APIs! | DevNation Tech Talk
To the moon and beyond with Java 17 APIs! | DevNation Tech Talk
 
Profile your Java apps in production on Red Hat OpenShift with Cryostat | Dev...
Profile your Java apps in production on Red Hat OpenShift with Cryostat | Dev...Profile your Java apps in production on Red Hat OpenShift with Cryostat | Dev...
Profile your Java apps in production on Red Hat OpenShift with Cryostat | Dev...
 
Kafka at the Edge: an IoT scenario with OpenShift Streams for Apache Kafka | ...
Kafka at the Edge: an IoT scenario with OpenShift Streams for Apache Kafka | ...Kafka at the Edge: an IoT scenario with OpenShift Streams for Apache Kafka | ...
Kafka at the Edge: an IoT scenario with OpenShift Streams for Apache Kafka | ...
 
Kubernetes configuration and security policies with KubeLinter | DevNation Te...
Kubernetes configuration and security policies with KubeLinter | DevNation Te...Kubernetes configuration and security policies with KubeLinter | DevNation Te...
Kubernetes configuration and security policies with KubeLinter | DevNation Te...
 
Level-up your gaming telemetry using Kafka Streams | DevNation Tech Talk
Level-up your gaming telemetry using Kafka Streams | DevNation Tech TalkLevel-up your gaming telemetry using Kafka Streams | DevNation Tech Talk
Level-up your gaming telemetry using Kafka Streams | DevNation Tech Talk
 

Recently uploaded

The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 

Recently uploaded (20)

The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 

Let's make a contract: The art of designing a Java API | DevNation Tech Talk

  • 1. Let's make a contract: the art of designing a Java API by Mario Fusco mario.fusco@gmail.com @mariofusco
  • 2. What is an API?
  • 3. What is an API?
  • 4. An API is what a developer uses to achieve some task What is an API?
  • 5. What is an API? An API is a contract between its implementors and its users
  • 6. And why should I care? We are all API designers Our software doesn't work in isolation, but becomes useful only when it interacts with other software written by other developers
  • 7. Basic Principles ● Intuitive ● Understandable ● Learnable ● Discoverable ● Consistent ● Self-defensive ● Concise ● Easy to use ● Minimal ● Orthogonal ● Idiomatic ● Flexible ● Evolvable ● Well documented ● Right level of abstraction ● Correct use of the type system ● Limited number of entry-points ● Respect the principle of least astonishment
  • 13. Convenience methods Use overloading judiciously and sparingly
  • 14. Convenience methods Use overloading judiciously and sparingly Primitives often cause methods proliferation {
  • 15. Convenience methods Use overloading judiciously and sparingly Are these all necessary? Primitives often cause methods proliferation {
  • 16. Convenience methods public interface StockOrder { void sell(String symbol, double price, int quantity); void buy(String symbol, int quantity, double price); void buy(String symbol, int quantity, double price, double commission); void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission); } What’s wrong with this?
  • 17. Convenience methods public interface StockOrder { void sell(String symbol, double price, int quantity); void buy(String symbol, int quantity, double price); void buy(String symbol, int quantity, double price, double commission); void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission); } Too many overloads What’s wrong with this?
  • 18. Convenience methods public interface StockOrder { void sell(String symbol, double price, int quantity); void buy(String symbol, int quantity, double price); void buy(String symbol, int quantity, double price, double commission); void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission); } Too many overloads Inconsistent argument order What’s wrong with this?
  • 19. Convenience methods Long arguments lists (especially of same type) public interface StockOrder { void sell(String symbol, double price, int quantity); void buy(String symbol, int quantity, double price); void buy(String symbol, int quantity, double price, double commission); void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission); } Too many overloads Inconsistent argument order What’s wrong with this?
  • 20. Convenience methods Long arguments lists (especially of same type) public interface StockOrder { void sell(String symbol, double price, int quantity); void buy(String symbol, int quantity, double price); void buy(String symbol, int quantity, double price, double commission); void buy(String symbol, int quantity, double minPrice, double maxPrice, double commission); } public interface StockOrder { void sell(String symbol, int quantity, Price price); void buy(String symbol, int quantity, Price price); } Too many overloads Inconsistent argument order What’s wrong with this? How to do better
  • 21. Consider static factories public interface Price { static Price price( double price ) { if (price < 0) return Malformed.INSTANCE; return new Fixed(price); } static Price price( double minPrice, double maxPrice ) { if (minPrice > maxPrice) return Malformed.INSTANCE; return new Range(minPrice, maxPrice); } class Fixed implements Price { private final double price; private Fixed( double price ) { this.price = price; } } class Range implements Price { private final double minPrice; private final double maxPrice; private Range( double minPrice, double maxPrice ) { this.minPrice = minPrice; this.maxPrice = maxPrice; } } enum Malformed implements Price { INSTANCE } } ➢ nicer syntax for users (no need of new keyword)
  • 22. Consider static factories public interface Price { static Price price( double price ) { if (price < 0) return Malformed.INSTANCE; return new Fixed(price); } static Price price( double minPrice, double maxPrice ) { if (minPrice > maxPrice) return Malformed.INSTANCE; return new Range(minPrice, maxPrice); } class Fixed implements Price { private final double price; private Fixed( double price ) { this.price = price; } } class Range implements Price { private final double minPrice; private final double maxPrice; private Range( double minPrice, double maxPrice ) { this.minPrice = minPrice; this.maxPrice = maxPrice; } } enum Malformed implements Price { INSTANCE } } ➢ nicer syntax for users (no need of new keyword) ➢ can return different subclasses
  • 23. Consider static factories public interface Price { static Price price( double price ) { if (price < 0) return Malformed.INSTANCE; return new Fixed(price); } static Price price( double minPrice, double maxPrice ) { if (minPrice > maxPrice) return Malformed.INSTANCE; return new Range(minPrice, maxPrice); } class Fixed implements Price { private final double price; private Fixed( double price ) { this.price = price; } } class Range implements Price { private final double minPrice; private final double maxPrice; private Range( double minPrice, double maxPrice ) { this.minPrice = minPrice; this.maxPrice = maxPrice; } } enum Malformed implements Price { INSTANCE } } ➢ nicer syntax for users (no need of new keyword) ➢ can return different subclasses ➢ can check preconditions and edge cases returning different implementations accordingly
  • 24. Promote fluent API public interface Price { Price withCommission(double commission); Price gross(); } public interface Price { void setCommission(double commission); void setGross(); }
  • 25. Promote fluent API public interface Price { Price withCommission(double commission); Price gross(); } stockOrder.buy( "IBM", 100, price(150.0).withCommission(0.7).gross() ); public interface Price { void setCommission(double commission); void setGross(); } Price price = price(150.0); price.setCommission(0.7); price.setGross(); stockOrder.buy( "IBM", 100, price );
  • 26. Promote fluent API public interface Price { Price withCommission(double commission); Price gross(); } stockOrder.buy( "IBM", 100, price(150.0).withCommission(0.7).gross() ); public interface Price { void setCommission(double commission); void setGross(); } Price price = price(150.0); price.setCommission(0.7); price.setGross(); stockOrder.buy( "IBM", 100, price ); Concatenate multiple invocations Use result directly
  • 27. Promote fluent API Streams are a very nice and convenient example of fluent API
  • 28. Promote fluent API Streams are a very nice and convenient example of fluent API
  • 29. Promote fluent API Name consistency??? Streams are a very nice and convenient example of fluent API
  • 30. Use the weakest possible type public String concatenate( ArrayList<String> strings ) { StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append( s ); } return sb.toString(); }
  • 31. Use the weakest possible type public String concatenate( ArrayList<String> strings ) { StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append( s ); } return sb.toString(); } Do I care of the actual List implementation?
  • 32. Use the weakest possible type public String concatenate( List<String> strings ) { StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append( s ); } return sb.toString(); }
  • 33. Use the weakest possible type public String concatenate( List<String> strings ) { StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append( s ); } return sb.toString(); } Do I care of the elements’ order?
  • 34. Use the weakest possible type public String concatenate( Collection<String> strings ) { StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append( s ); } return sb.toString(); }
  • 35. Use the weakest possible type public String concatenate( Collection<String> strings ) { StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append( s ); } return sb.toString(); } Do I care of the Collection’s size?
  • 36. Use the weakest possible type public String concatenate( Iterable<String> strings ) { StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append( s ); } return sb.toString(); }
  • 37. Using the weakest possible type... public String concatenate( Iterable<String> strings ) { StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append( s ); } return sb.toString(); } … enlarges the applicability of your method, avoiding to restrict your client to a particular implementation or forcing it to perform an unnecessary and potentially expensive copy operation if the input data exists in other forms
  • 38. Use the weakest possible type also for returned value public List<Address> getFamilyAddresses( Person person ) { List<Address> addresses = new ArrayList<>(); addresses.add(person.getAddress()); for (Person sibling : person.getSiblings()) { addresses.add(sibling.getAddress()); } return addresses; }
  • 39. Use the weakest possible type also for returned value public List<Address> getFamilyAddresses( Person person ) { List<Address> addresses = new ArrayList<>(); addresses.add(person.getAddress()); for (Person sibling : person.getSiblings()) { addresses.add(sibling.getAddress()); } return addresses; } Is the order of this List meaningful for client?
  • 40. Use the weakest possible type also for returned value public List<Address> getFamilyAddresses( Person person ) { List<Address> addresses = new ArrayList<>(); addresses.add(person.getAddress()); for (Person sibling : person.getSiblings()) { addresses.add(sibling.getAddress()); } return addresses; } Is the order of this List meaningful for client? … and shouldn’t we maybe return only the distinct addresses? Yeah, that will be easy let’s do this!
  • 41. Use the weakest possible type also for returned value public List<Address> getFamilyAddresses( Person person ) { Set<Address> addresses = new HashSet<>(); addresses.add(person.getAddress()); for (Person sibling : person.getSiblings()) { addresses.add(sibling.getAddress()); } return addresses; } It should be enough to change this List into a Set
  • 42. Use the weakest possible type also for returned value public List<Address> getFamilyAddresses( Person person ) { Set<Address> addresses = new HashSet<>(); addresses.add(person.getAddress()); for (Person sibling : person.getSiblings()) { addresses.add(sibling.getAddress()); } return addresses; } It should be enough to change this List into a Set But this doesn’t compile :(
  • 43. Use the weakest possible type also for returned value public List<Address> getFamilyAddresses( Person person ) { Set<Address> addresses = new HashSet<>(); addresses.add(person.getAddress()); for (Person sibling : person.getSiblings()) { addresses.add(sibling.getAddress()); } return addresses; } It should be enough to change this List into a Set But this doesn’t compile :( and I cannot change the returned type to avoid breaking backward compatibility :(((
  • 44. Use the weakest possible type also for returned value public List<Address> getFamilyAddresses( Person person ) { Set<Address> addresses = new HashSet<>(); addresses.add(person.getAddress()); for (Person sibling : person.getSiblings()) { addresses.add(sibling.getAddress()); } return new ArrayList<>( addresses ); } I’m obliged to uselessly create an expensive copy of data before returning them
  • 45. Use the weakest possible type also for returned value public Collection<Address> getFamilyAddresses( Person person ) { List<Address> addresses = new ArrayList<>(); addresses.add(person.getAddress()); for (Person sibling : person.getSiblings()) { addresses.add(sibling.getAddress()); } return addresses; } Returning a more generic type (if this is acceptable for your client) provides better flexibility in future
  • 46. Support lambdas public interface Listener { void beforeEvent(Event e); void afterEvent(Event e); } class EventProducer { public void registerListener(Listener listener) { // register listener } } public interface Listener { void beforeEvent(Event e); void afterEvent(Event e); } public interface Listener { void beforeEvent(Event e); void afterEvent(Event e); } EventProducer producer = new EventProducer(); producer.registerListener( new Listener() { @Override public void beforeEvent( Event e ) { // ignore } @Override public void afterEvent( Event e ) { System.out.println(e); } } );
  • 47. Support lambdas class EventProducer { public void registerBefore(BeforeListener before) { // register listener } public void registerAfter(AfterListener after) { // register listener } } @FunctionalInterface interface BeforeListener { void beforeEvent( Event e ); } @FunctionalInterface interface AfterListener { void afterEvent( Event e ); } EventProducer producer = new EventProducer(); producer.registerAfter( System.out::println ); Taking functional interfaces as argument of your API enables clients to use lambdas
  • 48. Support lambdas class EventProducer { public void registerBefore(Consumer<Event> before) { // register listener } public void registerAfter(Consumer<Event> after) { // register listener } } @FunctionalInterface interface BeforeListener { void beforeEvent( Event e ); } @FunctionalInterface interface AfterListener { void afterEvent( Event e ); } EventProducer producer = new EventProducer(); producer.registerAfter( System.out::println ); Taking functional interfaces as argument of your API enables clients to use lambdas In many cases you don’t need to define your own functional interfaces and use Java’s one
  • 49. Optional – the mother of all bikeshedding
  • 50. Optional – the mother of all bikeshedding Principle of least astonishment??? "If a necessary feature has a high astonishment factor, it may be necessary to redesign the feature." - Cowlishaw, M. F. (1984). "The design of the REXX language"
  • 51. Optional – the mother of all bikeshedding Principle of least astonishment??? Wrong default
  • 52. Optional – the mother of all bikeshedding Principle of least astonishment??? Wrong default This could be removed if the other was correctly implemented
  • 53. API design is an iterative process and there could be different points of view ...
  • 54. … that could be driven by the fact that different people may weigh possible use cases differently...
  • 55. … or even see use cases to which you didn’t think at all
  • 56. Also a good API has many different characteristics ...
  • 57. … and they could be conflicting so you may need to trade off one to privilege another
  • 58. What should always drive the final decision is the intent of the API … but even there it could be hard to find an agreement
  • 59. ● Write lots of tests and examples against your API ● Discuss it with colleagues and end users ● Iterates multiple times to eliminate ➢ Unclear intentions ➢ Duplicated or redundant code ➢ Leaky abstraction API design is an iterative process
  • 60. ● Write lots of tests and examples against your API ● Discuss it with colleagues and end users ● Iterates multiple times to eliminate ➢ Unclear intentions ➢ Duplicated or redundant code ➢ Leaky abstraction Practice Dogfeeding API design is an iterative process
  • 61. And that’s all what you were getting wrong :) … questions? Mario Fusco Red Hat – Principal Software Engineer mario.fusco@gmail.com twitter: @mariofusco