Towards Sound Refactoring in Erlang

6 downloads 0 Views 166KB Size Report
testing preorder by De Nicola and Hennessy [DH84]. Let A .... Ilaria Castellani and Matthew Hennessy. Testing ... Rocco De Nicola and Matthew C. B. Hennessy.
Towards Sound Refactoring in Erlang Erica Tanti

Adrian Francalanza

Department of Computer Science Faculty of ICT University of Malta Email: [email protected]

Department of Computer Science Faculty of ICT University of Malta Email: [email protected]

Abstract—Erlang is an actor-based programming language used extensively for building concurrent, reactive systems that are highly available and suffer minimum downtime. Such systems are often mission critical, making system correctness vital. Refactoring is code restructuring that improves the code but does not change behaviour. However automated refactoring tools do not guarantee program behaviour is preserved i.e., the refactoring is correct. In this work we strive towards a solution for this problem. We study a testing preorder, limiting our study to safety testing suites, i.e., suites of tests ensuring that nothing bad happens. A refactoring tool would be considered safe if the refactored code passes all the same tests as before refactoring. Unfortunately this reasoning is impractical, as one cannot run the set of all possible tests in a finite amount of time. We therefore investigate an alternative theory that facilitates reasoning about our testing preorder. The technical development does not follow directly from previous work as certain characteristics pertaining to actor systems complicate the development of our alternative preorder.

I.

I NTRODUCTION

The growth of multicore, and even more recently manycore, computer processors has made concurrency a crucial consideration for developers. Taking advantage of the potential speedup which can be achieved using multicore computers is one of the main driving forces for concurrency. Additionally, concurrent programs benefit from improved responsiveness by performing work asynchronously, thus enabling better humancomputer interaction. However concurrent programs are nondeterministic, thus executing the same program may produce different results. It is up to the developer to ensure program safety, that is data consistency, and liveness, that is computation progress [Var13]. Programming in a concurrent manner requires developers to think in a way humans find difficult and there are currently few tools which facilitate the introduction of parallelism in programs. Thus parallelism is not widely found in mainstream applications and most languages. There exist a number of concurrency models which allow developers to program in a concurrent manner. The actor model is a powerful abstraction which provides an alternative to the currently predominant shared memory concurrency model. Actors are suitable for structuring highly concurrent software systems which scale up to many-core processors, as well as scale out to clusters and the cloud. This has lead to a steady stream of research and industrial development, contributing to a renewed interest in actors in academia [KSA09], [Hal12], [SL05]. Examples of programming languages which have adopted the actor model include E RLANG and Scala. There also exist a number of actor frameworks such as Akka

which run on the Java Virtual Machine (JVM) with APIs available for both Java and Scala [Hal12] or Microsoft’s Asynchronous Agents Library for .NET [KSA09]. In this work we have chosen to focus on E RLANG [Arm07], [CT09] as it is one of the most mature actor languages (since 2000 [Arm10]). Apart from concurrency models there also has been recent (2012) work investigating the potential use of refactoring tools to transform single threaded code into parallel code without much additional effort on the developer’s behalf [BHDK12], [BHD13]. Program refactoring is the process of modifying a software system in such a way that does not alter the external functionality or behaviour of the code while, at the same time, improving its internal structure. Examples of such improvements include improved readability, such as through compliance with certain code practices, improved efficiency, reusability, extensibility or maintainability [MT04]. The use of automated refactoring tools is generally faster and less likely to introduce mistakes than refactoring manually [MHPB09]. However, currently most of the refactorings provided by existing refactoring tools are simple, as this is the only way to ensure behaviour is preserved. This means that such refactoring tools (such as Tidier [SA09]) can only perform a limited scope of refactorings. Tools permitting more complex refactorings (such as Wrangler [LTOT08]) use side-conditions or assertions to attempt to ascertain whether a refactoring is valid, but does not guarantee behaviour preservation. To mitigate the problem such tools are often semi-automatic, thus necessitating some human interaction, and support an undo mechanism which Mens and Tourw´e [MT04] state is required when a tool cannot guarantee behaviour preservation. In safety-critical software, where correctness is of utmost importance, undoing a refactoring when a bug is found, and thus when the damage may already have been done, is not satisfactory. The expense of introducing a bug, even for a short time, outweighs the possible benefits of refactoring. This problem could potentially be avoided if there was a way to truly ensure that behaviour has been preserved. This paper first gives an in-depth background on language formalisations and behavioural preorders which are used to verify the correctness of refactorings in Section II. We then outline the main aims of the work currently in progress in Section III. The paper closes in Section IV with conclusions and a summary of related work.

