Presentation at thee VACE workshop (http://vaquita-workshop.org/vace2017/index.html) at ICSE 2017 (http://icse2017.gatech.edu). The paper is available at http://docentes.fct.unl.pt/jmc-cunha/publications.
Applications based on micro or web services have had significant growth due to the exponential increase in the use of mobile devices. However, using such kind of loosely coupled interfaces provides almost no guarantees to the developer in terms of evolution. Changes to service interfaces can be introduced at any moment, which may cause the system to fail due to mismatches between communicating parts.
In this paper, we present a programming model that allows the development of web service applications, server end-points and their clients, in such a way that the evolution of services’ implementation does not cause the disruption of the client. Our approach is based on a type based code slicing technique that ensures that each version only refers to type compatible code, of the same version or of a compatible version, and that each client request is redirected to the most recent type compatible version implemented by the server.
We abstract the notion of version and parametrize type compatibility on the relation between versions. The relation between versions is tagged with compatibility levels, so to capture the common conventions used in software development. Our implementation allows multiple versions of a service to be deployed simultaneously, while reusing code between versions in a type safe way. We describe a prototype framework, based on code transformation, for server-side JavaScript code, and using Flow as verification tool.
Bentham & Hooker's Classification. along with the merits and demerits of the ...
Type-Safe Evolution of Web Services
1. Type-Safe Evolution of
Web Services
João Campinhos, João Costa Seco, Jácome Cunha
NOVA LINCS, Universidade NOVA de Lisboa, Portugal
j.campinhos@campus.fct.unl.pt, joao.seco@fct.unl.pt,
jacome@fct.unl.pt
Second International Workshop on Variability and Complexity in Software Design
VACE @ ICSE 2017
27 May, 2017 - Buenos Aires, Argentina
2. Problem
• Mobile/Web apps based on micro or web services have
had significant growth (smartphones explosion)
• Client and server are loosely coupled
• Using such kind of interfaces provides almost no
guarantees to the (client) developer in terms of evolution
• Changes to service interfaces can be introduced at any
moment, causing the clients to fail
• All of us now this evolution happens all the time
2
3. An Example of a Web Service for Users - v1.0
server implementation – version 1.0
user() => { name: “John Doe” }
client implementation – version 1.0
user().name.trim()
3
4. Server Evolution
server implementation – version 2.0
user() => { name:{ first: “John”,
last: “Doe” }}
client implementation – version 1.0
user().name.trim()
4
5. Clients Need to Go Along…
server implementation – version 2.0
user() => { name:{ first: “John”,
last: "Doe" }}
client implementation – version 2.0
user().name.first + “ “ + user().name.last
5
6. Several Issues
• It is probably not feasible to update all clients
to the latest version at the same time
• It is probably not possible to keep all service
interfaces and maintain them all
• If the client moves from version A to version B,
then all the code needs to move (not
incremental)
6
7. How can we help server and client
developers cope with evolution?
?
7
9. Coexistence Principle
• Coexistence Principle: to make all the existing
versions available as a complete application, as a
unique code base
• Making use of annotations in the client requests and
in the server code to identify which version(s) to use
to attend a request
• Both versions 1.0 and 2.0 of the server should coexist
at the same time and should be usable by a client,
both at the same time
9
11. Reuse
•The coexistence of versions only makes sense if
it is possible to reuse code across versions
•We introduce a language construct that allows
the annotation of an expression e with a
version v where it should be evaluated
(version = ‘v’) => e
11
14. 14
• In this case, the type of the response in
version 2.1 is a subtype of the response
in version 2.0
• In many cases, it is still possible for
clients to interact with the new version
• This makes it possible for version 2.1 to
be used whenever version 2.0 is
requested
15. Compatibility Principle
• Compatibility Principle: a system should serve its
clients with (type) compatible versions at all times
• Our solution is to use a relation on versions that
embeds the notion of compatibility between
versions
• We introduce version patterns which define the
base version for searching the correct
implementation
15
17. An Example of a Relation
17
1.0
2.0
2.1
1.0-A
user():{name:string}
user():{name:{first: string,
last: string}}
user():{name:{first: string,
last: string},
age:int}
strictfree
subtyping
18. Compatibility Modes
•Strict: all the changes from one version to
another preserve the types of all declared
identifiers (functions and variables)
•Subtyping: all changes from one version to
another follow the subtype relation
•Free: does not constraint the changes on the
type signatures, as to allow the developer to
arbitrarily change the source code
18
19. An Example of a Relation
19
1.0
2.0
2.1
1.0-A
user():{name:string}
user():{name:{first: string,
last: string}}
user():{name:{first: string,
last: string},
age:int}
strictfree
subtyping
20. Back to the Client Code - Subtyping Mode
second client implementation – version 2.0
(version = ’2.*’) => { user().name.first }
• Client code maybe still be in version 2.0, but if
it requests the most updated version of the
service, version 2.1 will be served
20
21. Type Checker and Dispatching System
• The static type checker considers all versions
and the compatibility modes between them to
typecheck the code base
• The runtime dispatching system also takes into
consideration the relation between the
different version to serve the appropriate one
21
22. Safety Principle
•A third (and more general) principle becomes
essential to reach a sound solution
•Safety Principle: all possible entry points of
the system should be type safe, in all versions,
and considering all possible version
redirections given by the version compatibility
relation
22
23. Modularity Principle
•Modularity Principle: the static verification of
code and the dynamic dispatching of requests
and execution should be decoupled from the
actual definition of what a version is and how
versions relate
•This implies the relation is defined by the
server developer to relate any versions using
any compatibility mode
23
25. Conclusions & Future Work
•We introduced a new programming model to develop and
evolve software with multiple versions at the same time
•It copes with evolution using version compatibility modes
•Our approach is flexible as it is parametric on any version
control system developers may use
•The type system we developed can typecheck programs
with several versions at the same time
•The dispatching function dynamically decides what is the
best version of a particular component for each request
25
26. Conclusions & Future Work
•As a proof of concept we have implemented our
programming model as a prototype using the Flow
typechecker and JavaScript
•As future work, we want to formally certify the soundness
of the approach
•Also, experimental work must be performed with larger
case-studies
•We would also like to develop an IDE with this
programming model built-in
26