Friday, January 25, 2013

SpotLight: How to use X++ Delegates in Dynamics AX 2012


Hi there,

I hope you are ready for a long and restful weekend. Certainly, I'm as this has been a tough week with lots of new challenges and lots of new learning, which is great. 

On this post I would like to point out a very interesting post about using delegates in Microsoft Dynamics AX 2012. The post was written by Marcos Calderon, who works for Microsoft as their SDE Lead. 

In his post he starts by showing us how to create a delegate in Microsoft Dynamics AX 2012, then he explains what delegates are and why they are used. He also explains what Event Handlers are and their relationship to the AX 2012 AOT. 



Finally, he give us an example on how to add an event handler programmatically in X++, and how to publish the subscriber into the same tier for later use.

From the post:

"...X++ delegates expose the publisher -subscriber pattern where a delegate defines a clear contract in a publisher class. This contract is used when an event occurs where the event can be a change of state, where all interested classes receive notification that the event has occurred."

You can access his post from here.

Well folks, that's all for now and until the next post!



Monday, January 14, 2013

Get Product Attribute Values in AX 2012 - Let's Code!





Hi There,

I hope that your weekend went OK and that you are ready for another interesting article about AX 2012.

Today I wanted to talk a bit about Product Attributes in AX 2012. As we all know by now, with the introduction of AX 2012 things got a little bit more complicated when dealing with Product Categories and Attributes. 

Categories in AX2012 are used to classify products, customers, and other type of data for reporting and analysis. In addition, each category must have a parent , and child elements (you can learn more about it here).

On the other hand, Product Attributes in AX 2012 focus on the details that we want to maintain for certain products. Before you can create a product attribute, you must define an Attribute Type. Now the great thing about product attributes is that we can assign them from different modules of AX 2012, and the attribute will belong to that module only and not other (you can learn more about it here).

When trying to get a Product Attribute Value for a Product in AX 2012, it is important to understand that there are three main tables involved.

 EcoResProductAttributeValue
 EcoResAttribute

 EcoResValue 

The following code will help you get the Product Attribute Value:

public static AttributeValueText getItemIdAttributeValue(RefRecId _product)
{
    EcoResProductAttributeValue ecoResProductAttributeValue;
    AttributeValueText          attributeValueText;
    InventTable                 InventTable;
    EcoResAttribute             ecoResAttribute;
    EcoResValue                 ecoResValue;
    ;


    //We only query a level down the inventtable and just used the InventTable.Product RecId as a reference for ecoResProductAtributeValue


    while select ecoResProductAttributeValue
        where ecoResProductAttributeValue.Product == _product
            join Name from ecoResAttribute
            where ecoResProductAttributeValue.Attribute ==    ecoResAttribute.RecId
                join ecoResValue where ecoResValue.RecId == ecoResProductAttributeValue.Value
    {
        attributeValueText = ecoResValue.value();
    }

    return attributeValueText;
}


If you notice, the only parameter we need in the example above is the Inventory Table Product Reference in order to find the correct value within the
EcoResProductAttributeValue View. 


The alternative can be to use the Inventory Table in the query as well, and it will look like this:


public AttributeValueText getItemIdAttributeValue()
{
   
    EcoResProductAttributeValue ecoResProductAttributeValue;
    AttributeValueText          attributeValueText;
    InventTable                 InventTable;
    EcoResAttribute             ecoResAttribute;
    EcoResValue                 ecoResValue;
    ;

    while select InventTable where InventTable.itemid == this.parmItemId()
        join RecId from ecoResProductAttributeValue
        where ecoResProductAttributeValue.Product == InventTable.Product
            join Name from ecoResAttribute
            where ecoResProductAttributeValue.Attribute == ecoResAttribute.RecId
                join ecoResValue
                where ecoResValue.RecId == ecoResProductAttributeValue.Value
    {
        attributeValueText = ecoResValue.value();
    }

    return attributeValueText;

}


In the code above I'm using an Inventory Table Item Id and referring the selected record in the EcoResProductAttributeValue View. 


Until the next post and have a great week.