II.

AkT

BACKGROUND

In this section we first discuss the main features of actor and E RLANG languages which in our work is then used to develop a formalisation for the language. We then describe how a test-based preorder may be used to compare the behaviour of two programs and the development of an alternative preorder which uses traces instead of tests. ω

A. Formalisation of the Actor-Based E RLANG Language In this work we aim to ensure behaviour is preserved through the development of formal proofs. To be able to develop a behavioural proof system we first define a language formalisation for (a subset of) the actor-based language E R LANG , which we do using a Labelled Transition System (LTS). In this section we define the core actor concepts and briefly discuss E RLANG. The term actor was originally coined by Hewitt in 1971 [Hew71]. This lead to a string of research papers by Hewitt and a number of other researchers. A short overview of early research on actors may be found in [AMST98]. Much work on actor systems today builds on the work by Agha [Agh86]. Agha continued to develop this work into a concurrent objectbased model in later works. In essence, an actor configuration is a collection of uniquely-named, concurrent actors and messages en route. Messages sent are adressed to a specific actor and can only be read by the intended receiver. Actors (or processes) have three primary components: a unique process identifier, an execution thread denoted by an expression and a queue of buffered messages known as a mailbox [KA11]. Actor behaviour is functional in nature, similar to that of lambda calculus. The original formalisation by Agha [Agh86] also includes the following three actor primitaves: •

letactor, which allows an actor to create other actors,



send, allowing actors to communicate via the sending of messages, and



become, wherein an actor replaces its current behaviour with new behaviour.

E RLANG is described as a “functional, strict, dynamically typed, pattern matching, higher order and concurrent” language in the specification for C ORE E RLANG, the official intermediate representation of E RLANG code [Car01]. Concurrency in E RLANG is based on the actor model, namely Agha’s work [Arm10], as discussed above. One notable difference is that instead of the become primitive is refined as the patternmatching receive primitive. The receive primitive attempts to match the contents of the mailbox with one of the patterns defined. The actor then assumes one of the defined behaviours, depending on which pattern was matched, or blocks and waits for more messages to arrive if no pattern is matched. B. Test-Based Behavioural Preorders Using the actor-based E RLANG formalisation we then define a behavioural preorder which may be used to prove the correctness of a refactoring. The preorder is of the form: A@ ∼ test B, where A and B are formalised E RLANG programs

ω

Fig. 1. Depicting how non-determinism results in multiple interleavings of A k T , where some interleavings result in ω being output and some do not.

It allows us to formally prove that A may be refactored to B without modifying the behaviour of the program. In E RLANG there is no accepted notion of a logic which specifies correctness. Instead developers generally write tests or use test generation tools such as QuviQ QuickCheck [Hug07] and PropEr [PS11] to determine correctness, where correctness is defined as a program passing a set of tests. Thus in this thesis we use a similar definition of correctness, based on the testing preorder by De Nicola and Hennessy [DH84]. Let A be the program before refactoring and B, the program after refactoring. We say that a refactoring is correct if when A passes a set of tests, then B will also pass these tests. By generalising the set of tests to all possible tests this may be reformulated as:   A@ ∼ test B iff for all T. A passes T implies B passes T A passes T implies an experiment set-up of the form A k T . This denotes a test, T , which is run in parallel with the system under test, A. A test is just a normal program (actor system) which additionally can output a special event ω. The test and system under tests interact and sometimes this results in the special action ω being output. However, due to nondeterminism, running the test may lead to multiple outcomes due to different program interleavings. Thus it does not suffice to say a test, when run, outputs an action ω, as for the same A and T the test may sometimes output ω and sometimes not, as shown in Figure 1. We limit our study to safety tests, where: •

