"I am Application developer, I use components, I don't build them."
I typically have thought well I have found another "point and click" developer who is not familiar with OOP. Since I have been at my component no candidate who has said this has been hired.
Recently I ran into an exception (outside of an Interview) a Delphi Developer who was very familiar with OOP but had still not built a component. I realized that there an artificial barrier into component development, that many might see. In a future blog postI will confront this artificial barrier head on and show how easy it is to do component development. This post is show some of the arguments of why we would want to do component development as an application developer.
In 2007 we converted our application from BDE to DBX. We had written an application that converted all TQuery components to TDbxQuery components.
The process of conversion to the 3 component model of DBX (TSqlQuery -> TProvider -> TClientDataset) was going to be error prone. It was also going to take an insane amount of time that we were not willing to spend.
So we spent a few days creating a component that looked like and behaved like TQuery but internally used the 3 Component DBX model. It was similar to TSimpleDateset but had properties and functions that matched existing TQuery functionality that we used. This allowed for a search and replace of instances of TQuery with TdbxQuery. This allowed us to complete this conversion in less time that if we had just used the built in components. Since we maintained the component we were able to expose any functionality of the 3 components model that we needed.
During this process we realized we had hundreds of TDBGrid components. So we decided to help our application for the long term. We replaced TDBGrid with TDwsGrid. Initially the code looked something like this. It basically offered nothing over TDbGrid.
TDwsGrid = class(TCustomDBGrid) published property Align; property Anchors; property BiDiMode; property BorderStyle; property Color; property Columns stored False; property Constraints; property Ctl3D; property DataSource; property DefaultDrawing; property DragCursor; property DragKind; property DragMode; property Enabled; property FixedColor; property Font; property ImeMode; property ImeName; property Options; property ParentBiDiMode; property ParentColor; property ParentCtl3D; property ParentFont; property ParentShowHint; property PopupMenu; property ReadOnly; property ShowHint; property TabOrder; property TabStop; property TitleFont; property Visible; property OnCellClick; property OnColEnter; property OnColExit; property OnColumnMoved; property OnDrawColumnCell; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEditButtonClick; property OnEndDock; property OnEndDrag; property OnEnter; property OnExit; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseActivate; property OnMouseDown; property OnMouseEnter; property OnMouseLeave; property OnMouseMove; property OnMouseUp; property OnMouseWheel; property OnMouseWheelDown; property OnMouseWheelUp; property OnStartDock; property OnStartDrag; property OnTitleClick; end;
The other day I had a look at this component, it now does the following.
- Sorts the Grid based on Click of column Title
- Persists Column positions and sizing to a configuration file.
- Ability to Export to Excel.
It's not a huge amount functionality but it allowed us to add this to many screens without how having to place this code to do this in every place we used TDbGrid.
When explaining this to application only developer one might expect a response of. "Well why not buy a 3rd party control that does that?" My answer "We did just that, when we had the budget we purchased a TMS Subscription and now use TDBAdvGrid in many places."
But the experience previously learned still applied to 3rd party component packages. We now are in the processed of creating, our new component which now looks like this:
TdwsAdvDbGrid = class(TAdvDBGrid) end;
Allowing us to add additional functionality to TAdvDBGrid if we need it. Granted for now we don't need to add anything. But the lesson learned from the previous experience has shown the value.
This does not just apply to additional functionality, it also applies to common custom settings.
Say for example every time you use a TEdit you need to change the Font to comply with a standard
you have set. Instead of doing the tedious mistake ridden work of doing this. Instead create a TMyEdit then use that instead of TEdit.
This does not just apply to additional functionality, it also applies to common custom settings.
Say for example every time you use a TEdit you need to change the Font to comply with a standard
you have set. Instead of doing the tedious mistake ridden work of doing this. Instead create a TMyEdit then use that instead of TEdit.
interface uses SysUtils, Classes, Controls, StdCtrls; type TMyEdit = class(TEdit) public constructor Create(AOwner : TComponent); override; end; procedure Register; implementation { TMyEdit } constructor TMyEdit.Create(AOwner: TComponent); begin inherited; Font.Name := 'My Crazy Font'; end;
So basically a developer should be able to do both, application and component development. Taking the time to learn component development will only help you in your your abilities to create great applications.
It just goes to show, what we learn we take for granted that others have also learned.
ReplyDelete15 years ago I learned to never use a component directly but to always create an interposer class and use that instead.
This allows you to not only extend your classes (usually) without having to resort to modifying the original class (though the extent to which this is successful depends on whether the original class has been well designed for extensibility) but also protects (to an extent) your application/consumer code from any future need to change from one set of base components to another.
But I disagree that a developer should be able to do both. The skill sets are very different. Designing a good component has a very different set of outcomes from designing an application. A component developer typically has to have a far broader vision and yet a far narrower scope.
Yes, there are some developers who are both good application developers AND good component developers, but generally speaking you will get better results by pairing a good component developer with a different good application developer, particularly on the component side of things.
For one thing, when designing components to use in your own application code, it is surprisingly easy to unwittingly and unintentionally blur the boundaries.
Just imho. ymmv.
>The skill sets are very different. Designing a good component has a very different set of outcomes from designing an application.
ReplyDeleteJolyon has a good point here. The examples in this article really aren't about creating components; they're about adapting components that other people have created. That's a heck of a lot easier than building new ones from scratch.
(And for some reason, your commenting system doesn't like the BLOCKQUOTE tag. That's kind of annoying when you want to quote someone else. Anything you can do about that?)
@Mason, @Jolyn:
ReplyDeleteI would completely agree that they are different skill sets.
But my point is that a application developer not knowing the basics of component development really puts you at a disadvantage.
As an application developer, sometimes solving things at the component level really can make life easier in the long term.
@Mason: No the commenting system is 100% controlled by Google.
Have you considered the possibility not developing components (nor adapting them), and not even _using_ components? Most of my work consists of this. And we are very much using OOP.
ReplyDeleteWe simply don't need that many components. So we don't develop them either.
Why use a TComponent descendant when a TObject descendant will do just fine? To be able to slap it onto a DataModule? Not much use really. The biggest part of our software suite is server side and we create everything at run time, so have no need for data modules or components that you would normally slap onto a data module.
Even the client part of our software is separated as much as possible from design time dependencies. Yes we put the components on a form, but many are created at run time (I wish component developers would stop using Loaded for all kinds of stuff as it isn't called when you create a component on the fly instead of streaming it in from a dfm) and we try to keep all other logic out of forms/frames. Personally I even go so far as not to rely on design time positioning of controls. Mainly because DFM's are a real pain when it comes to version control and especially merging of different branches.
marjanvenema, if you position your controls in run-time, then you need to take special care about different DPI's, and other similar things. There are chances, that you will miss something here, so better let VCL do it's job.
ReplyDelete@Marjanvenema
ReplyDeleteIf your really doing OOP you should be able to "consider" inheriting from your base library classes. These classes can be components.
For example we use our TDbxQuery quite a bit in code, where no DFM is used.
@mikolaterbins: we let the vcl do it's job. Positioning is mostly done by using panels, anchoring and aligning.
ReplyDelete@Robert: excuse me? I am not doing OOP if I do not inherit from some library base class? Of course we are inheriting from all kinds of library base classes, but that was not my point.
I was addressing the fact that your post seems to convey that someone is "simply" an application developer and not component/OOP developer when they are not creating any TComponent descendants.
Being able to derive a class from (a) TComponent (descendant) is not what makes someone an OOP developer.
We are very much doing OOP, but many if not most base classes we use do not descend from TComponent... In fact, most of our classes descend directly or indirectly from TObject.
In addition, inheritance is not the only way of doing OOP. In some corners of software developement it is actually is very much discouraged and composition and aggregation regarded much more favourably.
@marjanvenema:
ReplyDeleteYou are very much correct in what you have said.
But you have missed the point and some key words.
I think you missed the word "consider" and "can" in my last comment. I am not implying a requirement.
A majority of our code does not have TComponent in it's ancestry. But there are times it makes sense to use a TComponent descendant.
My original post was about people who place an artificial barrier around components. Avoiding Component descendants completely as a rule is such a barrier. Not needing them because they are not part of your design is completely acceptable.
Ah! Thanks for the clarification, totally with you now. Oh, the joys of written communication...
ReplyDelete