This will be the last week of me being a part of this group development team. So I will be completing my last few implementation, alongside with integration tests.
First and foremost, I will need to solve issue that I mention last week, where item.StockQuantity being negative. It is not wrong but it is least wanted situation to happen in real world. To handle this situation, we came up with an idea to force throw new DbUpdateException(). Hence, Implement try catch statement in ViewModel class to prompt a selection dialog using the error thrown (parameter = e.Message). In the dialog box, system users are given two options, "continue" or "cancel" on their consent that item.StockQuantity will be update as negative value if they would have pick "continue".
Next, I wrote few tests in service class and ViewModel integration tests. Service tests is mainly to test out if the transaction I about to implement would commit changes successfully and rollback if there is database update errors. While, ViewModel integration tests is to determine if dialog would be prompt upon error thrown and their behavior works correctly upon user selection.
Implementation is achieved by me using two variable to control the if else statement below:///transaction///
///Codes that check if stockQuantityNegative is true or false///
if (stockQuantityNegative && rollback)
{
throw new DbUpdateException("Stock Quantity for item {id} will be negative.\nDo you want to continue?");
}///rollback or commits transaction//////end of transaction///
Initially Ready To Pick method in ViewModel would called as such _service.ReadyToPickVM(parameters, true). In service/repository class, method is ReadyToPickVM(Parameter parameters, bool rollback). As initial ReadyToPick function deemed rollback to be true, the system would check if stockQuantityNegative is true to meet requirement above. If the statement do meet, system will prompt error and rollback all changes. Dialog will prompt on UI, _service.ReadyToPickVM(parameters, false) will be triggered if user clicks “continue” and save item.StockQuantity as negative value; else the system will not do anything after rollback.
After implementation is done, I make sure the tests passes. I alter few logic and in implementation and tests, making sure it is good to go. I then push my latest code to repository and marks the end of my participant in this team.
Last but not least, special thanks to my supervisor Peter for allowing me being a part of this group development team!
Variables Value Change According to “Ready To Pick”
In my implementation, Ready To Pick works as a signaling mechanism to let other module know when they could access the sub data in current module. As I working with Ready To Pick function previously, there is new implementation to add on upon clicks on Ready To Pick button.
First of all, in order to press “Ready To Pick” or “Undo Ready To Pick”, we will select a data/item set for example. In this item set, there is multiple list of item will it’s own attributes. Given availableItem and standbyItem as item’s attributes, new implementation is to alter value of attributes by incrementing or decrementing the value upon status of isReadyToPick (bool). Implementation must alter all the value for each item available in item set adding/subtracting itemQuantity.
i) Clicking “Ready To Pick” button when isReadyToPick = false, would change it to true and alter attributes value such as below:foreach (item in itemSet)
{
item.availableItem -= item.itemQuantity;
item.standbyItem += item.itemQuantity;
}
ii) Clicking “Ready To Pick” button when isReadyToPick = true, would change it to false and alter attributes value such as below:foreach (item in itemSet)
{
item.availableItem += item.itemQuantity;
item.standbyItem -= item.itemQuantity;
}
To avoid infinite increment or decrement, implementation is done in a transaction, to make sure the logic rollback if there is error. By using transaction, all value changes for isReadyToPick(bool), availableItem(int), standbyItem(int), itemQuantity(int) will be reverted upon any update failure.
Few tests is done to assert value change of availableItem(int), standbyItem (int). Tests assertion pass after “Ready To Pick” button is triggered, the value of attributes add or subtract value of itemQuantity.
After the implementation done, I shall continue implementation logic for situation when item.availableItem -= item.itemQuantity appears to be negative value.
Disable Controls and Make Controls Read Only To Prevent Updating Altered Data in View Mode
To begin the week, I will be fixing bug in Service class by refactor small changes on implementation. My objective is changing Read() to Get() on certain variable in update method. As this variable only has existing Read function, I then added Collection<Variables> GetVariables in Repository class. Hence, I change ReadVariables() to GetVariables() for update/edit/delete and any function that will make changes on the value of this variable.
In the progress, we bump into an issue, where we still able to input despite in detail view mode. This is a serious bug, as any changes would be updated/saved when ReadyToPick is triggered. Thus, we came up with a idea after discussing the issue. I need to set all input/controls to IsReadOnly and disable them. In order to do that, I need to alter code in DetailView XAML class and add new properties in DetailViewModel class.
As an alternative, I add IsEnabled = "{Binding IsControlEnabled}" and IsReadOnly= "{Binding IsControlReadOnly}" for relevant controls. While in DetailViewModel, I introduced two properties which is IsControlEnabled with default value true and IsControlReadOnly with default value false. I then perform logic of IsControlEnabled = false and IsControlReadOnly = true under view mode, making user unable to make changes on all controls.
However, there is a grid data textbox, buttons and combo box that is not set to disable & read only simply by using above method. It happens that I need to link it to ancestor of data grid such as below:i) IsEnabled="{Binding DataContext.IsControlEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
ii) IsReadOnly="{Binding DataContext.IsControlReadOnly, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
After code is altered, system user could use ReadyToPick without able to edit them in view mode. (In edit mode, user able to make changes but ReadyToPick button is disable). Hence, the bug fixed.
Fix Overall Bug in Repository and View Model Class
First and foremost, I start the week by removing duplicate integrations tests. Then, fix failure tests on repository test class as all of it failed. It is fix by adding test_server config.xml file to map towards database. However, few tests on UOM (unit of measurement) failed. As the test class is testing actual database tests. Direct initialization is required to ensure function run throw the references, variable able to reach and store directed value.
Next, I have problem with state machine in the system. Upon deletion of selected data, the system would prompt error of state machine. State.DeleteTrigger() is not implemented to go to correct state next. Thus, the only way is to remove State.DeleteTrigger(). By removing State.DeleteTrigger(), the state machine would move from State.SelectedTrigger() to State.DeselectTrigger(), which is logical flow as mapped in State Machine class.
Repository class only handles database code which is CRUD command towards database. Thus, move business logic that wrongly implemented in repository class to Wrapper Service/View Model class. After moving those logic away from repository class, the code in repository is more tidy.
Last but not least, I find it weird that system does not prompt error under a concurrency situation when It suppose to. I ran through the system once and I found out problem occurs at my status checker from last week’s implementation. The value of _selectedStatus is set to SelectedStatus.Normal, which will constantly get latest data to update the list before I save any changes. if (_selectedStatus == SelectedStatus.Normal)
{
_selectedStatus = SelectedStatus.Selected;
_eventAggregator.GetEvent().Publish(id); //Get Latest Data
}
Hence, database update is smooth as if there is no concurrency situation. But it will make user think they did not make any changes, if both before and after value appears to be the same. To solve this, I define _selectedStatus == SelectedStatus.Selected before I request to save changes upon editing selected data, so that it does not pass through get latest data event.
Status Checker To Control System Flow
As we have more implementation in our ongoing project, more and more criteria we need to take care in our system. That includes business logic, flexibility of system, and system flow. Our topic is about managing system flow.
As what you should know, I am implementing function to getItemData() everytime I select an item in list. However, when I select an item, it trigger selected event that would call event1, which event1 would call selected event, forming an infinite loop. I then figure out some idea to handle this situation as I saw my supervisor’s existing code implementation.
To achieve my my implementation, I have to add a custom status checker to control the flow of system. Below are code for my status checker:private enum SelectedStatus
{
Normal,
Selected,
}private SelectedStatus _selectedStatus = SelectedStatus.Normal; //declare default value of SelectedStatus
public void SelectedEvent
{
if (_selectedStatus == SelectedStatus.Normal)
{
_selectedStatus = SelectedStatus.Selected;
_eventAggregator.GetEvent().Publish(id); //call event1 that cause loop
}
else
{
//logic//
_selectedStatus = SelectedStatus.Normal;
}
}
When Event1 callback to current function, _selectedStatus would now be SelectedStatus.Selected and will not publish another event to cause infinite loop. At the same time, I am able to get latest item data each time I select the data. My intention of getting latest item data is to ensure I can update data changes and minimize concurrency situation.
In future, if there is more features to add on, we can always add few more variable in SelectedStatus. This way, It provide more alternative for us to control/restrict our system flow.
Trying out Domain Event
As the system implementation getting bigger, It may be hard to spot/fix important function. Therefore, we came up with an idea of using Domain Events to organize each function explicitly. As you may know, domain event is a simple class that constitute event in domain.
For the understanding, I go through some example and article regarding domain events. After that, I try out the implementation on my actual project. As my project is using Unity container, It is a bit differ from most examples on the internet (mostly structure maps). With few trials here and there for unity, my wrapper service class does directed to the event class, however it skip the event handler. Thus, nothing is trigger upon the button that I clicked and error prompted.
I then proceed the implementation based on various example that uses structure maps. After setting up the implementation, same thing occurs. Despite altering multiple declaration, system still unable to run as what we wanted. Even though it is said to be a great organized implementation, but it is still hard for me on how to implement domain event. In conclusion, domain events is yet suitable for me to apply in my actual project, thus, I have to look into other options available.
Remove File from Git Repository History
As I my implementation goes on, I push few commit upon my progress to bitbucket origin/develop branch. However, there is files/class that I want to remove from previous commits. After search up the internet, I get to know that git rm "filesname" command in new commit will not completely remove it from previous commits. Thus, after referring to my supervisor, I get to known there is a way to remove those files, which is by rebase and rewrite history of commit.
Beside, fix IsReady happens to have bug when I close and reopen the form. Given that I faced this situation quite often, I know that the bug is due to event aggregator is not unsubscribed during OnCloseDialog(). Thus, I just add a unsubscribe function and dispose the event for IsReady‘s view model class.
Lastly, I also add try catch statement and dialog when updating/creating data. This, is to notify user if there is error when updating changes onto database. I also add in new logic for IsCancelled in my repository class.
Row Version Update Upon Saving & The Importance of Clean Code
As my supervisor plan to print details in the system, I am required to and in new attribute in my current context. This attribute would actually be printed and customizable according to liking.
Next, rowVersion of current context won’t update whenever the changes is made in sub attribute. Therefore, I am required to add attribute “ModifiedDateTime” with attribute type of datetime. This attribute is used upon save button been clicked. Whenever a new/existing set of data is updated, ModifiedDateTime would update the latest date and time to the database, thus update the rowVersion.
Alongside of these implementation, I by accident altered my code. Which the alteration cause failure of updating ReadyToPick in my context. Thankfully I did commit my code frequently, hence, I am able to track my changes and revert it to working implementation.
I read through a few pages of Clean Code by Robert C. Martin. I found one interesting topic that more or less related to me which is about Bad Code. Many implemented application/system went down due to bad code. Bugs appears all over the system, crashed the system or even load time kept on increases as the system is not repaired. Major factor is mainly due to Rush, thus making big mess in code. As these mess builds, it may drag the productivity of one team. Eventually, it may cause the need of having more staff to help increase the productivity to its original phase. Which also may result more and more mess towards the project, as everyone trying to increase their productivity under pressured environment.
As the conclusion, I shall make sure my code is clean and easy to understand by others. It will bring benefit towards future me or other team member that is working on the same project. Therefore, Repairing, maintaining or adding implementation can be a lot more efficient.
Implement WrapperService class & Retrieving Other Modules
Adding new attribute “isCancelled” to my ongoing project code. It is a simple checkbox with type of tinyint(1) and logic is validate in boolean. After adding the checkbox, I proceed with fixing initialization on various test class to ensure all tests pass the assertion.
Next, Implement WrapperService to manage multiple transaction for my current module. To support my implementation, I need to reference some context from multiple modules. Therefore I need to retrieve latest implemented modules that is needed in my WrapperService class.
As I am currently working on the project in a group of three. Each of us will works on our own modules. However, there is time we need to use element/attribute from other modules. Hence, we use git to retrieve and merged commits to keep my code at latest version. Sometimes it can be hard, combining latest code from origin git repository and ongoing code might cause few issues. Issue such as refactored variable name, overloading and missing function situation might occurs. Thus, I will need to refactor those code and discuss on which function to be maintain/removed.
Refactoring code based on Integration Tests
There is few thing had been done, as shown as below that involve Test-Driven Development (TDD):
As some of my repository integration tests failed, I then refactor/alter my existing implementation of updating database from ReadData to GetData. ReadData in repository class has AsNoTracking(), where entity will not be tracked. When we make changes on the entity and will not be updated anyhow after calling context.SaveChanges(). By changing to GetData which allow entity to be tracked and any changes will be updated upon context.SaveChanges(). It also make sure latest data been retrieve after they are changed.
There is many repository test been done such as should add new, should update, should remove, should throw error, should roll back. I make sure these context integration tests passes and proceed to ViewModel classes tests. Following tests is mainly to make sure my implementation works fine under multiple scenario.
Most existing ViewModel integration tests failed as refactor of initialization is needed. ViewModel tests passed after few initialization, however there is few test involving DialogServiceMock failed to launch action of dialog in ViewModel class upon debugging. Despite that, the particular scenario works well when I run the application. Therefore, I need to figure out the factor behind failure of my test.