The special action ω is used to denote when something bad happens.



For a test to be successful the special action ω never occurs, for all possible test runs.

This test-based preorder is a useful starting point as it easily allows us to determine that two programs are not related by the test-based preorder. Determining that two programs are not related by the preorder is proved by counter example, i.e., by finding one test which A passes but B fails. However, as noted by [CH98], [BDP02], the test-based preorder is hard to use to determine that A @ ∼ test B, since the preorder universally quantifies over all tests. This means that to prove A @ ∼ test B we must check the condition holds for all possible tests, which are infinite in number. This cannot be achieved in a finite amount of time.

familiar with the may testing preorder will note that it is the inverse of the safety testing preorder [KH11] the development of the alternative characterisation is similar. Despite this, in our case the development of an alternative characterisation was particularly challenging due to certain characteristics of E RLANG. Briefly, these are asynchrony, which resulted in weakening which traces are equated, persistence, thus finite actor systems still had infinite traces and the single receiver property, which complicated the completeness proof.

A coin1 A1 coin2 A2 tea

coffee

A4 Fig. 2.

A3

Vending Machine Automaton [Nic11]

After developing an alternative characterisation it is required that this characterisation is proven to correspond to the test-based preorder. In practical terms this means that we must prove that the two preorders return the same results. To prove correspondence we must prove that the alternative preorder, @ ∼ trace , is both sound and complete with respect to the test-based preorder @ ∼ test . Consider the case where we @ know that A @ ∼ trace B holds. The alternative preorder ∼ trace is sound if we can prove that when A @ B holds we can ∼ trace also guarantee that no safety test is ever broken. That is for soundness we prove:

C. Alternative Trace-Based Preorder In such cases previous works provide an alternative reasoning technique that does not quantify over all possible tests. Our alternative preorder uses traces instead of tests, and is written as follows: A@ ∼ trace B, where A and B are formalised E RLANG programs A trace, s, describes a series of input and output interactions between an actor system and the external environment. As an actor system may accept more than one input and may also be non-deterministic, an actor system may be able to perform more than one trace. Thus for the vending machine depicted in Figure 2, some of the possible traces include  (no interactions), coin1 (input one coin then stop interacting with the system) and coin1 . coin2 . coffee (continue interacting with the system until your coffee is obtained). The alternative characterisation for the test-based preorder based on traces has the following general format:   A@ ∼ trace B iff for all s. B produces s implies A produces s A trace-based preorder is simpler to reason about because: •

interactions with a number of tests may be described using a single trace;



traces are somehow connected to the capabilities of the programs A and B being analysed, whereas tests may not be. III.

A IMS OF T HIS W ORK

In this work our first aim was to develop a formal calculus for our subset of the actor-based E RLANG language. This could then be used to formalise notion of the safety testing preorder for our calculus. As discussed, this formalisation is difficult to use in practice as it is universally quantified. Thus we then aim to define an alternative preorder for the test-based preorder. Substantial work on alternative characterisations for the may testing preorder already exists [BDP02], [Tha03]. Readers

@ A@ ∼ trace B implies A ∼ test B

Conversely, consider the case where A @ ∼ test B holds. The alternative characterisation is complete if using the trace-based preorder this refactoring is also identified as valid. Therefore all valid refactorings are identified as such by the trace-based preorder. Thus for completeness we prove @ A@ ∼ test B implies A ∼ trace B

IV.

C ONCLUSIONS AND R ELATED WORK

