Saturday, September 4, 2010

Quick Dive into Parsley (Intro - Why Parsley? - Part 1)

   This is a series of articles that should help you get you up and running with Parsley quickly.  It starts with the basics and moves up to more advanced features.  If you are new to Parsley or with to find out how to use Parsley in and MVC implementation, you came to the right place. 

  Here is an index of the Parsley posts and examples with source that you will find:
Why we like Parsley: This note.
Parsley Basic Concepts: http://artinflex.blogspot.com/2010/09/quick-dive-into-parsley-parsleys-basic.html
Basic Injection Example: http://artinflex.blogspot.com/2010/09/quick-dive-into-parsley-basic-injection.html
Basic Messaging Example: http://artinflex.blogspot.com/2010/09/quick-dive-into-parsley-basic-messaging.html
Basic Messaging with Flex Events Example: http://artinflex.blogspot.com/2010/09/quick-dive-into-parsley-messaging-with.html
Nested Contexts & Object lifecycle methods: http://artinflex.blogspot.com/2010/09/quick-dive-into-parsley-nested-contexts.html
Decoupled Bindings: http://artinflex.blogspot.com/2010/10/quick-dive-into-parsley-decoupled.html
Dynamic Commands & Dynamic Objects: http://artinflex.blogspot.com/2010/10/quick-dive-into-parsley-dynamic-command.html
Automatic Component Wiring: http://artinflex.blogspot.com/2010/10/quick-dive-into-parsley-automatic.html
Fast Inject (Injection without Reflection): http://artinflex.blogspot.com/2010/11/quick-dive-into-parsley-fast-inject.html
Presentation Model in Parsley (MessageInterceptor): http://artinflex.blogspot.com/2010/11/presentation-model-implemented-in.html
Presentation Model with multiple forms in Parsley: http://artinflex.blogspot.com/2010/12/presentation-model-with-multiple-forms.html

Why Parsley?

