SlideShare une entreprise Scribd logo
1  sur  61
Télécharger pour lire hors ligne
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

Contenu connexe

Tendances

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
 

Tendances (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
 

Similaire à 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
 

Similaire à 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
 

Plus de 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
 

Plus de 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
 

Dernier

Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 

Dernier (20)

Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 

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