In this paper we give an overview of our study of the safety testing preorder for the E RLANG language, as applied to refactoring. We then outlined the problems with a testbased preorder and our ongoing development of an alternative characterisation which is not universally quantified and may be proved to correspond to the test-based preorder. Related work in the area is mainly divided into those studying formalisations for actor-like and E RLANG languages and those studying behavioural preorders. There is a body of work that attempts to formalise various aspects of the current E RLANG implementation [Fre01], [CS05], [SF07], [SFE10]. There are also a number of works formalising actor-like languages similar to ours [GZ99], [GZ00], [Cra12]. However none of these study testing preorders. Testing preorders were first developed by De Nicola and Hennessy [DH84]. Asynchronous variants were developed then first by Castellani and Hennessy [CH98] and later by Boreale et al. [BDP02] and Thati [Tha03]. The aim of Thati’s [Tha03] work is perhaps the closest to ours, since he develops a may testing preorder for an actor calculus and then attempts to develop an alternative characterisation for the preorder. However the language used is essentially a variant of asynchronous πcalculus with a type system enforcing discipline on the use of names. This means he forgoes actor features such as mailboxes and the become primitive is reduced to an input (without pattern matching).

ACKNOWLEDGEMENT The degree was carried out following the award of a STEPS scholarship which is part-financed by the European Union — European Social Fund (ESF) under Operational Programme II — Cohesion Policy 2007-2013, “Empowering People for More Jobs and a Better Quality of Life”. R EFERENCES [Agh86] [AMST98]

[Arm07] [Arm10] [BDP02]

[BHD13]

[BHDK12]

[Car01] [CH98] [Cra12] [CS05]

[CT09] [DH84]

[Fre01]

[GZ99]

[GZ00]

[Hal12]

[Hew71]

Gul Agha. Actors: A Model of Concurrent Computation in Distributed Systems. MIT Press, Cambridge, MA, USA, 1986. Gul Agha, Ian A. Mason, Scott F. Smith, and Carolyn L. Talcott. A foundation for actor computation. Journal of Functional Programming, 7:1–72, 1998. Joe Armstrong. Programming Erlang - Software for a Concurrent World. The Pragmatic Bookshelf, 2007. Joe Armstrong. Erlang. Commun. ACM, 53(9):68–75, September 2010. Michele Boreale, Rocco De Nicola, and Rosario Pugliese. Trace and Testing Equivalence on Asynchronous Processes. Information and Computation, 172(2):139–164, January 2002. Christopher Brown, Kevin Hammond, Marco Danelutto, Peter Kilpatrick, Holger Sch¨oner, and Tino Breddin. Paraphrasing: Generating parallel programs using refactoring. In Bernhard Beckert, Ferruccio Damiani, Frank S. Boer, and Marcello M. Bonsangue, editors, Formal Methods for Components and Objects, volume 7542 of Lecture Notes in Computer Science, pages 237–256. Springer Berlin Heidelberg, 2013. Christopher Brown, Kevin Hammond, Marco Danelutto, and Peter Kilpatrick. A language-independent parallel refactoring framework. In Proceedings of the Fifth Workshop on Refactoring Tools, WRT ’12, pages 54–58, New York, NY, USA, 2012. ACM. Richard Carlsson. An introduction to core erlang. In PLI01 (Erlang Workshop), 2001. Ilaria Castellani and Matthew Hennessy. Testing theories for asynchronous languages. In FSTTCS, pages 90–101, 1998. Silvia Crafa. Behavioural types for actor systems. CoRR, abs/1206.1687, 2012. Koen Claessen and Hans Svensson. A semantics for distributed Erlang. Proceedings of the 2005 ACM SIGPLAN workshop on Erlang - ERLANG ’05, page 78, 2005. Francesco Cesarini and Simon Thompson. ERLANG Programming. O’Reilly, 2009. Rocco De Nicola and Matthew C. B. Hennessy. Testing equivalences for processes. Theoretical Computer Science, 34(1-2):83– 133, 1984. ˚ Lars-Ake Fredlund. A Framework for Reasoning about Erlang Code. PhD thesis, Royal Institute of Technology, Stockholm, Sweden, 2001. Mauro Gaspari and Gianluigi Zavattaro. An algebra of actors. In Paolo Ciancarini, Alessandro Fantechi, and Robert Gorrieri, editors, Formal Methods for Open Object-Based Distributed Systems, volume 10 of IFIP - The International Federation for Information Processing, pages 3–18. Springer US, 1999. Mauro Gaspari and Gianluigi Zavattaro. An actor algebra for specifying distributed systems: the hurried philosophers case study. In Concurrent Object-Oriented Programming and Petri Nets, Lecture Notes in Computer Science, pages 428–444. Springer-Verlag, 2000. Philipp Haller. On the integration of the actor model in mainstream technologies: The scala perspective. In Proceedings of the 2Nd Edition on Programming Systems, Languages and Applications Based on Actors, Agents, and Decentralized Control Abstractions, AGERE! ’12, pages 1–6, New York, NY, USA, 2012. ACM. Carl Hewitt. Description and Theoretical Analysis (Using Schemata) of PLANNER: A Language for Proving Theorems and Manipulating Models in a Robot. PhD thesis, MIT, 1971.

