-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.tex
1256 lines (896 loc) · 116 KB
/
main.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\documentclass[a4paper]{article}
\usepackage{preamble}
\begin{document}
% CREATED BY DAVID FRISK, 2015
% COVER PAGE
\begin{titlepage}
\newgeometry{top=3cm, bottom=3cm,
left=2.25 cm, right=2.25cm} % Temporarily change margins
\pagenumbering{roman}
% Cover page background
%\AddToShipoutPicture*{\backgroundpic{-4}{56.7}{figure/frontpage_eng.png}}
\AddToShipoutPicture*{\backgroundpic{-80}{800}{figure/AvancezChalmersU_black_right.eps}}
\addtolength{\voffset}{2cm}
\vspace*{-1.75cm}
\rule{\linewidth}{1pt}
% Cover picture (replace with your own or delete)
%\begin{figure}[H]
%\centering
%\vspace{2cm} % Adjust vertical spacing here
%\includegraphics[width=0.9\linewidth]{title.png}
%\end{figure}
% Cover text
\mbox{}
\vfill
\renewcommand{\familydefault}{\sfdefault} \normalfont % Set cover page font
\textbf{{\huge Evaluating Haste.App: Haskell in a web setting}} \\[0.5cm]
{\Large Effects of using a seamless, linear, client-centric programming model}\\[0.5cm]
Bachelor Science Thesis in Computer Science and Engineering \setlength{\parskip}{1cm}
{\Large \textsc{Benjamin Block}} \setlength{\parskip}{2.9cm}\\
{\Large \textsc{Joel Gustafsson}} \setlength{\parskip}{2.9cm}\\
{\Large \textsc{Michael Milakovic}} \setlength{\parskip}{2.9cm}\\
{\Large \textsc{Mattias Nilsen}} \setlength{\parskip}{2.9cm}\\
{\Large \textsc{André Samuelsson}} \setlength{\parskip}{2.9cm}
\vfill
\vspace*{-1.75cm}
\rule{\linewidth}{1pt}
Department of Computer Science and Engineering \\
\textsc{Chalmers University of Technology} \\
%\textsc{University of Gothenburg} \\
Gothenburg, Sweden, June 2016
\renewcommand{\familydefault}{\rmdefault} \normalfont % Reset standard font
\end{titlepage}
\restoregeometry
% TITLE PAGE
\newpage\null\thispagestyle{empty}\newpage
\newpage
\thispagestyle{empty}
\begin{center}
\textsc{\large Bachelor of science thesis}\\[4cm]
% Report number given by department
\textbf{\Large Evaluating Haste.App: Haskell in a web setting} \\[1cm]
{\large Effects of using a seamless, linear, client-centric programming model}\\[1cm]
{\Large \textsc{Benjamin Block}} \setlength{\parskip}{2.9cm}\\
{\Large \textsc{Joel Gustafsson}} \setlength{\parskip}{2.9cm}\\
{\Large \textsc{Michael Milakovic}} \setlength{\parskip}{2.9cm}\\
{\Large \textsc{Mattias Nilsen}} \setlength{\parskip}{2.9cm}\\
{\Large \textsc{André Samuelsson}} \setlength{\parskip}{2.9cm}
\vfill
% Logotype on titlepage
\begin{figure}[H]
\centering
% Remove the following line to remove the titlepage logotype
\includegraphics[width=0.2\pdfpagewidth]{figure/logo_eng.pdf} \\
\end{figure} \vspace{5mm}
Department of Computer Science and Engineering \\
\textsc{Chalmers University of Technology} \\
%\textsc{University of Gothenburg} \\
Gothenburg, Sweden, June 2016 \\
\end{center}
% IMPRINT PAGE (BACK OF TITLE PAGE)
\newpage
\thispagestyle{plain}
%\vspace*{4.5cm}
\textbf{Evaluating Haste.App: Haskell in a web setting}\\
Effects of using a seamless, linear, client-centric programming model\\
{ \textsc{Benjamin Block}} \setlength{\parskip}{2.9cm}\\
{ \textsc{Joel Gustafsson}} \setlength{\parskip}{2.9cm}\\
{ \textsc{Michael Milakovic}} \setlength{\parskip}{2.9cm}\\
{ \textsc{Mattias Nilsen}} \setlength{\parskip}{2.9cm}\\
{ \textsc{André Samuelsson}} \setlength{\parskip}{2.9cm}
\copyright ~ Benjamin Block, 2016. \setlength{\parskip}{1cm}\\
\copyright ~ Joel Gustafsson, 2016. \setlength{\parskip}{1cm}\\
\copyright ~ Michael Milakovic, 2016. \setlength{\parskip}{1cm}\\
\copyright ~ Mattias Nilsen, 2016. \setlength{\parskip}{1cm}\\
\copyright ~ André Samuelsson, 2016. \setlength{\parskip}{1cm}
Supervisor: Emil Axelsson\\
Examiner: Niklas Broberg, Department of Computer Science and Engineering\setlength{\parskip}{1cm}
Chalmers University of Technology\\
%University of Gothenburg\\
Department of Computer Science and Engineering\\
SE-412 96 Gothenburg\\
Sweden\\
Telephone +46 31 772 1000 \setlength{\parskip}{0.5cm}
\vfill
The Authors grants to Chalmers University of Technology the non-exclusive right to publish the Work electronically and in a non-commercial purpose make it accessible on the Internet. The Author warrants that he/she is the author to the Work, and warrants that the Work does not contain text, pictures or other material that violates copyright law.
The Author shall, when transferring the rights of the Work to a third party (for example a publisher or a company), acknowledge the third party about this agreement. If the Author has signed a copyright agreement with a third party regarding the Work, the Author warrants hereby that he/she has obtained any necessary permission from this third party to let Chalmers University of Technology store the Work electronically and make it accessible on the Internet.
\vfill
% Caption for cover page figure if used, possibly with reference to further information in the report
%Cover: Wind visualization constructed in Matlab showing a surface of constant wind speed along with streamlines of the flow. \setlength{\parskip}{0.5cm}
Department of Computer Science and Engineering\\
Gothenburg, Sweden 2016
\normalsize
%\pagenumbering{gobble}
\vfill
\newpage
% CREATED BY DAVID FRISK, 2015
{\Large \textbf{Evaluating Haste.App: Haskell in a web setting}}\\
{\Large Effects of using a seamless, linear, client-centric programming model}\\
\\
{ \textsc{Benjamin Block}} \setlength{\parskip}{2.9cm}\\
{ \textsc{Joel Gustafsson}} \setlength{\parskip}{2.9cm}\\
{ \textsc{Michael Milakovic}} \setlength{\parskip}{2.9cm}\\
{ \textsc{Mattias Nilsen}} \setlength{\parskip}{2.9cm}\\
{ \textsc{André Samuelsson}} \setlength{\parskip}{2.9cm}\\
\textit{
Department of Computer Science and Engineering\\
Chalmers University of Technology \setlength{\parskip}{0.5cm} \\
%University of Gothenburg
\setlength{\parskip}{0cm}}\\\\
Bachelor of Science Thesis
\thispagestyle{plain} % Supress header
\setlength{\parskip}{1em}
\section*{Preface}
We would like to thank our supervisor Emil Axelsson for his invaluable support and guidance during this project. We would also like to thank Anton Ekblad, the primary developer of Haste and Haste.App, for answering our questions throughout the work.
\section*{Abstract}
In this paper, we evaluate Haste.App, a newly developed Haskell library for distributed web applications. Haste.App promises to deliver multiple ease of use factors in addition to allowing the static type checking of Haskell to be extended over the network. It also pairs with the Haste compiler which compiles Haskell code to JavaScript. We conclude that Haste.App is a promising library that allows real world distributed web applications to be written in Haskell with ease. The seamless, client-centric programming model also has positive effects on programmer productivity. There are, however, some issues that will need to be addressed with Haste.App: some way of making sure the JavaScript is updated when the server is, standardisation when it comes to project structure, and some convenient way of handling DOM. In order to reach this conclusion, we evaluate Haste.App primarily based on three key aspects: performance, stability, and programmer productivity. The evaluation is performed by creating a simple online multiplayer board game and an attached lobby system.
\vfill
\textbf{Keywords}:
Haskell, Haste.App, Haste, functional programming, web development.
\newpage
\section*{Sammandrag}
I denna rapport utvärderar vi det nyutvecklade Haskellbiblioteket Haste.App, som syftar till att underlätta implementeringen av distribuerade webbapplikationer. Haste.App gör det möjligt att utöka Haskells statiska typkontroll över nätverkskommunikation samt ger programmeraren tillgång till ett antal bekvämlighetsfaktorer. Utöver det, levereras Haste.App tillsammans med Haskell till JavaScript kompilatorn Haste. Vi kommer fram till att Haste.App är ett lovande bibliotek som enkelt tillåter webbapplikationer att skrivas i Haskell. Den sömlösa, klientcentrerade programmeringsmodellen som Haste.App erbjuder har också positiva effekter på programmerares produktivitet. Däremot finns det ett fåtal problem som behöver ses över: den kompilerade Javscript-koden måste bli uppdaterad när servern blir uppdaterad, det behövs standarder för struktur på projekt i Haste.App, samt ett mer effektivt sätt att hantera DOM-manipulation. Vi nådde denna slutsats genom att undersöka Haste.App ur tre synvinklar: prestanda, stabilitet samt programmerares produktivitet. Denna undersökning genomförs genom att implementera ett enkelt brädspel för flera spelare som en webbapplikation med ett tillhörande lobbysystem.
\vfill
\textbf{Nyckelord}:
Haskell, Haste.App, Haste, funktionell programmering, webbutveckling.
\newpage
\tableofcontents
\newpage
\glsaddall
\setglossarystyle{super}
\printnoidxglossary
\newpage
\pagenumbering{arabic}
\section{Introduction}
Haste.App is a new Haskell library for writing seamless client-server applications. The library addresses some of the prevailing issues with traditional web development. It allows the programmer to write a client-server application in a single file and extends type checking over the network. There are a lot of promising advantages with Haste.App and utilising functional programming when developing web applications.
\subsection{Background}
Writing interactive web applications typically involves JavaScript for a significant portion of the client-side code. The prevalence of JavaScript stems from the fact that it is supported by all significant web browsers and virtually all websites use some form of JavaScript \cite{flanagan2011javascript}. Because JavaScript is popular, it has a large community supporting it and a large number of libraries. Haskell, on the other hand, is not as popular as JavaScript but it has other benefits, such as its advanced type system. Other advantages include the ability to perform equational reasoning on the code \cite{gibbons2011just} and a powerful testing library called QuickCheck \cite{Claessen:2011:QLT:1988042.1988046}.
Haste is a Haskell to JavaScript compiler. It makes it possible to use the advantages of a pure functional language in a web setting. Haste is based on the Glasgow Haskell Compiler, and its primary aim is to produce compact JavaScript code \cite{a-distributed-haskell-for-the-modern-web}.
Haste is bundled with the library Haste.App which allows both the client- and server-side code to be written in one program \cite{ekblad2015seamless}. The library takes care of the network communication, alleviating the programmer from writing it explicitly. As such, the programmer is relieved from this tedious and error-prone task. Moreover, Haste.App is pursuing a client-centric programming model, which means that the programmer writes the code from the client's perspective \cite{a-distributed-haskell-for-the-modern-web}. At the time of writing this thesis, Haste.App is still very new and requires more testing and investigation.
\subsection{Purpose}
\label{sec:purpose}
The purpose of this paper is to evaluate the advantages and disadvantages of writing client-server applications using the library Haste.App, with all of the properties of using a pure functional language. The language used is Haskell and Haste.App is an extension of the Haskell to JavaScript compiler Haste. Firstly, it is investigated whether or not there is any effect on performance, secondly, if there are any benefits regarding the stability of the application, and thirdly, if there are any advantages in regard to programmer productivity. An additional purpose of the project is to supply comments and feedback on Haste and Haste.App back to the developer, who is a Ph.D. student at Chalmers University of Technology.
\subsection{Limitations}
\label{sec:limitations}
The work does not assess demanding real-time applications and graphics with Haste.App since the focus of the project is mainly to evaluate the suitability of using Haste.App and Haskell to program for the web. Neither is a second application created using a more traditional library, for purposes of comparison. Furthermore, the usability \cite{usability} of programming in Haste.App is only considered on one point, namely by programmer productivity which is what is called efficiency in usability terms, the other parts are out of scope for this work.
%\subsection{Related research}
%\todo{Remove.}
%There are two ways to view related research regarding this project. The first being a greater overview of functional research, particularly applied functional programming which Chalmers University of Technology is heavily pursuing. The research done in this thesis is another example of functional programming applied to an area where it is not so commonly used today, namely web development.
%The other view is research directly related to the work of this thesis. This thesis is related to the work of Anton Ekblad, who is the main developer of the Haste compiler and its accompanying libraries. In his licentiate thesis, "A Distributed Haskell for the Modern Web", he describes the implementation of Haste.App and its potential benefits \cite{a-distributed-haskell-for-the-modern-web}.
%Regarding general language $X$ to JavaScript compilers, there is also much research. Many programming languages have a JavaScript compiler; an example is ClojureScript which is a Clojure to JavaScript compiler \cite{clojure-ieee}.
\newpage
\section{Problem description}
\label{sec:problem}
The purpose of this paper is analysed by splitting it into several smaller parts. These deal with different aspects of writing client-server applications with the help of Haste.App. As mentioned in \cref{sec:purpose} the purpose can be split into effects on performance, stability and programmer productivity. These are, however, also large and hard to analyse without further breaking them into even smaller parts.
\subsection{Performance description}
\label{sub:performance-description}
Performance is a crucial aspect when writing client-server applications, and therefore a crucial aspect when assessing Haste.App. On the server-side, the application created with Haste.App can not be too demanding regarding system resources. This is important both because it is often desirable to have as inexpensive servers as possible (while maintaining enough performance), and because it allows more clients to be connected to the server. On the client-side, the application and code generated by Haste need to be efficient for the user's computer to run smoothly and to not experience any delays from performance issues. As such it is important that there is not a significant discrepancy between using Haste.App and a more traditional client-server approach.
There could be several reasons for a significant divergence: firstly, on the client-side, the Haste compiler might generate JavaScript that is slower than equivalent JavaScript written directly in the language. Secondly, the server part of an application written in Haste.App must not be considerably slower than writing an application using a different library.
\subsection{Stability description}
On a language level, Haskell brings many benefits to the stability of an application, as it is a strongly typed static language. The static type checking verifies type correctness at compile time which allows bugs which are trivial but hard to find to be tracked down more easily. Another important benefit the type system in Haskell brings is that it allows for pure logic to be separated from its impure counterparts. This type system brings a benefit by allowing the use of tools like QuickCheck to test the pure logic of the application \cite{Claessen:2011:QLT:1988042.1988046}. Haste.App also extends the static type checking over the network through its remote procedure calls (RPC), which might remove confusing network errors.
The programmer can use these benefits when writing code for Haste.App. Stability is thus investigated in order to see if the advantages Haskell brings, in terms of program correctness, is of any practical use when writing client-server applications.
Besides language level correctness, the stability of the Haste compiler needs to be taken into account. Particularly the Haste.App module, which this project primarily focuses on, has to be evaluated to detect any errors. While these errors might decrease the stability of the application, they are not the fault of the program itself. This is where giving feedback on Haste and Haste.App becomes important as it allows bugs to be tracked down and fixed.
\subsection{Programmer productivity description}
\label{sec:programmer_productivity}
Traditional client-server applications, in contrast to Haste.App, force the programmer to write two separate applications and the communication between them. Writing two applications can be an error-prone and tedious task as it forces the programmer to make sure the type of the data sent between the client and server match. Moreover, the arbitrary communication pattern can make the program flow confusing and difficult to grasp as well as introduce errors. In this traditional model, both the server and client can drive the program flow, something that also serves to make the program flow unpredictable. These are all problems when considering programmer productivity.
Haste.App tries to counter these issues in a number of ways. Most importantly it allows the programmer to write both the client code and the server code in the same file and makes use of Haskell's strong and static type checking to handle the communication. It also lets the client be the only driving force in the application and uses a synchronous, linear programming model \cite{ekblad2015seamless}. Furthermore, Haskell has been shown to have some ease-of-use aspects compared to imperative languages, such as not having to consider statement sequence, \cite{mathematical-comparison-haskell-c++}. These ease-of-use aspects may influence programmer productivity.
\newpage
\section{Technical background}
Developing a web application using Haskell and Haste.App requires the use of a number of technical tools, languages, and standards. What follows is a description of these tools, languages, and standards.
\subsection{Haskell}
Haskell is a pure functional language with static typing and lazy evaluation. In a pure functional language it is possible to separate functions with side-effects, such as writing to file or user input, from functions which only depend on the parameters given to that function. Moreover, Haskell is a statically typed language and offers compact syntax.
Handling side effects, or more generally computational contexts, is done by using monads. For programmers unfamiliar with the concept, it might seem like an unnecessary obstacle which is a byproduct of the language being fully functional. There are, however, many benefits of using monads, one being that it affects the type system in a positive way. Because monads are explicitly seen in the type system, the programmer can at a glance see which code runs in what computational context.
Being a statically typed language means that all types are resolved at compile time instead of run time as it would have in a dynamically typed language. Static type checking brings benefits, mainly that trivial bugs can be caught at compile time. Knowing types at compile time also allows the compiler to do various optimisations otherwise not possible. The size of the compiled binaries also tends to become smaller and run more quickly because the code for checking types during run time can be omitted.
Haskell also offers very compact syntax, which may allow complex code to be expressed clearly. The clarity and reduced size of Haskell code can make it easier to digest functionality when reading new code. There is data supporting the fact that Haskell programs tend to be a lot more concise and smaller than object-oriented and imperative programs \cite{hudak1994haskell}. In addition, there exists a proportional relationship between the number of bugs and lines of code, generally independent of what language is used \cite{mcconnell2004code}. The brevity of Haskell and the relationship between lines of code and bugs could mean that an experienced programmer is more productive in a functional language than in an imperative one, if a programmer spends less time writing Haskell code than debugging.
\subsection{JavaScript}
\label{sec:javascript}
JavaScript is a high-level, dynamic and interpreted language which is standardised by the EcmaScript specification \cite{flanagan2011javascript}. Furthermore, it is supported by all major web browsers that are used today; this has made JavaScript a very popular language. However, despite its popularity, JavaScript still has several shortcomings. According to Ekblad, JavaScript suffers from several problems, including bad scoping semantics, weak typing, and poor support for the functional paradigm \cite{ekblad2012towards}.
\subsection{Haste}
Haste is a Haskell to EcmaScript compiler developed by Anton Ekblad, a Ph.D. student at Chalmers University of Technology. The output from Haste will be referred to as JavaScript in this work since the most common implementation of EcmaScript is JavaScript as described in \cref{sec:javascript}. Haste is based on the Glasgow Haskell Compiler (GHC) because the bulk of the work that goes into improving the Haskell language is implemented in GHC \cite{ghc-compiler}. GHC also includes many language extensions that are widely used today \cite{ekblad2015seamless}. Because Haste utilise GHC, it can make use of almost all of the optimisations the GHC makes to Haskell code before converting the code to JavaScript. In addition, Haste is integrated with the Google Closure Compiler. The Google Closure Compiler is a JavaScript-to-JavaScript compiler that minimises and optimises the code \cite{google-closure}.
One of the primary aims for the Haste compiler is to produce lightweight and optimised code. Because of this, Haste does not support everything the GHC compiler does. Instead, Haste makes some compromises in order to perform optimisations of the generated code \cite{ekblad2015seamless}.
\subsection{Haste.App}
Haste.App is a library compatible with the Haste compiler used for writing client-server applications. There are several properties that make Haste.App different in comparison to the traditional way of writing network applications.
Probably the most notable difference is that both the client and server logic is written in the same program. This allows for an extension of the powerful type system over the network. Haste.App makes it possible at compile time to verify that the type of data the client or server send and receive are correct. It is also easier to move functionality from the client to the server and vice versa.
Another significant feature of Haste.App is the abstraction of network communication. The programmer does not have to explicitly write the communication between the client and server. Instead of calling a function to send data over the network, the client can call the function on the server directly using special constructs, a combination of the \textit{remote} and \textit{onServer} functions. Functions that are called over the network in this way are always synchronous, which means that the client will wait for a response from the server before continuing the execution of the program. The abstraction of network communication is implemented using HTML5 WebSockets in Haste.App \cite{a-distributed-haskell-for-the-modern-web}.
Having all the logic in one program might seem to blur the distinction between the code executed on the client or server, but a separation is achieved using the Haskell type system. The code that is only executed on the server is wrapped in the \textit{Server} monad and the client code is wrapped in the \textit{Client} monad. Both monads are instances of the \textit{IO} monad.
Uniting the client and server code also requires a different way of compiling the program. The code is first compiled with GHC, which generates the binary that is executed on the server. After GHC is done, the code is compiled with Haste which produces the JavaScript code that runs on the client.
A simple example of Haste.App can be seen in \cref{fig:haste-app-example}. The \textit{main} function starts the app by creating a list variable containing names of the connected clients, wrapped in a \textit{MVar}, which is used as the server state. The \textit{MVar} (a synchronous variable) is lifted, i.e. has its context changed, into the Server context which tells Haste.App that it should only be available on the server. Also, in the main function the \textit{connect} and \textit{countClients} functions are wrapped in a remote context to enable them as remote procedural calls (RPCs). Being remote means that the function exists on the server but can be accessed by the client through a \textit{onServer} call. Following the creation of the remote function the client code begins, it prompts the client for a name and calls the \textit{remoteConnect} to add the acquired name to the servers state. It then calls the \textit{remoteCountClients} function and receives the number of connected players which is displayed to the client.
\begin{figure}[H]
\centering
\begin{lstlisting}
-- Entry point for both the Server and Client.
main = runApp defaultConfig $ do
-- Mvar is a synchronized variable.
clients <- liftServerIO $ newMVar []
-- Create the remote functions which the
-- client can call and execute on the server.
remoteConnect <- remote $ connect clients
remoteCountClients <- remote $ countClients clients
-- Here client only code begins.
runClient $ do
name <- prompt "Hello! Name please!"
-- <.> applies name as parameter to the remote function.
onServer $ remoteConnect <.> name
nbrOfClients <- onServer $ remoteCountClients
alert ("Hello number " ++ show nbrOfClients)
-- | Add clients nick to server state i.e. the list of names.
connect :: Server (MVar [String]) -> String -> Server ()
connect remoteClientList name = do
clients <- remoteClientList
liftIO . modifyMVar_ clients $ \cs -> return $ name : cs
-- | Count the total number of clients connected.
countClients :: Server (MVar [String]) -> Server Int
countClients remoteClients = do
clients <- remoteClients
clientList <- liftIO $ readMVar clients
return $ length clientList
\end{lstlisting}
\caption{Simple Haste.App example that stores your name on the server and displays how many clients have entered to the connecting client.}
\label{fig:haste-app-example}
\end{figure}
\subsection{DOM}
DOM or Document Object Model is a standard for representing documents that contain some markup languages, such as HTML. It allows for HTML pages to be written in a hierarchical tree-like manner and it allows for programs to interact with the contents of the page to create interactive websites. HTML, or HyperText Markup Language, is the standard for creating web pages.
The DOM in the form of HTML can be created in various ways. One approach is to use a separate file where raw HTML is accepted. Another approach is using JavaScript, or Haste in the case of this project, to create HTML elements and add them to the DOM tree. Another approach is to use an external library created for use with Haste.
\subsection{SQL \& MySQL}
Structured Query Language (SQL) is a domain specific language designed to interact with a relational database management system (RDMS). In an RDMS data is stored in tables where each table is organised into columns and rows. Columns represent which type of data may be retained in the table and the list of rows represent the data stored in the table. MySQL is an open source implementation of most parts of the SQL standard. Its main features are the ability to handle large amounts of data and that it is relatively easy to setup \cite{mysql-features}. Databases are an important aspect of web development.
\newpage
\section{Method}
\label{sec:method}
To reach a conclusion regarding the purpose of the project a number of methodologies of evaluating performance, programmer productivity, and stability have been used. An application was written with Haste.App to enable data gathering from measurements and tests. Specifically, a lobby system for games was developed together with an implementation of the game Chinese Chequers. Further evaluation was based on observations and tests performed during or after the creation of the application. How the assessment of these areas of interest was done is discussed in more detail below.
\subsection{How to measure performance}
\label{sub:method-performance}
Several different aspects needed to be taken into account to assess the overall performance of the application. Most notably, the speed of the application was measured. Because the application is hosted on a web page, there were primarily two metrics to be considered when measuring its speed. The amount of bandwidth sent between the server and the client and how much system resources were used by the application. The different methods used to measure system resources on the client and the server are explored below.
The bandwidth needed by the application was divided into two parts, the bandwidth required to transfer the JavaScript to the client from the server, and the bandwidth required when a client is using the application. This data was compared to other sites offering similar content to assess if the application requires a reasonable amount of bandwidth for what it does. Measuring the initial bandwidth was done by measuring the size of the generated JavaScript. Moreover, the bandwidth required during the connection was measured via \textit{Wireshark} \cite{wireshark-website}, a tool for monitoring network traffic.
The system resources used by the application on the server-side are defined by the CPU-usage, load average, network utilisation, and the amount of RAM required. To monitor these values the resource monitoring tool \textit{munin} \cite{munin-website} was used. On the client-side, on the other hand, performance was measured by looking at the total CPU time used by the executed JavaScript. The web browser Chrome was used together with its built-in developer tools to measure the total CPU time.
To test the performance of the server when there are many clients connected and interacting with the website, scripts were written with the help of the Ruby library \textit{Watir} \cite{watir-test-framework}. The library enabled a script to interact with the DOM elements of a web page. \textit{Watir} made it possible to simulate connected clients and simultaneously monitor and quantify CPU and memory usage on the server when a number of clients were connected.
\subsection{How to measure stability}
\label{sub:method-stability}
To measure the stability of the developed application, it was decided that a number of states should be monitored to make sure they were resistant to unrecoverable errors. An unrecoverable error is an error that cannot be handled by the application and forces a reset of the application state. The states were:
\begin{enumerate}[noitemsep]
\item When the server gets updated/restarted during an active session.
\item If the client has outdated JavaScript when trying to communicate with the server.
\item Runtime errors on the server.
\item Runtime errors in the clients JavaScript.\\
\end{enumerate}
The first state was decided to be monitored as it is common that an update has to be made to the server. Preferably it should be possible to perform such an update without the user noticing a reconnection of the web socket. It could also be the case that the server crashes. In the event of such a crash, it would be preferable if the server could restart without the clients noticing the crash.
The second state was monitored since the source code is compiled twice, once with Haste and once with GHC. It could be easy to accidentally update only one of the two compiled sources. When this happens, either the client or the server can receive an unexpected value and may crash.
The third state was considered because Haste.App can potentially cause crashes on its own as it is a new library. Since it is a new library, it was important to measure if these issues were a problem. While crashes can occur based upon logical errors, such crashes were not taken into account.
The final state was also considered since Haste is a relatively new library. Once again, what was primarily considered are crashes caused by Haste.App or Haste, since logical errors will be present regardless of the library. In the client JavaScript, however, there is another dimension compared to runtime errors on the server since the JavaScript is compiled with the Haste compiler.
\subsection{How to measure programmer productivity}
\label{sub:method-programmer-productivity}
Assessing the programmer productivity of using Haste.App was difficult. Initially, it might seem like a very subjective criterion, and it partly is, but there were further aspects taken into account when measuring programmer productivity. What was considered were, errors present in Haste and Haste.App, possible effects of the client-centric and linear programming model of Haste.App, if the strong static type system of Haskell has any effects, and comparing the lines of code with other similar applications.
Looking at errors present in Haste and Haste.App was an important aspect. Since Haste is on version 0.5.4 during writing, there may be some prominent issues in both Haste and Haste.App, which would have to be worked around during development. They would be detrimental to programmer productivity.
The client-centric and linear programming model of Haste.App is another interesting aspect. Since this programming model differs to traditional web development \cite{ekblad2015seamless}, it was an important aspect to assess. The developer of Haste.App claims that this programming model can make the program flow easier to grasp \cite{ekblad2015seamless}. Therefore, it would have a positive effect on programmer productivity.
Moreover, programmer productivity can also be affected by the strong static type system of Haskell. The type system is considered in respect to if the number of hard-to-find errors in the code is reduced. Since Haste.App also allows Haskell's type system to be extended over the network communication, aspects regarding errors in network communication are also considered.
Finally, the development of the application in this project was compared to other similar applications. Other applications were examined because difference in programmer productivity can be influenced by the number of lines of code required for that implementation. Lines of code in a project is an important aspect since it affects the maintainability as well as the development time.
\subsection{An application to measure Haste.App}
To accurately assess Haste.App an application was developed in two parts, a lobby system and a game. These two parts were chosen because they could be used to look at different areas of the problems described in \cref{sec:problem}. What follows is a brief description of the different parts as well as what problems they illustrate.
\subsubsection{The Lobby system}
The lobby system enables connected clients to start conversations with each other and create their own session of the game. When creating a new game session other clients are able to join until the game is full or until the creator starts the game, thus enabling games to be played.
A lobby system was created to assess scalability and performance of Haste.App. The scalability and performance was to be tested through the lobby since it does not have an upper limit of connected clients or concurrently active games. The aim was to find, if it exists, a correlation between performance and connected clients. Another important benefit of developing a lobby system was to enable thorough testing of programmer productivity when working with Haste.App since it would be possible to test various libraries for common web development purposes.
\subsubsection{Chinese Chequers}
\label{sub:chinesecheckers}
To test more of the performance and continuous communication between clients aspects of Haste.App a board game was implemented. Chinese Chequers was chosen for its simplicity since Haste.App might not yet be suitable for dealing with demanding real-time applications.
Chinese Chequers is a turn-based board game available for two, four or six players. The rules are fairly simple. Each player is assigned pieces of one colour. In order to win, a player has to move all pieces of the player's colour to the opposite side of the board. The six moves a player can make are moving horizontally down or up to the left or right, or vertically. A player may only move their piece to either one of those positions if they are empty. In case a position that can be moved to is occupied, it can be jumped over. An example is shown in \cref{fig:chequers-move}. Jumping over a piece makes the player eligible to move the same piece by jumping over another piece again.
\begin{figure}[ht]
\centering
\includegraphics[width=0.3\textwidth]{figure/moves}
\caption{Shows all the possible moves the blue chequer can do.}
\label{fig:chequers-move}
\end{figure}
\newpage
\section{Development}
Developing an application in Haste.App may differ somewhat from the development of an application in a different programming model. Therefore, the process of developing an application using Haste.App is here described. The process of development was split into two parts: the game and the lobby system, which were developed in parallel. This section describes how the development was performed and crucial decisions which had to be made along with other important issues that had to be solved.
\subsection{Dependency management using Haste.App}
\label{sub:dependencies}
Since an application in Haste.App is compiled using two compilers, GHC and Haste; this presents some problems when using some external libraries as Haste does not support everything GHC supports. To solve this problem, conditional compilation was used, which enables the programmer to tell the compiler to ignore certain parts of the code when compiling with a specific compiler. An example of how this was done is shown in \cref{fig:dependencies-definitions}.
\begin{figure}[ht!]
\begin{lstlisting}
#ifdef __HASTE__
import LobbyClient
#define disconnect(x) (\_ -> return ())
#else
import LobbyServer
#define clientMain (\_ -> return ())
#endif
\end{lstlisting}
\caption{Definitions made to work around dependency problems.}
\label{fig:dependencies-definitions}
\end{figure}
In \cref{fig:dependencies-definitions} it is stated that if '\_\_HASTE\_\_' is defined i.e. the code is compiled by the Haste compiler, import \textit{LobbyClient}, but also make a dummy definition of the \textit{disconnect} function, since the actual disconnect function is defined in \textit{LobbyServer}. Likewise, if '\_\_HASTE\_\_' is not defined i.e. GHC is compiling, import only \textit{LobbyServer} and make a dummy definition of the \textit{clientMain}.
In general, if a Haskell library which Haste cannot compile is desired to be utilised on the client-side then the server needs to provide it through a remote function and return it in some data type which Haste can handle.
\subsection{Updating the client}
\label{sub:updating-client}
During the development, there was a problem with updating the client when a state change occurred. For example, when a client connects to the server all other clients should be notified. Since Haste.App is client-centric, the client has to be the one to initiate communication with the server. Two methods were considered to solve this problem. The first method works by reading a state from the server and then updating every couple of seconds. The second method instead uses a synchronous channel at the server. The server writes to the channel when an update occurs and the client reads from the channel continuously.
The first method, reading a state from the server, is more intuitive to construct than the second. It is also in line with the client-centric model of Haste.App, which makes the program flow easy to understand. However, this method drains additional resources as the client has a process reading the state of the server every couple of seconds. Upon reading the state, the process has to determine if the state has changed and then update accordingly. The method is illustrated in \cref{fig:reading-state}.
\begin{figure}[ht!]
\begin{subfigure}[]{\textwidth}
\begin{lstlisting}[language=Haskell]
-- Waits for an update in state to occur and then updates if it has
listenForUpdates :: State -> (State -> Client ()) -> Client ()
listenForUpdates oldState callback = do
newState <- onServer readState
if oldState == newState
then do
-- if nothing has changed, wait a second before checking again
setTimeout 1000 $ listenForUpdates oldState callback
else do
callback newState -- Update the client in some way
listenForUpdates newState callBack
\end{lstlisting}
\subcaption{Client code, reads the state and then updates if it has changed}
\end{subfigure}
\begin{subfigure}[]{\textwidth}
\begin{lstlisting}[language=Haskell]
-- Simply reads the server state belonging to that client
readState :: StateList -> Server State
readState states = do
sid <- getSessionID -- gets the unique session id
liftIO $ do
case sid `lookup` states of
Nothing -> return emptyState -- "should not happen"
Just state -> return state
\end{lstlisting}
\subcaption{Server code, returns the state}
\end{subfigure}
\caption{The method of reading a state from the server and then deciding if to update.}
\label{fig:reading-state}
\end{figure}
The second method, reading a synchronous channel, solves the problem with consuming resources that the first method has. This method is, however, more complicated in its construction. Since the channels are created and kept by the server, there has to be a function on the server for reading the channel. Reading from the channel is a blocking operation so there is, for each channel, a process waiting to read. Upon reading a value from a channel, through a remote call to the server, the client has to react to the message in some way. This method is illustrated in \cref{fig:reading-channel}. After careful consideration, this approach was decided to be used to communicate state changes in both the game and the lobby.
\begin{figure}[ht!]
\begin{subfigure}[]{\textwidth}
\begin{lstlisting}[language=Haskell]
-- Client-side method for reading a message from the server
listenForMessages :: Remote (Server Message) -> (Message -> Client ()) -> Client ()
listenForMessages serverReadChannel callBack = do
msg <- onServer serverReadChannel -- call the server with the readChannel function
callBack msg -- React to the read message in some way
-- Perhaps by getting a new state
listenForChatMessages callBack -- recurse indefinitely
\end{lstlisting}
\subcaption{Reads the channel (at the server) and then reacts to the message, maybe by getting new state.}
\end{subfigure}
\begin{subfigure}[]{\textwidth}
\begin{lstlisting}[language=Haskell]
-- Called by a client to read its channel
readChannel :: Server (MVar [a]) -> Server Message
readChannel remoteClientChannels = do
sid <- getSessionID -- gets the unique session id
mVarClientChannels <- remoteClientChannels
liftIO $ do
clientList <- readMVar mVarClientChannels
case sid `lookup` clientList of
Nothing -> return $ ErrorMessage "Couldn't find client."
Just clientChannel -> readChan clientChannel -- readChan is blocking
\end{lstlisting}
\subcaption{Reads the client's state, if it can be found.}
\end{subfigure}
\caption{The method of reading a synchronous channel.}
\label{fig:reading-channel}
\end{figure}
\subsection{Development of the game}
\label{sec:game-development}
This section describes the rule set that was implemented in the game and the technical implementation. It also illustrates the choices taken during the development of the game sequentially.
\subsubsection{Implementation of the game rules}
\label{sec:game-rules}
The diagram in \cref{fig:flowchartGame} describes the actions a player can make. After a jump the game automatically moves to the next player but when a double jump (a jump over a chequer) is made it is possible to move again as seen in the flowchart, but only with the same chequer. In this implementation of the game, it is also possible to rotate the current player without moving a chequer.
\begin{figure}[ht!]
\centering
\includegraphics[scale=0.1,width=0.4\textwidth]{figure/flowchartGame}
\caption{Displaying all possible actions a player can make within the game.}
\label{fig:flowchartGame}
\end{figure}
\subsubsection{Game logic and data types}
The \cref{fig:gameTypes} illustrates the hierarchy in which the types depend on each other together with their definitions. The $Content$ data type was created to represent what every position can hold: it is either $Empty$ or it has a coloured piece, which is represented by the data constructor $Piece$ $Color$. The next crucial data type is $Square$. $Square$ is a product type containing a: $Color$, $Content$ and $Coord$. The $Coord$ type is simply a type synonym for $(Int,Int)$, representing the game logic coordinates. With the help of these types, the game table could be defined and it is represented by the $Table$ type. $Table$ is also a type synonym for $[Square]$.
\begin{figure}[ht!]
\centering
\begin{subfigure}{\textwidth}
\centering
\includegraphics[scale=0.8,width=0.8\textwidth]{figure/gameTypesHierarchy}
\caption{Visualisation of the game data types hierarchy. The root of the tree is the \textit{GameState}.}
\end{subfigure}
~
\begin{subfigure}{\textwidth}
\begin{lstlisting}
data Content = Empty | Piece Color
data Square = Square Content Color Coord
type Coord = (Int,Int)
type Table = [Square]
type Player = String
data GameState = GameState { players :: [(String,Color)]
, gameTable :: Table
, playerMoveAgain :: Bool }
, currentPlayer :: String
, fromCoord :: Maybe Coord
\end{lstlisting}
\caption{The Haskell data types that are used in the game}
\end{subfigure}
\caption{Illustration of the data types that are used in the game}
\label{fig:gameTypes}
\end{figure}
Furthermore, a way to represent the current state of the game was needed, and therefore, the $GameState$ type was created. $GameState$ contains the following:
\begin{itemize}
\item A $Table$ holding the current game table.
\item The field $Players$ which is of type $[(Player,Color)]$ containing all the active players with their respective colour implemented as a regular queue.
\item $CurrentPlayer$ is defined as a $Player$ which is a type synonym for a $String$.
\item $MoveAgain$ which is of type $Bool$ used for checking if the current player can move again.
\end{itemize}
The $GameState$ is thus holding all information about a game session and is the root of the type tree in \cref{fig:gameTypes}. Each client stores their $GameState$ locally in an $MVar$.
\subsubsection{Graphical implementation}
\label{sec:graphimpl}
\begin{figure}[ht!]
\centering
\includegraphics[scale=0.8,width=0.6\textwidth]{figure/game}
\caption{The resulting game graphics.}
\label{fig:gameGraphics}
\end{figure}
Haste provides a library for drawing and filling regular geometrical figures, but using these functions only achieves a pretty outdated graphical look. A decision was made to use bitmaps, which are just pictures that can be rendered on the screen. This gives a more modern graphical look, as seen in \cref{fig:gameGraphics}.
Furthermore, a highlighting effect was achieved by changing the contrast and brightness of the bitmaps used to represent the chequers.
Upon clicking on the screen to interact with the game, the input coordinates need to be parsed to represent game logic coordinates. There were issues with generating the correct input coordinates when using the function supplied with Haste. To solve the coordinates issue, the FFI for getting the game board position on the screen was needed. The FFI is used to call JavaScript directly from Haskell. Knowing the game board position and the current scrolled offset on the page, the correct input coordinates could be calculated.
\subsubsection{Network communication}
The first approach to communication between the client and server was to let the server give each client channels, from Haskell's $Control.Concurrent$ package. They did not work with Haste, which seemed strange since the $MVars$ from $Control.Concurrent$ had been used without a flaw.
The issue regarding the channels was solved by only reading and writing to the channels on server-side. The client simply requests the server to read or write to the channels located on the server. Using the channels from $Control.Concurrent$ works on server-side since the code is only compiled with GHC. Updating the client is described in more detail in \cref{sub:updating-client}.
As mentioned in \cref{sec:graphimpl} interaction with the game is done via the graphical game table, which upon clicking parses the coordinates. These coordinates are wrapped in a $GameAction$ type and sent to the server which broadcasts this message to all active clients. Upon receiving the $GameAction$ each client parses it and calls a function for updating the local game state.
The $GameAction$ type was created to avoid sending the whole $GameState$ over the network, and it represents each possible manipulation a client can make to the local $GameState$. The definition can be seen in \cref{fig:gameAction}, and the data constructors are self-explanatory.
Verifying the validity of a move is only done on client-side. This is an issue regarding the safety of the game. This allows for client-side manipulation of the code, which could make illegal moves possible. Doing the verification on server-side was left out mainly due to the limited amount of time.
\begin{figure}[H]
\begin{lstlisting}
data GameAction = StartGame
| RotatePlayer
| GameActionError String
| Coordinate (Int,Int)
\end{lstlisting}
\caption{Illustration of the data types that were used in the game}
\label{fig:gameAction}
\end{figure}
\subsection{Development of the lobby system}
\label{sub:lobby-development}
This section serves to describe the implementation of the lobby system. It describes the technical implementation and issues encountered along the way. After that it describes the data types of the lobby and why they are constructed as they are.
\subsubsection{Lobby implementation}
The development of the lobby system started out straightforward and was divided into three milestones:
\begin{enumerate}
\item Client does a handshake connection with the server to enter the lobby.
\item Create a game and start it when enough people have joined.
\item Implement a chat to enable communication between players.
\end{enumerate}
These goals might seem simple enough but they include other small issues. To only mention a few, a client should be able to see which games are active,change their name, edit settings of a game they own and see names of the other players in the lobby. Here a couple of important decisions taken during the development are described.
The problem mentioned in \cref{sub:updating-client} was encountered early in development. As stated, there are some advantages to the second method, such as taking fewer system resources, and it was therefore adopted. Several channels were created, one for each type of communication. The clients could then listen for messages being written to the channel to update their state.
Moreover, to allow communication between connected players a chat was implemented using concurrent channels the same way as previously mentioned. For each client joining a chat the corresponding channel on the server is duplicated and saved in a client entry for that specific client. An illustration of the flow of reading a chat channel can be seen in \cref{fig:read-chat-from-server}.
\begin{figure}[ht!]
\centering
\includegraphics[scale=0.5,width=0.7\textwidth]{figure/readChatFromServer}
\caption{Visualisation of data flow when a client uses a RPC to remotely access the API function readChatChannel.}
\label{fig:read-chat-from-server}
\end{figure}
In addition, to properly evaluate the development of a web application using Haste.App it was decided that the lobby should save most of its data in a database, since they are commonly used with web applications. MySQL was chosen as the backend database server and to interface with it from Haskell the libraries \textit{Persistent} \cite{persistent-yesod} and \textit{Esqueleto} \cite{esqueleto-hackage} were used. \textit{Persistent} contains most of the database functionality used in this project, including declaring type-safe SQL tables in Haskell code and Haskell functions that support basic database queries. \textit{Esqueleto} extends the functionality of \textit{Persistent} to allow custom, type-safe SQL queries that are more complex. At the beginning of the development, all games were stored in a list on the server, but this data was migrated to be stored only in the database to test its properties.
Furthermore, it was decided to test how password management would work with Haste.App, since authentication of users is another important aspect in web development. Therefore, some Haskell libraries offering to hash passwords were considered and it was decided to use \textit{Crypto.PasswordStore} \cite{pwstore-package}. However, since it would take too long to develop a user authentication system, it was decided that users should be able to protect their games with passwords. At first, the passwords were meant to be hashed at the client, but the library was not compatible with Haste. As such the passwords are sent in plain text and hashed at the server.
\subsubsection{Data types of the Lobby}
To create the lobby as previously described, a number of data types were created, which can be seen in \cref{fig:datatypes}. The data types are mostly self-descriptive, but some of the design decisions are illustrated here.
First, two lists were encapsulated in an MVar, namely $ConcurrentClientList$ and $ConcurrentChatList$. They were decided to be MVars since they are passed to the remote server functions at the entry point of the program and then modified inside those functions. This was necessary since it allows them to work in a similar way to a state, and since it allows only one process to access them simultaneously. Originally there was one more MVar list, $ConcurrentGameList$, but it was removed as all game data was instead saved in the database.
Next, there are two $Message$ data types, $ChatMessage$ and $LobbyMessage$. These were created in order to communicate change to clients. They are encapsulated in Concurrent Channels in order to allow the server, via a call from a client, write several messages to a client. These messages are then read via a remote call from a client to the server as illustrated in \cref{fig:reading-channel}.
\begin{figure}[ht!]
\centering
\begin{subfigure}{\textwidth}
\centering
\includegraphics[scale=0.4]{figure/datatypes}
\subcaption{The diagram displays the hierarchy in which the data types depend on each other.}
\end{subfigure}
\begin{subfigure}{\textwidth}
\begin{lstlisting}
type LobbyState = (Server ConcurrentClientList, Server ConcurrentChatList)
type ConcurrentClientList = MVar [ClientEntry]
type ConcurrentChatList = MVar [Chat]
type Chat = (Name, Chan ChatMessage)
type Name = String
data ClientEntry = ClientEntry {sessionID :: SessionID
,name :: Name
,chats :: [Chat]
,lobbyChannel :: Chan LobbyMessage
,gameChannel :: Chan GameAction}
data ChatMessage = ChatMessage {from :: Name
,content :: String}
| ChatJoin
| ChatAnnounceJoin {from :: Name}
| ChatLeave
| ChatAnnounceLeave {from :: Name}
| ChatError {errorMessage :: String}
data LobbyMessage = NickChange | GameNameChange | KickedFromGame | GameAdded
| ClientJoined| ClientLeft | PlayerJoinedGame | PlayerLeftGame
| StartGame | LobbyError {lobbyErrorMessage :: String}
\end{lstlisting}
\subcaption{The data types as they are defined in Haskell. GameAction is defined in the Game section.}
\end{subfigure}
\caption{Illustration of the data types in the lobby.}
\label{fig:datatypes}
\end{figure}
\subsection{Issues encountered with Haste and Haste.App}
\label{sub:issues-during-development}
During the development of the lobby and game a number of issues with Haste and Haste.App arose. The issues were related to working with channels, using the FFI, rendering, dependency management, password management and security, and generating HTML. %Here thgeneratingese issues are described in the context they appeared during the development of the lobby. \todo{Ta bort sista meningen?}
Channels from the $Control.Concurrent$ package does not seem to work with Haste. Writing to a channel works fine, but any other operation such as reading from the channel did not work. The application simply crashes when using any of those functions.
Using the library function for getting mouse coordinates in a canvas returns the x coordinate relative to the whole screen, and y coordinate relative to the canvas, which of course is not correct. This seems to be a problem with JavaScript and not Haste, since the library function in Haste is implemented using the foreign function interface (FFI), thus calling JavaScript code.
Moreover, the highlighted bitmaps in the game are not always rendered on the canvas, and it seems to be arbitrary when the rendering starts. It is assumed that the issue related to rendering the highlighted bitmaps is caused by a bug in the Haste compiler.
In addition, problems with dependencies with GHC and Haste also exists and are discussed in more detail in \cref{sub:dependencies}. Such a problem was encountered when using the \textit{Data.UUID} library for giving games a unique identifier. The library cannot be installed with Haste, thus forcing a very sharp separation between Server and Client code.
Furthermore, as described in \cref{sub:lobby-development} passwords are sent in clear text to the server to be hashed. Sending the passwords in clear text revealed an important issue with Haste.App: Haste.App does not provide secure web sockets. Even when forcing an HTTPS connection via the web server the web sockets used by Haste always default to insecure.
Generating HTML using Haste was a tedious task. The functions that operate on HTML elements, such as $<div>$ and $<body>$, work by first getting an element using its \textit{id} and then modifying that element. It works in the same way as generating an entire HTML page from JavaScript would. The difference between writing a simple HTML tree in Haste compared to pure HTML can be seen in \cref{fig:HTML-generation}. There are a couple of libraries developed for Haste that attempt to simplify generating HTML. Most of these libraries are, however, not up to date and will not work with the current version of Haste due to the rapid development of Haste itself.
\begin{figure}[H]
\centering
\begin{subfigure}[b]{\textwidth}
\begin{lstlisting}
parentDiv <- newElem "div" `with`
[
attr "id" =: "parent-div",
attr "class" =: "input-group"
]
inputField <- newElem "input" `with`
[
attr "type" =: "text",
attr "id" =: "text-field",
attr "class" =: "form-control"
]
buttonSpan <- newElem "span" `with`
[
attr "class" =: "input-group-btn"
]
button <- newElem "button" `with`
[
attr "id" =: "input-button",
attr "type" =: "button",
attr "class" =: "btn"
]
buttonText <- newTextElem "Change"
appendChild button buttonText
appendChild buttonSpan button
appendChild parentDiv inputField
appendChild parentDiv buttonSpan
appendChild documentBody parentDiv
\end{lstlisting}
\caption{Creating HTML in Haste}
\end{subfigure}
\begin{subfigure}[b]{\textwidth}
\begin{lstlisting}[language=HTML]
<body>
<div id="parent-div" class="input-group">
<input type="text" id="text-field" class="form-control">
<span class="input-group-btn">
<button id="input-button" type="button" class="btn">
"Change"
<button>
</span>
</div>
</body>
\end{lstlisting}
\caption{The same HTML in an .html file}
\end{subfigure}
\caption{Comparison of generating HTML in pure .html files and in Haste}
\label{fig:HTML-generation}
\end{figure}
However, an alternative to writing the HTML in Haste would be to have several HTML files that could be switched to during the use of the lobby. However, this exposed an issue with Haste.App: When the HTML file was switched the client disconnects from the server and then reconnects. Since the client has to reconnect, the server cannot easily identify this client as being the same as before. While this is an issue that can be bypassed by adding some identification to the client stored in HTML5 Local Storage (that Haste has support for), it was considered out of the scope of the project.
\newpage
\section{Results}
The aim of this project was to evaluate, based on a few topics, how suitable Haste.App is for web development. The topics were: Performance, stability and programmer productivity. The results are split into two parts. The first part addresses what was created, namely the game and the lobby and their respective functionality. The second part presents the results of the three points of interest and is evaluated as described in \cref{sec:method}.
\subsection{Game and Lobby implementation results}
\label{sub:game-lobby-results}
The game of Chinese Chequers was implemented according to description in \cref{sec:game-rules}. The resulting graphics can be seen in \cref{fig:gameGraphics}.
The implementation of the lobby system resulted in a system that does the following things:
\begin{itemize}[noitemsep]
\item Start a game that others can join.
\item Changing settings of a game, including name, password and, max number of players allowed.
\item Chat with other players.
\item Saving games and players in an external database.\\
\end{itemize}
The source code is available on GitHub, allowing a deeper review of the implementation:
\begin{itemize}[noitemsep]
\item Game: \url{https://github.com/DATx02-16-14/ChineseCheckers}
\item Lobby: \url{https://github.com/DATx02-16-14/Hastings}
%\item Performance test scripts: \url{https://github.com/DATx02-16-14/scripts}
\end{itemize}
\subsection{Results regarding performance}
\label{sub:performance-results}
The performance of the application is measured by, as stated in \cref{sub:method-performance}, the bandwidth required and system resources used. The bandwidth considered is primarily the data required to send the JavaScript since the data required to send images, text, and other static content is not unique to Haste.App. Moreover, the bandwidth needed when communicating with the server during use is also considered to make sure the client-centric programming model does not yield an unnecessary amount of network traffic. Furthermore, the system resources used on the server is measured, in respect to how many players are online. In addition, the system resources used on the client is measured.
\subsubsection{Server-Side performance}
\label{subsub:server-performance-results}
Using \textit{watir} it was possible to simulate 80 clients which joined the lobby, wrote messages in the chat and created games. The 80 clients were split up on four computers with 20 simulated clients each. The CPU usage, memory usage, load average and network traffic can be seen in \cref{fig:cpu-results} and \cref{fig:cpu-results-attachment}, \cref{fig:memory-results} and \cref{fig:memory-results-attachment}, \cref{fig:network-results} and \cref{fig:network-results-attachment}, \cref{fig:load-average-results} and \cref{fig:load-average-results-attachment}, respectively. The server running the application has 8 GB RAM and an Intel(R) Core(TM)2 Duo CPU E8400 3.00GHz, running Ubuntu 15.10. The full system specifications can be found in \cref{sub:system-specs}. Two tests were performed and are described below along with observations on CPU, memory, network traffic, and load average.
The first test showed the load when creating games on the server and as such tested performance when accessing the database. At 14:30 the 80 clients joined a game. At 14:45 the 80 clients created games and upon creating the games they change the games name, password and max amount of players. At 15:05 all clients start to leave the server.
The second test evaluated pure Haste.App performance by chatting in the server, it did not require any access to the database. The 80 clients joined at 16:25, and at 16:40 they start to chat. At 16:50 the clients then disconnect from the server.
Firstly, regarding CPU on the server, which is illustrated in \cref{fig:cpu-results} and \cref{fig:cpu-results-attachment}, it increases to about 5\% when 80 clients join the server. It can be seen that the most CPU intensive tasks occur when games are created and settings on them changed. This is either because of passwords for the games are set and then hashed on the server or because all game data is entered into the database and as such when a setting is changed and a game created the database is accessed. When chatting, that is only sending messages through Haste.App, the CPU usage stays at roughly 5\%.
\begin{figure}[ht!]
\centering
\includegraphics[width=0.9\textwidth]{figure/serversidePerformance/2016-05-05-game-test-cpu2.png}
\caption{CPU usage on the server during the first test}
%\caption{CPU usage on the server during the two tests}
\label{fig:cpu-results}
\end{figure}
The memory usage on the server, which is illustrated in \cref{fig:memory-results} and \cref{fig:memory-results-attachment}, stays about the same during both tests. The only time where there is noticeable memory usage is when the initial connection is established.
\begin{figure}[ht!]
\centering
\includegraphics[width=0.9\textwidth]{figure/serversidePerformance/2016-05-05-game-memory.png}
\caption{Memory usage on the server during the first test}
%\caption{Memory usage on the server during the two tests}
%\caption{Server performance when 80 clients joined the server(14:25), created games and changed their settings(14:45-15:00) and then left(15:10)}
\label{fig:memory-results}
\end{figure}
Furthermore, network traffic on the server during the two tests are shown in \cref{fig:network-results} and \cref{fig:network-results-attachment}. The server sends more data than it receives when the clients connect. During the phase where the clients either chat or create games, the server sends about the same amount of data as it receives as all clients receive messages as described in \cref{sub:lobby-development}. When disconnecting some data is sent, but not much.
\begin{figure}[H]
\centering
\includegraphics[width=0.9\textwidth]{figure/serversidePerformance/2016-05-05-network-traffic-game.png}
\caption{Network traffic on the server during the first test}
%\caption{Network traffic on the server during the two tests}
%\caption{Server performance when 80 clients joined the server(14:25), created games and changed their settings(14:45-15:00) and then left(15:10)}
\label{fig:network-results}
\end{figure}
The load average can be seen in \cref{fig:load-average-results} and \cref{fig:load-average-results-attachment}. The load stays below one throughout the tests which indicates that no process has to wait to be run. The max load average is 0.43, which is not especially high since 1.0 indicates that one process is waiting for CPU time.
\begin{figure}[H]
\includegraphics[width=0.9\textwidth]{figure/serversidePerformance/2016-05-05-load-average-game-test.png}
\caption{Load average on the server during the first test}
%\caption{Server performance when 80 clients joined the server(14:25), created games and changed their settings(14:45-15:00) and then left(15:10)}
\label{fig:load-average-results}
\end{figure}
\subsubsection{Client-Side performance}
\label{subsub:client-performance-results}
The measured performance on the client-side was done in two parts. The JavaScript was profiled three times, with 0, 30 and 90 games created in the lobby respectively, results from that profiling are shown in \cref{fig:hastings-performance}. The figure shows that the relationship between the number of games created in the lobby and the total loading time for the website has a linear relationship. Additionally, in \cref{fig:hastings-comparison} two other websites that offer a lobby system were profiled, \textit{brasee.com} and \textit{lichess.org}. Lichess is a very popular website with 6000 concurrent users and 1500 simultaneous games at the time of profiling. Brasee, on the other hand, is not as popular with only a couple of games and about as many users online when the profiling was run. Nonetheless, it is interesting to note that while Lichess was noticeably slower, it also had a lot more games and players connected.
\begin{figure}[H]
\centering
\begin{subfigure}{0.32\textwidth}
\includegraphics[width=\textwidth]{figure/clientsidePerformance/graph1.png}
\subcaption{1 player connected and 0 games created.}
\end{subfigure}
\begin{subfigure}{0.32\textwidth}
\includegraphics[width=\textwidth]{figure/clientsidePerformance/graph30games1.png}
\subcaption{1 player connected and 30 games created.}
\end{subfigure}
\begin{subfigure}{0.32\textwidth}
\includegraphics[width=\textwidth]{figure/clientsidePerformance/graph90games1.png}
\subcaption{1 player connected and 90 games created.}
\end{subfigure}
\caption{Breakdown of computation time when loading the website in Chrome.}
\label{fig:hastings-performance}
\end{figure}
\begin{figure}[H]
\centering
\begin{subfigure}{0.32\textwidth}
\includegraphics[width=\textwidth]{figure/clientsidePerformance/graph1.png}
\subcaption{Loading our website with 0 games created.}
\end{subfigure}
\begin{subfigure}{0.32\textwidth}
\includegraphics[width=\textwidth]{figure/clientsidePerformance/braseegraph1.png}
\subcaption{Loading of the lobby on Brasee.}
\end{subfigure}
\begin{subfigure}{0.32\textwidth}
\includegraphics[width=\textwidth]{figure/clientsidePerformance/ligraph1.png}
\subcaption{Loading of the lobby on Lichess.}
\end{subfigure}
\caption{Breakdown of computation time when loading three similar websites in Chrome.}
\label{fig:hastings-comparison}
\end{figure}
\subsubsection{Bandwidth when using Haste.App}
In order to profile the bandwidth used by the websites, the program \textit{Wireshark} was used. All packets sent and received by the host address during a period of ten minutes were captured and analysed. In \cref{tab:site-comparisons}, data is differentiated by static and dynamic data. Static data is images and website content that are sent on page load. Dynamic data is data transmitted in response to an event by the application, for example, a player joining the lobby or when a chat message is sent.
In \cref{tab:site-comparisons} there are a couple of noteworthy differences. Firstly, Brasee has considerably more static data which can be attributed to the large number of images on that website compared to the others. Secondly, the Lichess lobby sent more dynamic data; probably because Lichess had a greater number of players connected.
\begin{table}[H]
\centering
\begin{tabular}{|l|l|l|l|}
\hline
\textbf{Web Site} & \textbf{Total Data Sent}(kb) & \textbf{Dynamic data}(kb) & \textbf{Static Data}(kb)\\ \hline
Lichess Lobby & 1185,737 & 1181,276 & 4,461 \\ \hline
Lichess Game & 122,067 & 116,512 & 5,555 \\ \hline
Brasee Lobby & 1496,903 & 254,435 & 1242,468 \\ \hline
Brasee Game & 2108,192 & 692,241 & 1415,951 \\ \hline
Our Lobby & 281,692 & 278,035 & 3,657 \\ \hline
Our Game & 162,067 & 156,705 & 5,362 \\ \hline
\end{tabular}
\caption{Data sent (in kilobytes) between the client and server for different lobby and game systems during 10 minutes.}
\label{tab:site-comparisons}
\end{table}
\subsection{Results regarding stability}
\label{sub:stability-results}
The stability of the application was considered out of four aspects, as defined in \cref{sub:method-stability}: updating the server, a client connecting with outdated JavaScript, runtime errors on the Server, and runtime errors on the client.
Because of the static type checking if Haskell the amount of runtime errors related to types on the client were reduced compared to writing JavaScript code. They are reduced since the static type checking captures all type errors in compile time. It did, however, not completely rid the application from them. Moreover, there are errors that are recoverable which seem to be inherent to Haste, namely when there is an HTML input field. The first character written into the field throws an error with the message:
\begin{align*}
\textit{Uncaught [object Object]}
\end{align*}
When continuing to write it throws an error with the message for every letter typed:
\begin{align*}
\textit{Uncaught Infinite loop!}
\end{align*}
These errors, however, do not seem to have any effect on the application.
The unrecoverable errors that can occur do so when working with the DOM, and specifically when trying to retrieve objects with an \textit{ID} that does not exist. This is, however, a problem that has to be dealt with both when using Haste and when using JavaScript.
Moreover, the server also very rarely has runtime errors. The programming model of Haste.App, with type safe network communication, appears to work very well. There has been no instance of a crash or bug occurring because of a network communication problem.
Updating the server, however, seems to be a prominent issue with Haste.App. There is currently no way of updating the server without disconnecting all clients connected. As the communication is handled via HTML5 WebSockets, these close when the server is restarted and there is no way in Haste.App to resume the same connection. The client has to reset the connection and thus it has to restart from the same state it was in when it first connected to the server. There is no way to keep current connections alive while updating the server so that new connections receives the updated state.
Since the code is compiled twice, the server and the client code needs to match. Matching the code can be tedious since the HTML has to be placed/updated at the web servers root and then the server has to be restarted. Should one of the two steps not be performed, the application can enter a faulty state and crash.
Moreover, to ensure the logical correctness of the code, the testing library \textit{QuickCheck} was used. The ability to use a powerful testing library helps in eliminating logical errors in the code. As such, \textit{QuickCheck} has helped to ensure the stability of the application.
Furthermore, there is no memory leakage on the server. The server application was left running for seven days during which the application was moderately used. During this time there were no evident increase in memory usage on the server.
\subsection{Results regarding programmer productivity}
\label{sub:programmer-productivity-results}
Programmer productivity when writing a web application using Haste.App was heavily influenced by a number of factors. A large influence is that all code is written in Haskell, compared to writing JavaScript client-side and some language server-side. Other influences on programmer productivity have been debugging and runtime errors, database usage, the linear, client-centric approach taken by Haste.App, and the fact that the whole application is written in the same language and the same project. The lines of code in the complete application are also compared to other similar applications and games.
\subsubsection{Haskell versus JavaScript during development}
\label{subsub:haskell-vs-js-during-development}
An advantage to writing the client-side code using Haskell instead of JavaScript has been the static type system of Haskell. Instead of manually checking the types of a function or data type (or object in JavaScript), one can rely on the static type checking to report any type errors. Allowing types to be checked during compilation has reduced the number of bugs encountered to a very limited set of runtime errors. In addition, since the type checking can also be used over the network, type checking network code is an easy matter.
Another advantage of Haskell is the clear separation between pure code and code with side effects. Most of the code with side effects in the developed game were Haste code. The graphical and network implementations are the parts where Haste was needed, while the game logic was written purely in Haskell. This clean separation made it easy to use \textit{QuickCheck} to test the pure and impure code as shown in \cref{fig:quickchecking}, and \cref{fig:quickcheck-monadic}.
\begin{figure}[ht!]
\begin{lstlisting}
-- |Property that checks that a square is not empty after having piece put into it.
prop_putPiece :: TableCoords -> OnlyPiece -> Bool
prop_putPiece (TableCoords (t, _, coord)) (OnlyPiece p) =
squareContent (putPiece t p coord) coord /= Empty
\end{lstlisting}
\caption{Testing pure code using QuickCheck.}
\label{fig:quickchecking}
\end{figure}
\begin{figure}[ht!]
\begin{lstlisting}
-- |Property that makes sure a game can be properly created.
prop_createGame :: [ClientEntry] -> Int -> Property
prop_createGame clientList maxPlayers = monadicIO $ do
pre $
not (null clientList) &&
maxPlayers /= 0
let sid = sessionID $ head clientList
let playerName = name $ head clientList
run preProp
--Setup test preconditions.
clientMVar <- run $ newMVar clientList
run $ PlayerDB.saveOnlinePlayer playerName sid
uuid <- run $ Server.Game.createGame clientMVar sid maxPlayers
game <- run $ GameDB.retrieveGameBySid sid
--Cleanup test
run postProp
assert $
--Check that the UUID returned exists.
isJust uuid &&
--Check that the game exists in the database.
isJust game &&
--Check that the max amount of players is correct.
(Fields.gameMaxAmountOfPlayers . Esql.entityVal . fromJust) game == maxPlayers
\end{lstlisting}
\caption{Testing impure code in the IO monad using QuickCheck.}
\label{fig:quickcheck-monadic}
\end{figure}
However, when writing a client-server application in Haste.App almost all client and server specific code has side effects. The client code is naturally placed in the \textit{Client} monad, and the server code in the \textit{Server} monad. The client mostly creates and updates HTML, which is naturally side-effecting. Furthermore, the server code mostly modifies a state, either in a database or a synchronous variable, both of which are also side-effecting. However, most code is easily testable by lifting the functions into the IO monad, which \textit{QuickCheck} supports natively.