Wednesday, January 9, 2013

Spotlight - ERP Evaluation Checklist




Hi There,

I would like to share a great article about choosing the right ERP solution. 

The article was written by Jen Dorsey and she is a Marketing Manager at Microsoft. In her blog, she presents 10 point evaluation items to take into consideration when choosing and/or evaluating an ERP solution.

You can access her blog from here


From the post:

"Choosing the right enterprise resource planning (ERP) solution is a strategic investment for your company, so it's well worth your time to carefully examine your options...


...Business solutions from Microsoft feature a consistent look and feel that your people already know and work with. If they already know and use Microsoft Outlook, Word, and Excel, they will find the Microsoft Dynamics ERP user experience familiar and adopt it faster."






Until the next post!



Perform in-place upgrade to Microsoft Dynamics AX - A Summary in Pictures 2012 R2



Hi There,

I hope everyone is having a good week so far and that you are ready for another topic on AX 2012 R2. I was reading the AX 2012 R2 upgrade guide and it seems like a lot of information to process. Therefore, I thought on creating a summary of the complete AX 2012 R2 upgrade process through pictures and just a few words. As the saying says, a picture express a thousand words. 

You can download the original document here, which is a very useful guide when it comes to upgrade to AX 2012, AX 2012 Feature Pack, and AX 2012 R2.

Moving right along, An upgrade from Microsoft Dynamics AX 2012 or Microsoft Dynamics AX 2012 Feature Pack to Microsoft Dynamics AX 2012 R2 is classified as an in-place upgrade. The great thing about this type of upgrade is that it does not requires source-to-target workflow, which is when we needed to upgrade an AX 4.0 instance to AX 2009 before bringing it to AX 2012, instead the upgrade is done directly into the source AX 2012 system, so look for upgrade XPO in your AX 2012 R2 setup files. 


Create a Test System

Duplicate your existing production system to create the test system. You can accomplish this by copying a virtual machine image, or, alternatively, you can build a new system by using Setup from your legacy Microsoft Dynamics AX version, and then copying over the production database


 
Run the Microsoft Dynamics AX 2012 R2 Setup on the Test System

By running Microsoft Dynamics AX 2012 R2 Setup on the test system, you accomplish the three numbered tasks shown in the following picture.

Back up the Test System Model Store

Create a file backup of the model store. This backup is used during code upgrade of the models in the customer layer. i.e. AxUtil.exe exportstore /file:[full path of file and file name]


Back up the Test System Model Store
 
Create a file backup of the model store. This backup is used during code upgrade of the models in the customer layer. i.e AxUtil.exe exportstore /file:[full path of file and file name]



Create Development System

Duplicate the Microsoft Dynamics AX 2012 R2 test system to create the development system, which is used to upgrade customer models





Upgrade Customer Models

Customer models belong to one of the customer layers. In ascending order, these layers include the ISV, VAR, CUS, and USR layers. Code upgrade is performed by layer, meaning that each customer layer is upgraded separately, starting at the lowest layer and working up through the higher layers.




Upgrade Code on the Development System and Export the Upgraded Models

All tasks on the checklist have to be completed for each layer that contains models that require upgrade.



Import the Model Store Backup to the Development System

On the development system, import the backup of the model store that you made in the procedure “Back up the test system model store.” i.e. AxUtil.exe importstore /file:[full path of file and file name] /idconflict:overwrite



Import Upgraded Models into their Layers on the Development System

Import the upgraded model or models into the appropriate customer layers. Start with models from the lowest layer, then work up through the higher layers.



Repeat Code Upgrade for Each Layer

For each remaining layer that contains customized models, repeat the upgrade procedure, moving from the lowest remaining layer to the highest layer.



Export the Upgraded Model Store

Export the fully upgraded model store that you have created on the development system to a file. This file acts as the source of the upgraded customer models that are used to prepare for data upgrade first on the test system and later on the production system. i.e. AxUtil.exe exportstore /file:[full path of file and file name]



Import the Upgraded Model Store into the Test System

