We have an old and big PHP application with complex business logic. Now the project almost fully consists from spaghetti-code. I plan to do a smooth migration using Symfony e.g. rewrite some features using Symfony. Also seems DDD is a good choise for the project like this. So the main idea is to make a rewriting of some features to make it more clean and easy to maintain. Any suggestions?
Thanks.
Actually the DDD principles can be applied in the context of a legacy code base refactoring. This is how we did (and are still doing it), but don't take it as a silver bullet:
Phase 1 - Strategic preparations:
1.) Use Context Mapping to identify Bounded Contexts and their integrations. Try to be agnostic towards your current architecture. This is actually very hard to do because of biases. It comes in handy if you do it with people that are no constant users of the old system.
2.) Sort the contexts by strategic value and identify your Core Domain (Where is the money?), eventually finding Supporting Sub Domains (parts of the system that support achieving your strategic goals) and Generic Sub Domains (things that are absolutely necessary, i.e. compliance and accounting).
3.) Bring Stakeholders, Developers and Product Owners together to form a common language, the Ubiquitous Language within the different Domains that capture the intents and capabilities of the business. Be dogmatic about a central dictionary of these terms, if you hear something ambiguous during discussions, resolve it and add it to the dictionary. This is an integral part of any DDD project since we are modelling the capabilities of the business, which means the code and the stakeholders language should carry the same semantics.
4.) OTPIONAL: Depending on the size and working methodologies of your organization, you might have to restructure it. Let Conway's Law work for you and create a certain feature gravity by reassigning teams and individuals to the different domains that you have identified earlier as value streams where the best and brightest should be working on the Core Domain. Enable direct communication interfaces between developers and stakeholders to work closely on specification and constantly distilling the Model.
Phase 2 - Implementation:
0.) If you have no experiences with such a complex refactoring, get external help (consultants) or hire experienced engineers that have done this before. Believe me, you will need it (I have learned it the hard way myself).
1.) Create a Bubble Context in which you are free to redesign your models and integrate it with the legacy system. There are a lot of integration patterns (you can find a nice summary of those patterns here and here. Always ask yourself if the context in question has enough strategic value and is bound to evolve over time and has to nicely respond to change in the future. In the end it is all about creating Software that is easy to change and refactor. Iterate, rinse and repeat. Always refactor the new code as early as you gain new insights from the business.
NOTE: Don't try to do too much. The Bounded Context's play very nicely as Microservices boundaries, but a lot of times people underestimate the complexities of a distributed system. If you don't have the availability and performance requirements that would require this architecture, then a well designed, modular monolith can be just the correct tool to get the stuff done.
EDIT
If you are interested in the Strategic part of DDD you MUST watch Paul Rayner's talk from DDDEU 16 here.
DDD is a set of methodologies to facilitate team communication. It has less to do with refactoring and more to do with architecture.
I don't know if this qualify for SO, anyhow the explanation would be huge. There's no "silver bullet" method here. Personally I would try to isolate components, and migrate those one by one to a or several new Symfony application(s).
DDD is not relevant there. You can find many usefull pattern/methods in Martin Fowler books, especially "Refactoring" and "Patterns of Entreprise Architecture".
Related
We are currently bringing an online business software to other EU markets, where not only language but also rules and regulations differ from country to country which made me wonder, what is the best way to implement such in a software?
The UI localization isn't really a problem - done that more times then I could care to count, but for example while invoicing countries tend to require different data (well not totally different, but different enough to make you think about it architecture wise) meaning different inputs, different validations and somewhat different handling of that data.
Which way can be considered better?
The standard way of localizing UI and adding the needed conditional statements for showing extra and hiding non-essential elements with similar conditionals in the Controller classes
Creating a copy of the app for the given country with slightly altered controllers and views (which will make the constant updates a nightmare, but the code much cleaner)
Trying to somehow create a Factory/Builder pattern around this?
While the last one sounds most reasonable to me, it frustrates me even more, as I have no clue on where to start yet. Any good pointers on that?
Language of the choice is PHP with Laravel
Definitely do not make different copies.
Have a look at your current database architecture and see how you can expand it to fulfill your requirements. Then rewrite or update the business-logic code layer of your application.
Then you will only need to make minor adjustments in the front-end.
This post is some kinda old, But the title is general and could be found by some others via search, so I wrote my answer in the following:
I think it's totally based on your architecture. In recent years, peoples are following different principles to break-down the whole application into meaningful microservices with specific tasks and boundaries. This mindset would help you to analyze the whole business process and the places that you may need to do some customization for each customer or country.
for example, for product catalog or inventory management, the processes between each country may not differ. but in the payment or order management, invoicing you need to do small modifications which would be quite easier while you are following a microservice pattern. Furthermore, you can have your own plugin loader structure which lets you modify, override and extend each instance by having a filter/hook feature in your application as you might have seen in WordPress and other opensource platforms.
At my company we have a web application that we have been developing for over 5 years. We still have a codebase that contains PHP4 and has been extended with loads of PHP5.
The LOC is pretty big, about 471k. It is not based on a framework, ORM, etc, etc.
The developers who started of with this project ignored any i18n and translations. All the language texts are hardcoded in the software. Yes, I know this sucks big time.
At the moment we're fine since we only sell this in the language the software is written in but we're also looking at expanding abroad.
I'm struggling with the best approach on dealing with the translation.
How would you guys approach this? Would it be better to rewrite using a framework since that would probably also improve the codebase and providing a solid structure. Or would you just use the current software and filter out the language texts.
Any tips and hints on this subject are appreciated!
I think both variants are possible. You can leave your code, or rewrite. But as you know rewriting is a long process, in spite of that fact you've writing it for over 5 year.
If it's still stable, works fine, and PHP4 and other 'tasty things' you don't need, you can leave and just review all hardcoded texts. i18n helpers are very easy to make. You have to do nothing more then:
Choose appropriate way of storing texts and translations
Caching mechanism for already loaded translations
Class and helper for i18n operations.
You should analyse you bussiness plan well, if you decide to rewrite you code.
Still got an additional answer. Translating almost identical strings is very costly. Multiply that with the number of languages and one realizes: a good internationalization with sharing of same strings, and maybe formats, is really more efficient.
A first rewrite of the templating part, probably makes sense. First by hand, then with an automatic conversion tool written by you. It should prepare I18N.
In my experience, it's not a good job to have a single project with two major goals - especially if those goals are almost entirely unrelated from a business point of view. I'd have one project team responsible for localization (which may well involve more than just translation - different countries have different legal requirements, currencies, payment providers, etc.), and one team for "improving the code base".
I'd start by having the localization team work out a rough plan (and cost) for "the simplest thing you could do" - retro-fitting localization functionality into the site as it is right now. Unless that cost is unacceptable form a business point of view - I'd go down that route.
If the business case for refactoring hasn't been made, I'd not try to shoe-horn it into your localization project - I've seen similar things happen before, and all the developers wanted to work on the cool refactoring stuff, talk about the relative merits of various frameworks, and which source code control system to use, while the thing the business cared about was pushed to the future; eventually, the business owners lost interest in the project, and cancelled it.
If there really is no realistic way to do the localization without a refactoring effort, I'd still run it with two, separate teams. The localization team can be a primary requirements owner for the refactoring team, and they do need to work together - but by keeping the two projects running independently, you avoid the risk that you get 90% of the refactoring done, but only 10% of the localization.
It sounds like you have more than a translation project ahead of you. If you're wanting to take it abroad, you'll have to redesign at least part of the system.
If your budget allows for it and the benefit justifies it, you'll want to step back and take a look at the overall design. Keep what you can, but don't be afraid to rip out, redesign, replace and upgrade major portions of it.
Much has changed in the last 5 years, so if it's an app that you plan on selling for many more years, it's likely worth the investment in redesign.
It depends on what the priorities are, as to what you should do.
If the main concern is the language translation, then you can start with just taking out the hard-coded strings so they can be internationalized.
If there are other needs, such as wanting to easily support different databases, then that would help determine if there is a better approach.
I have been playing around with the concept of 'module' that some mvc frameworks implement and it seems like a good solution, and also with TDD, but I think there must be something more, like a design pattern I missed (I only know a few), that will let me build applications that can grow (in code) with no limits.
Any thoughts?
edit : Another good thing about modules is that they can be built in a way that they are application-independent, so they can be reused.
In "Facts and Fallacies of Software Engineering," Robert L. Glass says:
Fact 15. Reuse-in-the-small is a well-solved problem.
Fact 16. Reuse-in-the-large remains a mostly unsolved problem.
Fact 17. Reuse-in-the-large works best in families of related systems.
In other words, you can reuse modules, but only between applications that work very similarly. Trying to make modules so versatile that you can resuse them in any application is too hard. You end up making modules that are so configurable that they're overly complex to use, and contain lots of code to handle scenarios that are of no use to a given application.
You'd be better off coding a custom module for each application, that does just what that each application needs, and no more. This is especially important for a language like PHP, where code is loaded on each request, so the volume of code has a significant impact on performance.
Reusing more fine-grained functionality is different. The uses of say, logging, is reasonably similar between applications no matter how different the applications are from one another. This is why most frameworks do really well with general-purpose service-style classes.
Re comment from #A_Var:
You can make a class reusable if you know the range of possible functionality in advance, and therefore the parts that need to be extensible. This is relatively easy for a simple class that's used similarly in every app. I mentioned the example of logging. This is what Glass refers to as reuse-in-the-small.
But we're not talking about simple classes. If you try to do the same thing with a complex module (think of multiple classes to handle multiple screens, forms, different database schema, etc.), it's too hard to write the code to be generic enough to cover all the specific needs for each application. You end up needing more code in the generic module than the sum total code you'd need to write separate modules for each app.
Also, testing becomes very costly, because any change you make to the base module requires that you re-test all the apps that use and extend it.
In the end, it's less work to write a new module for each app, and you can gain what efficiency you can by employing reusable components that are more fine-grained.
Programming languages/environments aside, are there many developers who are using a framework in PHP, ORM and still abide by encapsulation for the DAL/BLL? I'm managing a team of a few developers and am finding that most of the frameworks require me to do daily code inspection because my developers are using the built in ORM.
Right now, I've been using a tool to generate the classes and CRUD myself, with an area for them to write additional queries/functions. What's been happening though, is they are creating vulnerabilities by not doing proper checks on data permission, or allowing the key fields to be manipulated in the form.
Any suggestions, other than get a new team and a new language (I've seen Python/Ruby frameworks have the same issues).
Throwing away a team is never an option: improve it instead!
Arrange security workshops to make them more aware of these issues.
Introduce (or even better: ask them to introduce) code guide lines for better handling these problems (a security-aware hungarian notation or usage of prepared statements are two examples)
Address the short-comings in code reviews - don't blame them for ignoring security, just show the problematic snippets you found and explain that security is very important to [choose one: this project/the customer/your company's reputation/you personally]
Let them do security audits on their own or their peer's code. Let them find out how easy it is to exploit such security flaws.
Find other tools/frameworks that better support your security model. But be warned: this option is very expensive! Your programmers will need to maintain code in the old framework and learn a new one (worst case: they will need to learn a new language along with the new framework)
But basically this is an issue that you have to solve collaboratively with your developers. If you declare war on them, you're bound to lose (regardless of the outcome for the developers.)
To me it sounds like you want to improve coding culture. Have a look at the Rules of Extreme Programming. Maybe you can adopt a few techniques.
Basically, I get the impression there is very little communication right now between the developers and you. I might be just reading that into it, but to me it sounds like the devs are locked in the cellar and you are sitting somewhere else and getting frustrated about them. Change that kind of thinking. You are part of the team.
If your developers are not aware of the vulnerabilities they introduce into the code, consider having weekly code reviews. Let the developers talk about the code they wrote. Let them learn from each other. Make the code collectively owned. Foster learning and constructive criticism.
Remember, there is no I in Team.
May I recommend Nepthali? It's not an ORM, but the framework is designed to force security. I.E. all variables are encoded before output to the screen; unless explicitely defined not too.
It's also fairly lean, having no ORM, etc. so you can plug whichever ORM into it you want. It's pretty nice, actually.
If you want to check if the user has access to property it is another layer other than data access layer. But still there are frameworks where you can override default load functionality and insert your logics after/before loading.
The lightest framework I ve ever worked is db.php (http://dbphp.net, https://github.com/hazardland/db.php). But it is code first object rational mapper. You ll have to define classes than databases\tables will be created according to your classes.
Take a look at \db\table::load method. Every class has its own handler instance of \db\table located in database::tables array. You can override table::load or create individual handlers for tables derived from \db\table class and place them in database::tables.
The only problem is that framework is not fully documented but has very light intuitive code structure and samples.
Another option is to make dal framework by yourself it will take up to 3-4 months for 1 person to make it full functional and powerfull.
I currently ran into a problem I can not really solve by myself:
I ve started to code a "small" framework (browsergame-framework), which follows the MVC pattern in some way.
Now I have my index, bootstrap, db adapter, dispatcher, wrapper, but I do not really know "how" to link them.
I coded their methods etc. but I do not know how to design them to work like an engine.
And the next problem are my controllers, I do not know how to "link" them so that they easily can access the whole framework....
Yes, it is confusing, that is why I need your help, some generic scheme of "how a framework program flow" should like would be very nice.
Thank you.
you're putting the cart before the horse. frameworks are not written, they're grown. see Evolving Frameworks from Ralph Johnson, one of the Gang of Four.
edit
I do not understand, what the author means with "application", does this
mean raw-coded-project or does this mean project with basic functionality
which will be taken to the later framework.
Either, depending on your expertise in programming and the problem domain.
It's the goal (a useful framework) that's important, the process should simply support you
in achieving it as best as possible. You may either start slow, develop three applications in the same problem domain without any code sharing among them,
and just look at the code bases and see what they have in common, and possibly refactor these three finished applications to converge the code, and extract the common pieces.
This won't give you any boost during the development of the second and third application,
but neither will it hinder their development with concurrent refactoring of the previous ones.
Let's say you want a framework to ease writing browser-based, turn-based
strategies.
Your first turn is to write such a game without thoughts of reusing the
code outside this single game, but with attention to code reuse within
it: refactor mercilessly, apply all the principles of programming: OCP,
SRP, DRY, etc. Especially DRY. Code reuse (Don't Repeat Yourself) is a
basic principle of programming, and the first step on the path to a
framework. You will end up with a library of classes and/or functions
that are used across the game.
Your second turn is to write, adhering to the principles mentioned above,
another browser-based, turn-based strategy, using the code of the first
game. You'll find that much of it is specific to that first game. Use
the pieces that fit in the second one without modification, refactor those
that are useful but don't quite fit so that they are useful and do fit
in both games.
Repeat the procedure with the third game.
Three is the smallest number that gives you any hope of arriving at code
that is truly reusable across the problem domain (think triangulation),
not a guarrantee that it'll happen. OTOH, deriving a useful framework
without the support of real-world applications is a sure way to end with a
pile of useless crap.
Johnson:
Developing reusable frameworks cannot occur by simply setting down and
thinking about the problem domain. No one has the insight to come up
with the proper abstractions.
Read the "Three Examples" section carefully.