[Hug07]

John Hughes. Quickcheck testing for fun and profit. In Proceedings of the 9th international conference on Practical Aspects of Declarative Languages, PADL’07, pages 1–32, Berlin, Heidelberg, 2007. Springer-Verlag. [KA11] Rajesh K. Karmani and Gul Agha. Actors. In Encyclopedia of Parallel Computing, pages 1–11. 2011. [KH11] Vasileios Koutavas and Matthew Hennessy. A testing theory for a higher-order cryptographic language. In Gilles Barthe, editor, Programming Languages and Systems, volume 6602 of Lecture Notes in Computer Science, pages 358–377. Springer Berlin Heidelberg, 2011. [KSA09] Rajesh K. Karmani, Amin Shali, and Gul Agha. Actor frameworks for the jvm platform: A comparative analysis. In Proceedings of the 7th International Conference on Principles and Practice of Programming in Java, PPPJ ’09, pages 11–20, New York, NY, USA, 2009. ACM. [LTOT08] Huiqing Li, Simon Thompson, Gy¨orgy Orosz, and Melinda T´oth. Refactoring with wrangler, updated: data and process refactorings, and integration with eclipse. Proceedings of the 7th ACM SIGPLAN workshop on ERLANG, 2008. [MHPB09] Emerson Murphy-Hill, Chris Parnin, and Andrew P. Black. How we refactor, and how we know it. In Proceedings of the 31st International Conference on Software Engineering, ICSE ’09, pages 287–297, Washington, DC, USA, 2009. IEEE Computer Society. [MT04] Tom Mens and Tom Tourw´e. A survey of software refactoring. Software Engineering, IEEE Transactions on, 30(2):126–139, 2004. [Nic11] Rocco De Nicola. Behavioral Equivalences. In David Padua, editor, Encyclopedia of Parallel Computing, pages 120–127. Springer US, 2011. [PS11] Manolis Papadakis and Konstantinos Sagonas. A PropEr integration of types and function specifications with property-based testing. In Proceedings of the 2011 ACM SIGPLAN Erlang Workshop, pages 39–50, New York, NY, September 2011. ACM Press. [SA09] Konstantinos Sagonas and Thanassis Avgerinos. Automatic refactoring of Erlang programs. Proceedings of the 11th ACM SIGPLAN conference on Principles and practice of declarative programming - PPDP ’09, page 13, 2009. ˚ ke Fredlund. A more accurate [SF07] Hans Svensson and Lars-A semantics for distributed erlang. Proceedings of the 2007 SIGPLAN workshop on Erlang Workshop - Erlang ’07, page 43, 2007. ˚ ke Fredlund, and Clara Benac Earle. A [SFE10] Hans Svensson, Lars-A unified semantics for future Erlang. In Proceedings of the 9th ACM SIGPLAN workshop on Erlang, pages 23–32. ACM, 2010. [SL05] Herb Sutter and James Larus. Software and the concurrency revolution. Queue, 3(7):54–62, September 2005. [Tha03] Prasannaa Thati. A Theory Of Testing For Asynchronous Concurrent Systems. PhD thesis, 2003. [Var13] Carlos A. Varela. Programming Distributed Computing Systems: A Foundational Approach. MIT Press, May 2013.