On the test system, import the model store file that you made in the procedure “Export the upgraded model store.” i.e. AxUtil.exe importstore /file:[full path of file and filename] /idconflict:overwrite



Perform Data Upgrade on the Test System



Upgrade Production System

On the production system, enter single-user model. All client users other than the administrator will be disconnected form the Microsoft Dynamics AX system at this point. This action starts the downtime window during which new business transactions cannot be processed.



Upgrade the Core Production System

Upgrade on the production system requires that you run Microsoft Dynamics AX 2012 R2 Setup on each computer in your deployment.



Upgrade AOS and Other Components

Run Setup on the production system to upgrade the core server and client components.



Perform Data Upgrade on the Production System

Complete the tasks on the checklist as described earlier in this how-to in the section “Perform data upgrade on the test system.



Upgrade Additional Server Components

When data upgrade is completed, you can complete the upgrade of server components.



Upgrade Additional Clients

Run Setup on your additional Microsoft Dynamics AX client systems to upgrade the client software.




I hope this summary can serve you well as a snapshot of the complete AX 2012 R2 in-place upgrade. There is a lot to learn with this new release and I would expect lots of customer wanting to upgrade to R2 after Convergence 2013.


Have a great rest of the week and until the next post.



Friday, January 4, 2013

Business Benefits of Microsoft Dynamics AX 2012 R2

 
 
Hi There!
 
