In the focus of recent feedback that I got, I think there is a need for me to justify some of the decisions we made while developing Webiny Framework. Some parts of the feedback were negative, but in a good way, as they directly pointed out certain aspects that we need to refine and make a better solution. On the other hand, some of the feedback was just placed in a negative way, mostly due to the angle from which the person was looking at and evaluating our framework.
With Webiny, we chose to “reinvent the wheel” in a lot of aspects and in doing so we both forked some libraries and re-engineered some approaches. This is where NIH kicks in.
Not Invented Here
Not invented here (NIH) is the philosophical principle of not using third party solutions to a problem because of their external origins. It is usually employed in favor of employer’s own solution to a given problem, though not necessarily so; NIH’s emphasis is on ignoring, boycotting, or otherwise refusing to acknowledge others’ solutions.
- Wikipedia http://en.wikipedia.org/wiki/Not_invented_here
I would say that’s exactly true in our case. In order to understand our decision for creating a new framework, let me give you some context. Our goal is to create a content management platform that will always work, be very fast and easy to use. With that in mind, you know you need the best foundation you can get, and current frameworks, like Symfony, Laravel and Phalcon, all provide that foundation. But, they change, evolve and re-shape their functionality in a different pace and with a different vision in mind. That’s a big risk if you are developing something that should never break and your users put their trust in you.
Sure, we could fork an existing framework, and maintain our own version, but is that really a good solution, with all the merging and patching, not having a clear insight in every single line of code? Sorry, but we just didn’t want to compensate on the very foundation of the platform we are building - that’s why we decided to build the Webiny Framework and reinvent some of the components, but not all of them.
On a component basis, we had to make decisions about completely writing our own solutions for some components - like the Rest or Entity component - while with some other components, like Mailer, we just provided an abstraction layer, where we would control all the public APIs.
This is a solution that we are happy with, and will continue to develop the framework in that way.
Bonus: If you have time, and I mean a lot of time, do try to code a fully fledged component, reinvent it. It will be worth your while, you will learn so much from it, and you will grow as a developer, even if it doesn’t end up being used by anyone.
The good thing about reinventing the wheel is that you can get a round one.
- Douglas Crockford http://en.wikiquote.org/wiki/Douglas_Crockford
What we Need to Improve
A couple of days ago, we were surprised that Anthony Ferrara mentioned us in one of his tweets.
If applying your code style to code makes it demonstrably more difficult to read, perhaps you should think twice about that…— Anthony Ferrara (@ircmaxell) February 1, 2015
Not exactly an endorsement, considering his profile and influence, right? :)
Now, to give a bit of background. Our Crypt component uses the PHP-CryptLib library by Anthony which we forked.
The tweet called out our component directly - we reformatted the code on the forked component. In our conversation with Anthony, he made some additional points we should work on to improve some parts of our Crypt component … in the following few sections I’ll go through some of these points and give our feedback.
Why did we reformat the forked code?
It really wasn’t our intention to re-format the forked code, it was honest oversight from our end, it was done automatically by IDE. We are aware of the problems this can cause later on. I’m not going to talk about or ask for excuses … it’s something we need to correct, and this is something we’ll definitely do.
Why so much abstraction?
Anthony complained about us having too much abstraction in the component. Most of the components in Webiny Framework follow the same architecture:
With this approach, we ensured that the dependencies to 3rd party libraries always go through the Bridge and the Driver. These two parts provide a flexible abstraction layer, and that if we wish to change any of our 3rd party dependencies, we we can do that easily without affecting the component public APIs.
This can end in multiple abstraction layers, if the 3rd party library also has one, which might be a bit too much. To avoid this, yes we can work around the abstraction layer of the 3rd party library. In some cases, like on the Crypt class, we haven’t done that. We usually integrate the 3rd party library inside the driver in the same way that is documented by the author of that library. Whether or not this is a mistake, I would say no, but is there room for improvement, yes, and we will do our part. In any case, we would welcome suggestions to alternative solutions for this. It’s just important to keep in mind that too much abstraction is better than too little.
Low strength generator on the random functions
We used low strength generators for performance reasons. High strength generators use more processing power, but the fact is that they are more secure - as Anthony stated in his feedback. It’s definitely something that we will be changing, it we decide to go further with this library.
Using static initialization vector
Anthony noted that using a Static Initialization Vector is a horrible idea. That’s a good point, it’s bad practice to use a static initialization vector, especially if you need to encrypt some really sensitive content. In our case, we don’t do that, we don’t store such data, however I acknowledge the fact remains, this is a standalone component and part of a development framework, so it needs to be configured in that way. In our case the static IV is initialized through a configuration file, but the developer has the option to manually initialize the component and can use a random IV for every encryption.
I figure a good practice would be to force a random IV for every encryption, eg. encrypt method should not take the IV as a param, it should be generated inside the method, and returned to the user, together with the encrypted string - not sure if there is such a library already? Do let us know if you know of some.
Cryptography and rolling your own
Basically - we didn’t, and you shouldn’t. We put a layer in front of an existing solution. What we did wrong is that we missed some of the best practices, which Anthony clearly stated and we will be fixing them.
Feedback is always great, it’s how we learn and improve. I’m very grateful to Anthony who took his time and sent us such great points on which we will definitely work to make our solution even better.
I just have one more general plea for all other developers out there. Please don’t start with a negative thought, and directly point and accuse somebody. Try asking first, is this intentional, was it done with a purpose, or was it just a mistake? We all make them, but if we step up and help somebody with advice or a suggestion, we are making something better together.
Give us more feedback :)
There are developers and engineers way smarter than us, but what we are doing is solving a very tough problem - we want to make website creation and management easier and more efficient, for the developers and designers out there. How good of a job we do, depends on our team, but also on the feedback you provide us with. So please, visit our framework’s github repo, tell us what you dislike, what you would improve and how - we are open minded and will gladly consider any feedback you may have.