====== Lab0: Calendar===== If you get stuck, be sure to view the [[https://wiki.eecs.yorku.ca/project/eiffel/videos:start|Instructional Videos]]. For Lab0 below (Calendar example) view accompanying Video [[https://youtu.be/woVYZsVV8F8|here]] ====== First Project Using the IDE ====== **Precondition**: Study how to to use the EiffelStudio IDE, add the ESpec library, change the root class, add clusters and classes, and write tests. If you have met the above preconditions, you should be able to start a new Eiffel project from scratch. Start Eiffelstudio, and setup a new project "calendar" as shown in the steps below: ===== Step1: Create a new project ===== Create a new ''calendar'' project at the terminal: [[:eiffel:starter:|Eifflel 18.11 Void Safe Starter Project]]: red> eiffel-new New Eiffel void-safe project name: calendar red> ls calendar Check your directory structure to see that the file system mirrors the cluster hierarchy. calendar ├── calendar.ecf ├── model │   └── calendar.e ├── root │   └── application.e └── tests └── test.e The new project is in the folder ''calendar''. estudio18.11 calendar/calendar.ecf& Also, take a look at the Settings and the XML/ECF file to see the Void safe settings. To add a new cluster or class see [[/eiffel/faq/cluster|FAQ: Adding a new cluster/class]] ===== Calendar Class ===== The start of a Calendar class might be as follows: {{ :eiffel:hello:hello2:calendar1.png?600 |}} Note that the query has a precondition, and calls another query to calculate the leap year: {{ :eiffel:hello:hello2:calendar2.png?600 |}} The leap year calculation also has a postcondition. Also note the indexing clause. Apply the **self-documentation principle** by giving meaningful names, preconditions, postconditions, invariants etc. **Note**: the implementation of the leap year query may not be correct. Does it satisfy the postcondition? In the Gregorian calendar (established in 1582) we add a Leap Day on February 29, almost every four years. Three criteria must be taken into account: The year can be evenly divided by 4; If the year can be evenly divided by 100, it is NOT a leap year, unless, the year is also evenly divisible by 400. Then it is a leap year. This means that in the Gregorian calendar, the years 2000 and 2400 are leap years, while 1800, 1900, 2100, 2200, 2300 and 2500 are NOT leap years. Instead of the informal English description, the postcondition is a precise mathematical specification of the leap-year query. ===== ESpec Unit Tests ===== Try the following tests {{ :eiffel:hello:hello2:test.png?650 |}} Test ''t0'' is a Boolean query whereas test ''t1'' is a command (a violation case). Make sure you know the difference. Note that a boolean test must terminate with Result true, but you can also add some asserts along the way. In addition to the ''comment'', you can also apply additional documentation via ''sub_comment''. ===== The Root Class APPLICATION ===== The Root class should look as follows {{ :eiffel:hello:hello2:root.png?500 |}} The root class inherits from ES_SUITE. (You can also let the root class inherit from ES_TEST, and add the tests in the root class). We can then add further classes with other tests. ===== Testing feedback in the browser ===== {{ :eiffel:hello:hello2:espec.png?400 |}} Ensure that you get the above feedback. **Question**: How many tests must you write to ensure than you are calculating the leap year correctly? Here is another question. Suppose wee add another violation test t2: {{ :eiffel:hello:hello2:violation.png?500 |}} This results in a red bar{{ :eiffel:hello:hello2:violation2.png?400 |}} Why? ===== Additional features, design and class invariant ===== We wish to add additional features such as advance the date to tomorrow and next week, and change the date to yesterday and last week. We may also want to calculate the number of days between two dates. The user will have to keep adding arguments to commands ''tomorrow(a_year, a_month, a_day:INTEGER)'', ''yesterday (a_year, a_month, a_day:INTEGER)'' etc. **Is there a better design?** One that avoids all those arguments evert time we wish to change the date? How about the following: {{:eiffel:hello:hello2:calendar3.png?500|}} Note that the invariant constraints dates to the potentially allowable range, but a feature ''is_valid_date'' is still needed to check that the actual date is allowable given leap years etc. * Add all the new features * Add union tests for the new features * How can we compare two dates? ===== Using the debugger ===== When tests fail, it is essential to be able to use the debugger to track down the error. [[https://www.youtube.com/watch?v=X2L_gyB0eAU&index=5&list=PLGoQo5eIwvcBYwWdMleIk5PU4n7lVnk-E|Using Estudio Debugger]] This is part of a series of instructional videos: [[https://wiki.eecs.yorku.ca/project/eiffel/videos:start|Eiffel instructional videos]] ===== Abstraction ===== Wikipedia defines abstraction as follows: "In software engineering and computer science, abstraction is a technique for arranging complexity of computer systems. It works by establishing a level of complexity on which a person interacts with the system, suppressing the more complex details below the current level. The programmer works with an idealized interface (usually well defined) and can add additional levels of functionality that would otherwise be too complex to handle. For example, a programmer writing code that involves numerical operations may not be interested in the way numbers are represented in the underlying hardware (e.g. whether they're 16 bit or 32 bit integers), and where those details have been suppressed it can be said that they were abstracted away, leaving simply numbers with which the programmer can work. In addition, a task of sending an email message across continents would be extremely complex if the programmer had to start with a piece of fiber optic cable and basic hardware components. By using layers of complexity that have been created to abstract away the physical cables and network layout, and presenting the programmer with a virtual data channel, this task is manageable." Beck's map of the London underground is a wonderful example of abstraction, in which irrelevant details have been suppressed and only the relevant information to use the underground is described: {{:eiffel:hello:hello2:beck_map.jpg|}} ==== Abstraction in the Calendar program ==== How can we write the contracts for additional features such as ''tomorrow'', ''yesterday'' and the number of days between any two dates? What about if awe want to convert one calendar date (say the Gregorian) to a Julian date, or a Persian date? This is where a good abstraction can greatly simplify the code and its specification. In Calendrical Calculations, Nachum Dershowitz et. al (Cambridge), provide an abstract model of dates as a sequence of integers ..., -3, -2, -1, 0,, 1, 2, 3 ,.. When introducing any new calendar (say the ISO calendar) all that we need is a function to convert from that calendar to the fixed days and vice versa. Here is the abstraction function for the Georgian calendar: {{:eiffel:hello:hello2:abstraction.png|}} ''g2fd'' is an abstraction function. We can now write the specification for the command ''tomorrow'' as year: INTEGER month: INTEGER day: INTEGER tomorrow do ... ensure g2fd(year, month, day) = old g2fd(year, month, day) + 1 end Here is a test case: t3: BOOLEAN local c1, c2: CALENDAR do comment("t3: test tomorrow") create c1.make (2016, 12, 31) create c2.make (2017, 1, 1) Result := c1.is_valid_date check Result end c1.tomorrow Result := c1.year=2017 and c1.month=1 and c1.day =1 check Result end Result := not (c1 = c2) and (c1 ~ c2) create c1.make (1900, 2, 28) c1.tomorrow Result := c1.year=1900 and c1.month=3 and c1.day =1 check Result end c1.yesterday Result := c1.year=1900 and c1.month=2 and c1.day =28 end With a sequence of integers as a data abstraction, converting from one calendar to another and specifying calendar features becomes much simpler. ===== Building Maintainable Software ===== See "Building Maintainable Software: Ten Guidelines for Future-Proof Code", by Joost Visser, O-Reilley, 2016. Difficult-to-maintain source code is a big problem in software development leading to costly delays and defects. In addition, it is usually frustrating working with someone else's code. The mark of a professional is the ability to develop code that others can understand and maintain. The authors provide the following guidelines for building maintainable software: {{:eiffel:hello:hello2:good-code.png|}}