As we all very well know by now, the release of AX 2012 R2 (You can get more informtion about AX 2012 R2 on the What's New in Microsoft Dynamics AX 2012 for Developers) came to a reality last December, and I wanted to share the four most important business benefits of this release.
 
You can access the original post here, which was written by the Microsoft Dynamics AX Product Team.
 
New functionality for Industries and Administrative Processes
  • Manufacturing: Improve manufacturing operations for process manufacturing. AX 2012 R2 introduces new capability for management of potency, traceability and product batch sequencing to help process manufacturing streamline operations.
  • Retail: Assorment management across channels in your retail operations. New multi- and cross-channel capabilities for retail organizations, including catalogue management, cross-channel workflows, and integrated sales channel management will include a new “out of the box” web storefront.
  • Public Sector: AX 2012 R2 simplifies the financial budgeting process in public sector organizations. By combining the power of Microsoft Excel with the power of the workflow engine inside of Microsoft Dynamics AX 2012, AX 2012 R2 supports new capabilities in budget formulation with workflow approvals, flexible tracking, and reporting.
  • Professional Services: AX 2012 R2 improves in the intercompany scheduling capability of project resources will specifically benefit services organization with resources and projects across multiple entities and will improve utilization of your resources.

Improve Business Insights for all Users

New and updated KPI content is offered, and updated KPIs will come with the SQL BI cubes shipped with the release. These KPIs will surface on the different role centers.

Enabling the usage of the new Power view technology (You can learn more about this from the Murray Fife's post Creating PowerView Dashboards Against Dynamics AX 2012) introduced in Microsoft SQL Server 2012. This will help users to discover new insights through a highly interactive and familiar data visualization technology.

Increase Global Reach and Simplify International Operations

AX 2012 R2 has increased the global reach of Microsoft Dynamics AX 2012 by adding localization for 11 new markets (Brazil, Czech Republic, China, Estonia, Hungary, India, Japan, Latvia, Lithuania, Poland, and Russia), extending the reach for Microsoft Dynamics AX 2012 to support 36 localizations worldwide.


Simplify the Application Lifecycle for Customers

This goes from simplifying single instance international ERP deployment scenarios up to simplifying setup and functional implementation with new and improved lifecycle services.

Also, in AX 2012R2, we’ll see:

  • The Code Analyzer that will help us analyze the performance of custom code based on rules in the design phase of an extension by customers or partners.
  • The Data Migration Framework will support import, export and migration of data to/from Microsoft Dynamics AX 2012 in the deployment phase. It will cover over 20 scenarios including customer, vendor, product, employee, BOM, open sales and purchase order data, which can be extended by partners and customers.
  • The Diagnostics Framework will assist by analyzing data collected from the installation’s servers based on rules in the maintenance phase.

It is really exciting to see all these improvements in new release, as it will add more value to customer acros the board and it will help AX 2012 R2 to be used in other countries based on the localization improvements.

Take care and until the next post!



Thursday, January 3, 2013

Create Product / Product Masters AX 2012

 

Hi There,

I hope everyone had a great new year and that you are ready for a new one full of challenges, and good things.
 
In this post I would like to discuss how to create product and product masters in AX 2012. Sometimes our requirements vary depending on the customer, and more often than not, we need to provide a dynamic option to create either a product or a product master.

So, what is the definition of these two terms?

Product: This is the simpler of the two. They do not need product dimension groups when created.

Product Master: This type must contain product dimension groups; otherwise you’ll get a run-time error at the time the EcoResService is called.

The product dimension groups can be Color, Size, Style and Configuration. In addition, you can create any other dimension group. In my example, a user created a dimension group called “Revision”, which is the chosen one for this example. This shows how flexible AX2012 is around product dimensions.

The following code takes two parameters. One is the product name (which has a custom EDT), and the product sub type (is it product or product master). Further, to achieve this we will use the following classes:

EcoResEcoResProduct_TrackingDimGroup   
EcoResEcoResProduct_Product_Master     
EcoResEcoResProduct_Product_Distinct   
EcoResEcoResProduct_ProductDimGroup    
EcoResEcoResProduct_StorageDimGroup    
EcoResEcoResProduct_translation        
EcoResEcoResProduct_Identifier         
EcoResProductService        

           
The EcoResEcoResProduct_Product_Master (http://msdn.microsoft.com/en-us/library/ecoresecoresproduct_product_master.aspx) class is in charge of creating the new Product Master, and the EcoResEcoResProduct_Product_Distinct (http://msdn.microsoft.com/en-us/library/ecoresecoresproduct_product_distinct.aspx) class is in charge of creating the Product. These records are going to be created in the EcoResProduct Table.
 
As you probably know by now, even these records exist in the EcoResProduct table, they haven’t been release to AX just yet.

Moving right along, we will be using the EcoResProductService class (http://msdn.microsoft.com/en-us/library/ecoresproductservice.aspx) to actually create the product in the EcoResProduct Table.

/// <summary>
/// Creates a new product in EcoResProduct
/// </summary>
/// <returns>
///
/// </returns>
/// <remarks>
///
/// </remarks>
/// <exception cref="Exception::Error">
/// Throws error upon Exception.
/// </exception>

 
public static void CreateEcoResProduct(ProductName _ecmProductName, EcoResProductSubtype prodSubType)
{
    EcoResEcoResProduct_TrackingDimGroup    tracDimGroup;
    EcoResEcoResProduct_Product_Master      productMaster;
    EcoResEcoResProduct_Product_Distinct    distMaster;
    EcoResEcoResProduct_ProductDimGroup      prodDimGroup;
    EcoResEcoResProduct_StorageDimGroup      storDimGroup;
    EcoResEcoResProduct_translation          translation;
    EcoResEcoResProduct_Identifier           identifier;
    EcoResProductService                     ecoProdSvc;
    EcoResProductNumber                      lEcoResProductNumber;
    NumberSequenceTable                      numberSequenceTable;
    EcoResEcoResProduct                      ecoResProd;
    EcoResProductType                        ecoResProductType;
    boolean                                  isMaster = false;
    ;

 
    try
    {
        // create product by initializing the Service object
        ecoProdSvc = EcoResProductService::construct();

 
        // initialize the EcoResEcoResProduct object
        ecoResProd = new EcoResEcoResProduct();

     
        numberSequenceTable = EcoResProductParameters::numRefProductNumber().numberSequenceTable();


        lEcoResProductNumber = NumberSeq::newGetNumFromId(numberSequenceTable.RecId).num();
        ecoResProductType = EcoResProductType::Item;
      
        if(prodSubType == EcoResProductSubtype::ProductMaster)
        {
            isMaster = true;


            //Create a new product master
            productMaster = new EcoResEcoResProduct_Product_Master();

 
            //initialize product master
            productMaster.parmDisplayProductNumber(lEcoResProductNumber);
            productMaster.parmProductType(ecoResProductType);
            productMaster.parmSearchName(_ecmProductName);
           
            productMaster.parmVariantConfigurationTechnology(EcoResVariantConfigurationTechnologyType::PredefinedVariants);

 
            //create a product master Translation Object
            translation = productMaster.createTranslation().addNew();

 
            // create a new identifier object
            Identifier = productMaster.createIdentifier().AddNew();

 
            // Create the ProductDimensionGroup
            prodDimGroup = productMaster.createProductDimGroup().addNew();
            prodDimGroup.parmProduct(lEcoResProductNumber);
           
            prodDimGroup.parmProductDimensionGroup('Revision');

 
            // Create the StorageDimgroup object
            storDimGroup = productMaster.createStorageDimGroup().addNew();
            storDimGroup.parmProduct(lEcoResProductNumber);
            storDimGroup.parmStorageDimensionGroup("S-W-L");

 
            // Create the TrackingDimGroup object
            tracDimGroup = productMaster.createTrackingDimGroup().addNew();
            tracDimGroup.parmProduct(lEcoResProductNumber);
            tracDimGroup.parmTrackingDimensionGroup("none");

        }
        else
        {
            // Create a new product distinct master
            distMaster = new EcoResEcoResProduct_Product_Distinct();

 
            // Take the newly created and initialize ProdMaster - variable and fill with product data
            distMaster.parmDisplayProductNumber(lEcoResProductNumber);
            distMaster.parmProductType(ecoResProductType);
            distMaster.parmSearchName(_ecmProductName);

 
            // Create a translation object
            translation = distMaster.createTranslation().addNew();

 
            // Create a new identifier object
            Identifier = distMaster.createIdentifier().addNew();

 
            // Create the StorageDimgroup object
            storDimGroup = distMaster.createStorageDimGroup().addNew();
            storDimGroup.parmProduct(lEcoResProductNumber);
            storDimGroup.parmStorageDimensionGroup("S-W-L");

 
            // Create the TrackingDimGroup object
            tracDimGroup = distMaster.createTrackingDimGroup().addNew();
            tracDimGroup.parmProduct(lEcoResProductNumber);
            tracDimGroup.parmTrackingDimensionGroup("None");
        }


        // fill the translation object
        translation.parmDescription(_ecmProductName);
        translation.parmLanguageId('en-us');

 
        //translati
        translation.parmName(_ecmProductName);

 
        // fill the identifier
        identifier.parmProductNumber(lEcoResProductNumber);

 
        // add the product to ecoResProd
        if(isMaster)
            ecoResProd.createProduct().add(productMaster);
        else
            ecoResProd.createProduct().add(distMaster);

 
        // create the product using service
        ecoProdSvc.create(ecoResProd);

    }
    catch(Exception::Error)
    {
        throw Exception::Error;
    }
    catch(Exception::Deadlock)
    {
        retry;
    }
    catch(Exception::UpdateConflict)
    {
        if(appl.ttsLevel() == 0)
        {
            if(xSession::currentRetryCount() >= 4)
            {
                throw Exception::UpdateConflictNotRecovered;
            }
            else
            {
                retry;
            }
        }
        else
        {
            throw Exception::UpdateConflict;
        }
    }
}




Happy New Year and until the next time!




Monday, December 31, 2012

Happy New Year



Hi there!

I just wanted to take a few minutes and wish everybody in our community a happy new year filled with success, health and happiness.

For me, 2012 has been a great year. It has been full of new experiences that lead me to become a better person and also a much sharper professional. I'm grateful about all that I went through, and the people I met that helped me grow.

Next year is full of challenges for all of us, and hopefully, they will make us grow again and help us become better consultants and human beings.

Be safe and until next year :)

Eduardo.

Friday, November 9, 2012

Why a resurgence in US manufacturing may be the next big bet?

 

Hi There,

I wanted to find the time this week to discuss and share my thoughts about the manufacturing sector here in the US. I think this is an important topic as it concerns our nation economic growth, but also it can have a positive/negative impact for many ERP consultants, and Microsoft Dynamics AX implementers.

I found an excellent study about this and after reading it, I do see the manufacturing trend being positive for the US as China no longer is the cheapest and most efficient place to do this. In addition, shipping, labor, and distribution costs are rising rapidly.



In addition, the U.S. has experienced the longest stretch of employment gains in manufacturing in almost two decades. Even though our economy is growing slowly … it is growing. There have been many “green shoots” in the economy from housing to autos to manufacturing. I beleive that the U.S. has had to learn how to transition from the post-bubble, post-recession economy in a strong, sustainable way.

Form the source:

"The manufacturing sector in the US is rebounding. Is this a cyclical recovery or could it be an indication of a more sustained one? PwC looks at possible structural changes in seven key areas that could lead to a sustained recovery and help reverse the offshoring of R&D and production in the manufacturing sector.

The key factors that could impact reshoring decisions include labor, materials, transportation/energy costs, market demand, the availability of talent and capital, tax rates, and currency fluctuations."
 
 
Until the next time.
 
 

Thursday, November 8, 2012

How to Add a Financial Dimension in AX 2012


 

Hi There!

I hope everybody is having a great week and that you are ready for the weekend. Well, things in New York are not that good. First we had Sandy and just yesterday (Wednesday) we had a Nor-Easter as well! I'm pretty sure the rest of the country has suffered from natural disasters, but I think New York wasn't prepared for something this big.

Anyway, life goes on and AX2012 does too. So, I wanted to share a great post about adding financial dimensions to AX 2012. The post goes in detail on this topic allowing us to deeply understand the relationship between financial dimensions and everything else in AX 2012, and it shows us a step-by-step sequence on creating new financial dimensions in AX 2012.

You can access the post here.

Have a great weekend!




Friday, October 5, 2012

Domain Driven Design - An Introduction.

 
Hi there,

I hope everyone is having a great week and that you are ready for the weekend. I this post I would like to explore a interesting programming concept and technique called Domain Driven Design and/or Domain-Centric programming.

Let me go in more detail into this concept. Data-centric generally means that we build a system around an understanding of the data you’ll be interacting with. The typical approach is to first model a database. The second step is to then take the model (the database) and make sure that resembles the domain (the business). The third step is to take a multi-tier approach to the model and the business where the UI, business Logic and database live in different layers.

At this point you might be thinking, well, Microsoft Dynamics AX is built like this, and the answer is yes. AX, in my opinion, uses a domain driven approach as it has been build for a large number of business models. In turn, the actual business domain (a business that just purchased AX) can be coupled to AX and vice-versa.

Domain-centric design focuses on the problem domain as a whole, which not only includes the data, but also the behavior. So we not only focus on the fact that an employee entity has a First Name, but also on the fact that the entity can get a vacation, or a raise.


The tool used is object oriented programming (OOP), which relies on the power of classes and encapsulation. The idea behind domain driven design is to build a system in a manner that’s reflective of the actual problem domain we are trying to solve. This is where business users come into play. For example, they’ll help you understand how the actual system currently works (even if it’s a manual paper process. and/or existing AX process) and how it ought to work. .

Anyone who’s gone through the above knows that learning a new business is the most complicated part of any programming job. For that reason, there are real benefits to making our code resemble, as much as possible, the domain.


Essentially what I’m talking about is communication. If your users are talking about Strategic Outcomes, which a month ago meant nothing to us, and our code talks about Strategic Outcomes then some of the ambiguity and much of the potential misinterpretation is cleaned up.

Ultimately, this is the true purpose of an enterprise developer – to understand the problem domain.

 


Doing domain driven design (DDD) design doesn’t necessarily mean we have to start with modeling the domain but rather it means that we should focus on the domain and let the business (domain in this case) drive our next steps. We may agree at this point that we should start with our data model (or existing data model such a AX).

DDD extends our organizational toolbox and borrows from well-known industry patterns. For example, In AX modules help us organize a larger single model into smaller chunks.
 
In most enterprise systems there are course-grained areas of responsibility. DDD calls this top level of organization a Bounded Context.
 
Let's take workers' compensation insurance policies as an example. These need to be concerned with elements such as:
  • Quoting and sales
  • General policy workflow (renewals, terminations)
  • Auditing payroll estimation
  • Quarterly self-estimates
  • Setting and managing rates
  • Issuing commissions to agencies and brokers
  • Billing customers
  • General accounting
  • Determining acceptable exposures (underwriting)

We could incorporate all of this into a single system, but in doing so leads us to many issues down the road. Business users might understand general workflow versus a policy in the context of payroll auditing in two very different ways. If we use the same policy class, we are pushing the limitations of that class and getting away from best practices such as the Single Responsibility Principle (SRP).

Systems that fail to isolate models often fall into an architectural style called The Big Ball of Mud. Also, DDD nudges you toward identifying contexts and constraining your modeling effort within particular contexts. We can use a simple diagram, called a context map, to explore the boundaries of our system.
 
 
Source: Microsoft
 

This is why when writing the code for our model, we need to understand the domain and resemble it (a representation of the model that is) in our code. For example, let’s assume for a minute that we are doing an implementation for a car dealership and that we've talked to our client and a few salespeople, and we’ve realized that a major point is keeping track of the inter-dependency between upgrade options.


Then, in code (and remember this is conceptual and does not have to be taken to AX and/or .NET) we’ll create four classes/objects to support the theory of "-dependency between upgrade options":
 

public class Car
{
private Model _model;
private List<Upgrade> _upgrades;
public void Add(Upgrade upgrade){ //todo }
}

public class Model
{
private int _id;
private int _year;
private string _name;

public ReadOnlyCollection<Upgrade> GetAvailableUpgrades()
{
return null;
}

}

public class Upgrade
{
private int _id;
private string _name;

public ReadOnlyCollection<Upgrade> RequiredUpgrades
{
get { return null; }
}

}

public class Car
{

private Model _model;
private List<Upgrade> _upgrades;

public void Add(Upgrade upgrade)
{
_upgrades.Add(upgrade);
}

public ReadOnlyCollection<Upgrade> MissingUpgradeDependencies()
{

List<Upgrade> missingUpgrades = new List<Upgrade>();

foreach (Upgrade upgrade in _upgrades)
{

foreach (Upgrade dependentUpgrade in upgrade.RequiredUpgrades)
{

if (!_upgrades.Contains(dependentUpgrade)
&& !missingUpgrades.Contains(dependentUpgrade))
{

missingUpgrades.Add(dependentUpgrade);

}

}

}

return missingUpgrades.AsReadOnly();

}

}


As you can see in the above code, we first implemented the Add method. Then we implement a method that allows us to retrieve all the missing upgrades for a specific car. The code should reflect all concepts exposed by the model. Classes and methods should be named according to the names defined by the domain.

Furthermore, associations, compositions, aggregations and sometimes even inheritances should be extracted from the model.  Sometimes, during implementation, we realise that some of the domain concepts discussed and added to the model don't actually fit well together and some changes are necessary. When it happens, we should discuss the problems and/or limitations with the domain experts and refactor the domain model in order to favour a more precise implementation, without ever distorting the business significance of the design.

Ultimately, the code is the most important artefact of a software project and it needs to work efficiently. Regardless of what many experts in the subject say, code implementation will have some impact on the design. However, we need to be careful and very selective about which aspects of the code can influence design changes. As a rule, try as much as we can to never let technical frameworks limitations influence our design, but as we know, every rule has exceptions.
 
Again, the code above is just conceptual for argument's sake, and it is a good exercise for now to highlight how we might get started and what that start might look like. The main idea behind the above code is that "simulates" the business need.

Becoming proficient with object-oriented programming is not an easy task. I believe is within the reach of most people, but it takes dedication, book learning, and practice. It also helps if you adopt an attitude of craftsmanship and continual learning.

Well folks, I hope you found this article interesting, and that it has helped you in any way to remind you of the basics of programming.

Until the next time.