A little background on how and why we chose to use Parsley in our projects.

    I'm a developer who ran into Flex some years back and fell in love with it.  As usual, the quest for finding better ways of doing things is always on, and as projects grow in size this becomes even more important.  A while back I heard about the MVC Architecture pattern, and in larger projects this makes sense.  In brief, MVC is a software engineering design pattern, that involves separating the Model, the View, and the Controller, with the goal of being able to develop, deploy, and test your Components individually (generally called decoupling).  You can get a much more detail explanation of the MVC concept in Wikipedia (http://en.wikipedia.org/wiki/Model View Controller), but in a very simplified fashion, the View is the collection of User Interface elements, the Model is the collection of classes that hold and manipulate your data, and the Controller is the collection of classes that receive input and proceed to either make calls to Model Classes, or Services to load data into the Model.  The idea of separating all three is actually a good idea, you will be surprised how much time you will save by doing this as projects grow.  The main goal is to decouple your objects.  The idea is that every object should do its own thing, and only its own thing.  Decoupled objects benefit from being more easily reused in other projects or even within the same project because they are not tied to a specific implementation, also they are more easily tested individually (Unit Testing), since you (the developer) makes sure that it does what it is supposed to do, regardless of where or how it is implemented.  The drawback of highly decouple applications is that it's a bit harder to follow the whole application logic, as it's no longer obvious.  Simply put; your application becomes more "event driven" and easily become more asynchronous, which leads to having no control of when exactly the methods will be called.

  Now MVC is a pattern, not a framework.  There are multiple frameworks that have been created to help you follow the MVC pattern, and one of the most known in the world of Flex is called Cairngorm  (http://sourceforge.net/adobe/cairngorm/home/).  Cairngorm is one of the original frameworks aimed to assist the developer in following the MVC pattern.  You do not need a specific framework to do so, but they do help.  When I started using Cairngorm, I really enjoyed the benefit of using it as the projects grew in size.  Cairngorm is one of the most popular MVC frameworks for Flex, probably because it is officially back by Adobe, and it's been around longer.

    A lot of people will bash Cairngorm for some of the ways it handles things, particularly for its implementation of the ModelLocator.  Cairngorm uses Singletons, a single instance of a Class (which could also be called a Global Variable), to hold some of its objects.  Regardless of its "incorrect" way of implementing things, it's actually useful.  Cairngorm promotes the use of a specific structure, which makes team collaboration easier, and as much as people could call its ModelLocator an atrocity, it's actually handy in many cases.

  A simple example:  Let's say that you have an application that allows users to Log In.  But being logged in is not a requirement in every area of your application.  Once the user has logged in, you probably want to hold the state that the user is logged in and the session id.  Now, you add some feature that requires the user being logged in, so the component has to check if the user is logged in before it lets the user access that feature.  Using regular dependency injection, involves passing the logged in status information all over the place, just in case one of the subcomponents requires access to that information, even if the parent's don't really care.  With Cairngorm's ModelLocator, that's not the case, because if a subcomponent needs the logged in status, it doesn't need to get it from its parent, it can just reach and grab it.  This will uncouple all the component's that don't need this information from this particular implementation, which is good, cause you can reused them more easily.  They don't need to carry data around that they don't need, simply because one of their children or grandchildren might need it.
    So if this is good, why do people "hate" it so much?  Well, the problem is with the "reach and grab it", particularly with the "reach".  Although some decoupling is accomplished using Cairngorm, the component's that needs to "reach" now gets coupled and tied to that particular implementation of the ModelLocator, and doing unit testing become much more difficult.

  That said, the main reasons we decide to leave Cairngorm follow:
  1. Cairngorm is heavily dependent on binding, which is useful in many cases but can get annoying.  Under Cairngorm , the Controller makes a Service call, and feeds the Model through Commands.  But let's say that the user request some data, and when the service call returns it turns out that there are no records that match that search, so nothing will be added to the Model.  Since the View is bound to the Model, the view will usually refresh when new data arrives, but if there is no data added, well it won't refresh, there is no change.  It's a nice feature to let the user know that no data was found, but the view will simply not know this.  You could of course create a popup from the Command letting the user know that that no data was found, or you could set a flag in the model that the View is "watching" to raise the issue and display the message.  The popup approach I don't like because you are moving elements of the View to the Command which breaks the pattern, but more importantly, still the view doesn't know that there is no more data and can't adjust because of it.  Setting a flag would be the one "correct" approach, but this adds a lot of logic for a simple thing.  Why a lot of logic?  Well, first you need to add a property change watcher (ChangeWatcher.watch()).  But property change watchers in Flex lead to memory leaks if you don't remove them before the item is destroyed (ChangeWatcher.unwatch()).  But Flex doesn't have "Destroyers" that get called before your object get's destroyed.  Since it's a view, you can use the removedFromStage event that would be called when your item is removed.  Great!... Right?... Wrong.  See the Flex framework occasionally re-parents view components (for example when scrollbars are added) which will trigger the removedFromStage event.  So, now you are also force to monitor the addedToStage event to set the watchers back up in case they got removed during a re-parenting process.  Although this would be a "correct" approach, I simply think it's way too much of a hassle for something that simple.  You could set up an event listener tied to the Model, but you still need to remove the event listeners when your view is being removed, same long approach as with the flag, and again you couple your view even more to that model.  I, of course, hacked my way around it, setting a callback function in the event that triggers the command so that the command can notify the view directly for things such as this.  Some might argue that this breaks the MVC pattern, but there is no ONE way of implementing MVC, and it certainly accomplishes the decoupling goal in a much simpler fashion.  The only really un-debatable problem with my quick hack is that only the view that generates the event that called the command will get the message back from the command. 
  2. Cairngorm's limited decoupled messaging system. The second really important issue with Cairngorm from my point of view is somewhat related to issue #1.    Cairngorm's decoupled messaging system is aimed towards executing Commands.  All other messaging is "supposed" to be done through either binding or Flex/Flash Events, and although binding is messaging, binding is not the best way to accomplish ALL messaging.  Besides, Binding involves coupling, which is the opposite of the original goal.  You can use Flex's event mechanism, but that also means that you will go back to coupling.  Flex's Binding and Event messaging mechanism involves that you must listen to a specific object.  Although Cairngorm's messaging is aimed to aid in some issues, it is simply too shortsighted, it's basically a one way road.
  3. The Singleton.  I know I said it comes in handy, but it can become a problem.  Since the Model is a Singleton, it is shared by the whole application.  Sometimes you want to have SubModels.  Model's that are shared only in a section (context) of you app.  Or you have an application that allows the user to edit a customer's data, but suddenly the user needs to edit another customer's data, but the user doesn't don't want to close the window and "save" the changes to the other customer just yet, just open a new Customer window to work in.  Basically an MDI (Multiple Document Interface) app.  You need two models that are identical, but hold different data views.  Cairngorm will not help you here, since the models are global.  They are not within a specific scope.  You of course, can find the way around that, but it's on your own.
  4. Lack of Modularity.  Cairngorm is very friendly with RSL's, but it's not friendly with Modules.  You can use Modules, but it's somewhat limited.  This is related somewhat to issue #3.  Since Models and the FrontController are implemented with Singletons.  There is a way to make it work with modules, but keep in mind that is not how it was designed to work.  You can read about it here.

So all that said, I still think Cairngorm will help you with non-small projects, but there are "better" ways.

So I'll explain what "better" means to us.  Ideally it must be:
  • Flexible.  There is no one absolute unique "right" way of doing things.  Patters are good as long as they help you accomplish your goals.  When they start getting in the way, it's time to chose a different pattern or at least modify it.  They guys from the very successful Flick site have a saying that they "generally try do the dumbest thing that will work first."  Sometimes elegant solutions are not the best way of actually getting things done.
  • Have a powerful Decouple Messaging System.  Way beyond what Cairngorm does.  Messages should be able to be sent anywhere to anywhere in a decoupled way.  A plus is if the can be limited within a specific context (scope).
  • Allow for easily integration with Flex Modules.  This is a BIG important issue for us.
  • Aid in decoupling.  A framework that aids with achieving Inversion Of Control (IOC).
  • Simplifies Dependency Injection.  You don't need a framework to use Dependency Injection.  Actually DI is available by default in ActionScript, or just about any OO language.  The issue with DI without the assistance of a framework is that you will have to manually carry all objects around, which will work against decoupling the app.  The idea is to have the framework manage the DI, so I as the developer don't have to, achieving a much higher level of decoupling.  No singletons in the model, unless you actually want one.
  • Allow for Model's scopes or contexts.  The idea that there are Sub-models that can coexist.  (You could call them "scoped singleton's", shared only within a context (scope).
  • Allows for easy project growth.  As the project grows, it is still easily maintained, and could be easily re-factored if necessary.
  • Easy to learn, quickly to implement.

So we did a little research and came up with the following options:
  1. Make our own.  Hah hah hah.  We are a small team; we can't invest that much time, especially if there are several great options available.
  2. PureMVC.  http://puremvc.org/
  3. Mate Flex Frameworkhttp://mate.asfusion.com/
  4. Swiz Framework: http://swizframework.org/
  5. Robotlegs: http://www.robotlegs.org/
  6. Parsley: http://www.spicefactory.org/parsley/
I'm sure there must be others, but time is limited and I can't devote that much time into looking at every possible option there is.  These are the "better known" pro-MVC Flex frameworks.

Each has their positive side, and depending on your projects you might choose a different framework for different projects.  Unfortunately for us, we can't invest time into getting to know deeply each one of them.
I did however take time to look at examples and read through the documentation of all of them, looked at what people like and dislike about each one of them to decide on what to use keeping in mind the list of what "better" meant for us, considering the projects that we currently have lined up.

So I'll explain the reasons why we chose to go with Parsley for some of our projects.  I really want to stress that I don't think that any of these frameworks are "wrong", nor "bad".  They implemented similar goals in different ways which have their unique benefits, but we evaluated their features according to our goals.  Your goals will be different, so you should do your own evaluation.
  • PureMVC.  The idea is actually good.  The goal is to have a framework that works in multiple environments.  So if you code in multiple languages or use multiple platforms, it sounds good.  But to accomplish that, it must make sacrifices and not exploit the Flex's sdk as it could.  The other issue is that it uses a similar singleton approach as Cairngorm does.  So it was out of the contest quickly.
  • Mate Flex Framework.  A lot of people like Mate, and I understand why.  It nearly fills all of the requirements we were looking for.  What I don't like about Mate is its glue mechanism.  Decoupled objects eventually need to be coupled (or glued) together for your app to work.  Mate uses "Map" files that describe how to glue (couple) things together.  Map files are great in the sense that they illustrate the logic of how the app works.  So a developer new to the app, can easily catch on how things are tied together, something a bit harder in other frameworks.  So what's not to like?  Well, Map files are built using MXML, and doing logic in MXML is just weird.  I could get used to it, but what I really don't like is that Map files tie Objects/Models/Commands to properties or methods, but it does it through string variables.  This means that you will not get compiler errors, and you have to be careful when you re-factor, as to make sure your Map files also get updated.  You have to be even more careful if you use the same property name in two different components and decide to refactor one of them.  Also, I fear that as the project grows and expands Map files could grow to be a pain to maintain, as they centralize the coupling of just about everything.  I know you can distribute the Map files into several map files, but I still think it can become a pain.  I do like the fact that it doesn't require custom metatags, and it works well with modules.
  • Swiz Framework.  Swiz follows a completely different approach on how to wire (glue, couple) your objects together.  Swiz uses and Autowire feature, where objects are glued "Magically" by themselves.  Ok it's not magic, it uses custom metagags, but it doesn't require a Map file.  Actually, Parsley and Robot Legs both follow this same basic idea, where it comes to Dependency Injection.  The framework figures out what to inject based on the properties Class type.  You don't have to manually specify it, it just happens at runtime.  You might ask:  So what if I have two Models of the same Class type, although unusual, it's not a problem, it has a simple solution.  Actually the way the messaging is done is similar to Parsley's messaging.  So if Swiz and Parsley are so much alike, why Parsley?  Simply put, Parsley has more options.  Swiz frameworks messages must be Flex Events.  Parsley's can be Flex Event's but don't have to be.  Parsley is more friendly to Modules, and Parsley's lifecycle is automatically tied to the view lifecycle, which means that there is even less to worry about.  If you wish to control the lifecycle manually in Parley, you still can.  Parsley is simply more mature and more "flexible".
  • Robotlegs.  Robotlegs is the new kid on the block, and gaining lot's of momentum.  Robotlegs isn't based on Spring like most of the other frameworks.  Robotlegs also provides an implementation of (MVCS, Model View Controller + Service)  Robotlegs does DI in a similar way that Parsley and Swiz do, but messages are handled a bit different.  You use something similar to addEventViewer of Flex, but it's coupled to the framework and not the specific implementation.   It has a similar concept of Context as Parsley does, but in Robotlegs you must extend a Context class from Robotlegs.  Parsley let's you define the Context as Object in MXML or even in XML and load it at runtime.  Robot   Robotlegs includes Mediators, similar to the concept from PureMVC's mediators.  One key aspect of mediators is that they allow you to isolate the view from the rest of the application.  Basically they allow you to have little to no code in the view, and certainly no logic that ties it to the particular implementation.  If that's your goal, then you can easily to the same with the "Presentation Model (PM)" which Parsley easily supports.  Actually Flex 4 has this concept built in with the new Spark Skins, you can totally isolate the View from the logic.  But in Parsley you can certainly use PMs without spark skins, or Flex 4.  If you really have to have mediators in the PureMVC style, then you should strongly consider Robotlegs.  Which is better?  That's a matter of choice, we have started to use Robotlegs in our latest project for one specific reason:  Although Parsley does allow you to add objects to the context at runtime after the context has been created, they are treated differently, in Robotlegs, all objects are added to the context after it's been created, and treated exactly the same, that is a very particular requirement from us in our latest project.  This isn't an issue in the vast majority of projects.  In brief, you can use Robotlegs in a similar fashion as Parsley, or you can follow it's pattern inspired by pureMVC.  The key difference is that in Robot legs you configure and use the framework through ActionScript, while in Parsley it is done through Metatags, MXML and/or XML.
In conclusion:
    Parsley easily met all our original requirements.  It is very flexible, it works in Flex and in pure AS3 projects (Flex not required, although in it's latest versions it is departing from Flash), it is simple, it makes sense, it does what you expect it to do, you don't have to extend the framework, but you can if you want.  Parsley is easy and it doesn't require you to write any AS to tie things together nor to extend any of it's classes.  You don't even have to follow an MVC pattern for it to be useful.  Actually Parsley is not aimed specifically to implement an MVC pattern, it just helps you with it, and you can chose any patter that you like.

    That doesn't mean it's perfect.  Parsley uses custom metatags, which translate to issues with the compiler.  When using RSL's or Modules, you must instruct the compiler to keep the custom metatags, or it simply won't work, and worse, sometimes it will fail silently.  I guess that one thing that is debatable if it's good or bad is that in Parsley there is more than one way to accomplish the same thing, it's good because you choose what you like the most, or fits better, it's bad because it could lead to inconsistency, which could make working as a team a bit more difficult.  Flexibility does have a price, but it's a matter of coordination, and I rather have the flexibility and use it responsibly than not have it at all.

    Well, that's why we chose to use Parsley.  I will write a series of articles with examples to help you get started with Parsley, or just learn about it.  It will start with very simple examples, and move on to more complex scenarios to really show the power behind it.

Next -> Parsley's Basics

51 comments:

  1. hey frnd,
    its a nice article.
    I'm new in parsley , so need some good sample tutorials,
    waiting for such good things from u .
    abhishekchess1@gmail.com
    :)

    ReplyDelete
  2. Thanks. Currently there are two basic examples, and a couple more are on the way.

    ReplyDelete
  3. Hi, nice article. Not easy to compare all these frameworks.
    For me some important points when choosing a framework which you didn't mentionned are:
    - good documentation is a must
    - active community around the fwk through forums for help, for bug fixing, etc...

    To me, Parsley is fine for these two points.

    Jahz

    ReplyDelete
  4. Great overview with just the right amount of information and supporting reasons.

    Do you know if any of these frameworks have support for doing long client-side calculations without freezing the display?

    Matt.

    ReplyDelete
  5. @Jahz,
    They all have good documentation. Really none of them are bad around this point.
    My personal feeling is that Mate probably has the largest community, Robotlegs' forum has the benefit of being watched for by several contributors. Parsley's forum is followed by Jens (creator of Parsley) directly with a very fast response time. Other people jump in also.
    Swiss is backed up by several people also, most I think work for Universal Mind.

    ReplyDelete
  6. @Matt
    Thanks Matt,

    No I don't think that any of these support that feature. That's not their goal. But what you are asking is not simple but it isn't all to complicated.

    The big problem is that Flash is not multi-threaded when it comes to executing ActionScript code. While AS code is being executed, no events will be fired so the screen "freezes". So any framework would be limited in how much it could actually help you with.

    There are several approaches to this issue, but they all really on that you must write a function that will do the long computations, and can exit and be called again and continue with the work that is pending, and do this multiple times. You can set a timer to call this function once every 200 milliseconds for example. When the function exits, other events will have a chance to fire and other code will get executed. It's hard to know exactly how many computations to do, before it exits, but you can try it on several computers and get some idea. Just make sure it last's around 100 ms.
    Note: This approach will make the long code take longer to execute, but your users will have a much better experience.

    Adobe is seriously considering adding multithreading to Flash in the future, which would resolve this issue, but will bring a whole new level of complication to the picture. Multithreading isn't hard, but you have to be very careful with some things, otherwise you will have inconsistent results.

    ReplyDelete
  7. BTW. I'm building a quick post on the long computation solution. It should be up shortly.

    ReplyDelete
  8. Well, it took a lot longer than I hoped. I was internet less @ home for a while.

    Anyways, It's there now:
    http://artinflex.blogspot.com/2010/12/executing-long-running-tasks-without.html

    ReplyDelete
  9. Hi Art,

    I really like your Parsley series. I'm giving a talk on it at 360Flex and would like to discuss your experience with Parsley and frameworks in general.

    joelhooks at gmail dot com

    ReplyDelete
  10. Thanks Joel,

    Sure. I wrote you a couple of days ago, let me know if you didn't get my email.

    ReplyDelete
  11. Well I must say the analysis was awesome :) Even I was confused about the choice of framework but now got the idea.

    Thanks,
    Akhil Mittal

    ReplyDelete
  12. Nice stuff to go through. Thanx for sharing.

    ReplyDelete
  13. Dear Art
    you know I will always remember the name of you blog for 2 reasons:

    1- your simple and understandable explanations
    2-my son's name is Artin like your Artin+Flex

    BR
    Farid Valipour

    ReplyDelete
  14. Thank you for these very useful Parsley framework posts. I have one question about the difference between Parsley and Robotlegs. You said:

    "Although Parsley does allow you to add objects to the context at runtime after the context has been created, they are treated differently, in Robotlegs, all objects are added to the context after it's been created, and treated exactly the same."

    My question is: what exactly is the different treatment that you see for objects added to Parsley at runtime.. can you elaborate more on this point?

    Another quick question. I am trying to decide between Parsley and Robotlegs. I tried working with Parsley, but found the code snippets in the documentation not helping in some situations... I couldn't even load a configuration file at runtime... a simple task like this that I couldn't understand how to implement is the reason why I started to look for other toolkit.

    So I found Robotlegs, it was easy to follow and understand... at least there are lots and lots of examples out there... my only concern is that Robotlegs has lots of "extensions".. whatever you want to do, you can find an extension for... but when you go to the main website, you don't find those extensions nor explanations for them. Using those extensions is pretty straight forward... but what concerns me is these things that I need to add to my project while they are not official on the website.

    Its confusing...!! any help is highly appreciated. But again, the last time you posted on this blog was on 2011... not sure if this message will get to you.

    ReplyDelete
  15. Flex Application development- flexdeveloper.in is one of the top most IT organization that offers cheap and best flex development, flex java development, flex design and freelance work at affordable rate. We have a lot of client all over the world.

    ReplyDelete
  16. Replies
    1. شركة تسليك مجارى بالدمام
      شركة تنظيف بالدمام
      شركة عزل اسطح بالدمام
      شركة كشف تسربات المياه بالدمام
      شركة مكافحة حشرات بالدمام
      شركة تنظيف بالرياض
      شركة تنظيف خزانات بالرياض
      شركة نقل اثاث بالرياض
      شركة تنظيف بابها
      شركة تنظيف بخميس مشيط
      شركة تنظيف شقق بخميس مشيط
      شركة تنظيف فلل بخميس مشيط
      شركة تنظيف منازل بخميس مشيط
      شركة رش مبيد بخميس مشيط
      شركة مكافحة حشرات بخميس مشيط
      شركة نقل اثاث بخميس مشيط
      شركة مكافحة الحشرات بينبع
      شركة تنظيف فلل بالرياض
      شركة تنظيف خزانات بابها
      شركة كشف تسربات المياه بابها
      شركة تسليك مجارى بالرياض
      شركة نقل اثاث بخميس مشيط
      شركة مكافحة حشرات بالطائف

      شركة تسليك مجارى بالدمام
      شركة تنظيف بالدمام
      شركة عزل اسطح بالدمام
      شركة كشف تسربات المياه بالدمام
      شركة مكافحة حشرات بالدمام
      شركة تنظيف بالرياض
      شركة تنظيف خزانات بالرياض
      شركة نقل اثاث بالرياض
      شركة تنظيف بابها
      شركة تنظيف بخميس مشيط
      شركة تنظيف شقق بخميس مشيط
      شركة تنظيف فلل بخميس مشيط
      شركة تنظيف منازل بخميس مشيط
      شركة رش مبيد بخميس مشيط
      شركة مكافحة حشرات بخميس مشيط
      شركة نقل اثاث بخميس مشيط
      شركة مكافحة الحشرات بينبع
      شركة تنظيف فلل بالرياض
      شركة تنظيف خزانات بابها
      شركة كشف تسربات المياه بابها
      شركة تسليك مجارى بالرياض
      شركة نقل اثاث بخميس مشيط
      شركة مكافحة حشرات بالطائف

      Delete
  17. افضل شركة تنظيف فلل بجدة
    شركة تنظيف مجالس بجدة
    افضل شركة نقل اثاث بجدة
    شركة نقل عفش بجدة
    شركة مكافحة حشرات بالرياض وبجدة
    شركة مكافحة حشرات بالرياض وبجدة
    شركة مكافحة حشرات بالرياض وبجدة
    شركة جلي بلاط رخام بالرياض
    شركة تنظيف مجالس بالرياض
    شركة تنظيف فلل بالرياض
    شركة رش مبيدات بالرياض
    شركة تنظيف خزانات بالرياض
    شركة مكافحة النمل الابيض بالرياض و بجدة
    شركة تنظيف موكيت بالرياض و بجدة
    شركة تنظيف شقق بالرياض
    شركة تنظيف منازل بالرياض
    شركة تسليك مجارى بالرياض و بجدة
    شركة مكافحة حشرات بالرياض
    شركة نقل اثاث بالرياض
    شركة كشف تسربات المياه بالرياض و بجدة
    شركة تنظيف بالرياض
    شركة نظافة بالرياض
    شركة رش مبيدات بجدة
    شركة عزل اسطح بالرياض
    تنظيف المسابح
    نقل اثاث
    شركة نظافة بالرياض
    شركة تنظيف بيوت بالرياض

    كشف تسربات المياه
    شركة تخزين العفش بالرياض
    شركة تخزين اثاث بالرياض
    افضل شركة دهانات بجدة
    افضل شركة مكافحة البق بجدة
    افضل شركة مكافحة صراصير بجدة
    افضل شركة تنظيف خزانات مياه بجدة
    شركة تنظيف مساجد بجدة
    شركة عزل اسطح بجدة
    شركة عزل خزانات بجدة
    شركة ترميم منازل بجدة
    شركة نظافة فلل بجدة
    افضل شركة نظافة منازل بجدة
    افضل شركة تنظيف بجدة
    افضل شركة نظافة بيوت بجدة

    ReplyDelete
  18. شركة تنظيف فلل بالرياض
    شركة رش مبيدات بالرياض
    شركة تنظيف خزانات بالرياض
    شركة مكافحة النمل الابيض بالرياض و بجدة
    شركة تنظيف موكيت بالرياض و بجدة
    شركة تنظيف شقق بالرياض
    شركة تنظيف منازل بالرياض
    شركة تسليك مجارى بالرياض و بجدة
    شركة مكافحة حشرات بالرياض
    شركة نقل اثاث بالرياض
    شركة كشف تسربات المياه بالرياض و بجدة
    شركة تنظيف بالرياض
    شركة نظافة بالرياض
    شركة رش مبيدات بجدة
    شركة عزل اسطح بالرياض
    تنظيف المسابح
    نقل اثاث
    شركة نظافة بالرياض
    شركة تنظيف بيوت بالرياض

    كشف تسربات المياه
    شركة تخزين العفش بالرياض
    شركة تخزين اثاث بالرياض
    افضل شركة دهانات بجدة
    افضل شركة مكافحة البق بجدة
    افضل شركة مكافحة صراصير بجدة
    افضل شركة تنظيف خزانات مياه بجدة
    شركة تنظيف مساجد بجدة
    شركة عزل اسطح بجدة
    شركة عزل خزانات بجدة
    شركة ترميم منازل بجدة
    شركة نظافة فلل بجدة
    افضل شركة نظافة منازل بجدة
    افضل شركة تنظيف بجدة
    افضل شركة نظافة بيوت بجدة

    افضل شركة تنظيف منازل بجدة
    افضل شركة شراء اثاث مستعمل
    افضل شركة تنظيف قصور بجدة
    افضل شركة تنظيف سجاد بجدة
    افضل شركة تنظيف ستائر بجدة
    افضل شركة تنظيف عمائر بجدة
    افضل شركة تنظيف مسابح بجدة
    افضل شركة تخزين عفش بجدة
    شركة تنظيف خزانات بجدة
    افضل شركة تخزين اثاث بجدة

    ReplyDelete
  19. Today Azizi is the best cleaning agent in the Kingdom of Saudi Arabia It is the corner company of Shorouk Corner, which is distinguished by the technical workers with great experience in the field of cleaning, pest control and transfer of mold to all parts of the Kingdom The company has a great experience in the field of cleaning work in the Kingdom.
    شركة تنظيف بالرياض


    شركة مكافحة حشرات بالرياض


    شركة نقل عفش بالرياض

    شركة تنظيف خزانات بالرياض
    شركة تنظيف بالطائف

    شركة نقل عفش بالطائف
    شركة مكافحة حشرات بالاحساء
    شركة تنظيف خزانات بالاحساء
    افضل شركة تنظيف مجالس بالاحساء
    شركة تنظيف خزانات بابها





    ReplyDelete