|
see yourself in 1 year, what kind of psychopath will you be when you'll have to do changes in that code.
Refactor your code.
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
That's definitely part of my consideration on choosing the approach
It's quite likely that another company will do the maintenance though due to an arrangement we have
|
|
|
|
|
I've successfully used a single dialog with all content and then injected the display and validation logic from a container.
It should give you the best of both worlds.
veni bibi saltavi
|
|
|
|
|
Welcome Back Mr. Vilmos.
Long without seeing you.
I hope everything is fine with you and your people.
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
Complexity is perhaps going to make it easier to extend.
Duplication will in all likelihood make it easier to debug.
I know it's the wrong answer from a software engineering point of view - but from the point of view of someone who spends a lot of time fixing defects on a huge code base I would go for duplication.
I have seen a lot of code that makes use of inheritance and quite frankly I have found it to at times be something of a nightmare.
Complexity is clever and is elegant but it can make tracking and fixing bugs a lot more difficult.
“That which can be asserted without evidence, can be dismissed without evidence.”
― Christopher Hitchens
|
|
|
|
|
GuyThiebaut wrote: Complexity is clever and is elegant but it can make tracking and fixing bugs a lot more difficult.
Yeah, that's what I'm hoping to avoid.
|
|
|
|
|
That's when you're overdoing it.
Put everything common in a base file that you inherit. Duplicate the rest.
|
|
|
|
|
I would also favour composition over inheritance where possible.
So you could have a baseclass form that is very basic, then the implemented forms can perhaps use some form of builder to class to individually tailor those forms.
Using composition may make it easier to see what each form is built from.
“That which can be asserted without evidence, can be dismissed without evidence.”
― Christopher Hitchens
|
|
|
|
|
Inheritance and specialization.
Maybe make the common sections into UserControls, etc.
|
|
|
|
|
A bit of a different idea: could you implement the common code in UserControls and classes so they have a well defined internal API?
|
|
|
|
|
Hmm, metal note: refresh the page and read any new posts before posting. PIEBALDconsult beat me to this by about 2 hours and 30 minutes.
|
|
|
|
|
So this means you are voting for duplication? 😂
|
|
|
|
|
Every time I've re-used UI for multiple forms I've come to regret it.
Ask yourself, who are the stakeholders for every form?
Are they the same? Do they know if another form is changed? Do all forms change at the same time?
If any of your answers is "no" then duplicate them, they look the same (for now), but are functionally different.
I didn't and am now in a situation where one form is evolving while the other isn't and the amount of if-else's is too damn high!
Now, I only re-use specific elements or components on a page.
Talking web (ASP.NET MVC and Razor Pages) and WinForms experience here (maybe your hybrid approach?).
|
|
|
|
|
A series of "user controls": no "duplication" - only reuse. Show / collapse based on context.
The common "70%" is an obvious candidate for abstracting into a user control that becomes familiar; UI, business rules, or both.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
ideally ...
1) define a generic base Form with common features/controls/logic all specific types will use.
2) define specific Forms that inherit from the base Form.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Some interesting comments in this thread - funnily enough almost all focussed on the technical details of one approach or the other rather than a general principle.
To my mind, and after decades of coding in lots of environments, I (and this is only my personal opinion here!) always find a single codebase is overall easiest to maintain. Having multiple copies of similar, but not quite the same, code is just asking for trouble, especially as a generic logic error may not manifest in the same way in all duplicates.
Careful structuring of the code, with - useful! - comments about what each section (however coded) is doing and why, will be much easier to keep working or amend than multiple similar versions. Especially so for someone unfamiliar with the codebase.
Obviously for very small chunks of functionality this may not be true, but the more complex the process being modelled the greater the benefits of not creating multiple copies...
All IMHO, of course, as I said!
|
|
|
|
|
Mike Winiberg wrote: Having multiple copies of similar, but not quite the same, code is just asking for trouble, especially as a generic logic error may not manifest in the same way in all duplicates.
Good point and what I'm trying to avoid.
This is the approach I'm taking for now as it's too early to optimize / refactor at this stage. It's an Angular project, so I might break the UI into smaller components, but leave the logic in the main / parent component.
|
|
|
|
|
Since this is turning complex anyway, let the user benefit from it:
(1) Define all your functional bits as separate classes.
(2) Create a set-up form, which lets the user define his own forms.
(3) Set up the four standard forms yourself to get the user started.
(4) Consider creating a domain-specific language (DSL) to define your set-up. Easy now! This should just be a very simple declarational script with your own syntax. This will allow you (and superusers) to whip out customised forms. Your set-up page (2, above), of course, creates a DSL-script under the hood. The DSL, by the way, makes testing straightforward. The DSL is parsed to create an object tree representing your form.
The user gains flexibility, and you are relieved from hard-coding specific permutations of all the functional bits. -- And the time spent coding will be fun!
|
|
|
|
|
Others mentioned Componentization, and Inheritance.
I agree. First the common controls / components should be built.
But I believe the framework gives you some of this.
So, I really like the idea of either inheriting from a base class.
I have one application that grew from 3 to about 10 "Wizard" input screens. Walking the users through complex steps inspecting things at an engineering level.
Having taken the time to build a single wizard page (Base Object), that identifies ALL mistakes or required entries, and business rule violations. A Virtual Method for custom validations, etc...
I can tell you it was ALMOST a PLEASURE adding new screens. 100% completely different screens, mind you, but the inherited approach meant that the user flow was the same.
So, sometimes a beautiful solution that fits perfectly, but is hard to extend... Sucks...
Sometimes a flexible solution that fits, but is so complex, you hate having to relearn the 17,000 things you have to do to make it work, and test it... [see "frameworks", lol]... Makes it a pain...
Great question. I think you look at the progression of the requests. Upcoming future stories, and creating a code base that is anti-fragile, and even enjoyable to work with... And you can't go wrong.
If you did, refactor it when you learn better....
|
|
|
|
|
I think you already have some good answers here. The following are my general rules for this sort of situation.
No code, string, or logic that ever needs to be kept in sync should ever be duplicated via copy and paste. It will get out of sync if you do. And trying to keep it in sync will drive up the cost of the development/debug cycles despite the "increased complexity" of someone updating a single pasted copy.
To facilitate this, apply the following in order:
When 'magic strings' are required, they are put into constants and referenced so one can't be changed without breaking compilation.
If you KNOW that you are only going to have 2 or 3 versions of whatever you are maintaining, simple if then else logic is perfectly fine as you haven't violated the primary rule of not duplicating any code/logic/markup that needs to be kept in sync and more importantly in all likelihood, you want a future developer to consider the impact on the other uses of the logic rather than being able to ignorantly get things out of sync by updating one form and not the other.
When code can be placed in a function and effectively called from each required location, do this.
When composition/aggregation can be used to capture the logic into a reusable component, do this.
When the above are not possible, consider inheritance and/or a metadata driven approach.
NOTE that all of these rules only apply assuming you are coding in a language that can be compiled or linted (well), such as a traditional language (C,c++,java,c#,Typescript,...), annotated python, ... These would not ALL apply to vanilla JS, non-annotated python, lua, or other similar languages that only break at runtime and require developers to create tests to replace what a compiler and linter mostly does for a good code base.
Further, they assume that performance is not a concern.
Dave B
modified 13-Oct-21 12:40pm.
|
|
|
|
|
Make sure there is no business logic in the UI.
Try to do all of your heavy reuse in the business layer. Design the interface between the UI and the business layer in such a manner that the UI will have a compile breakage for incompatible business layer changes.
Lots of other good posts on how you might organize UI layers. Reuse in UI layers would map to reuse in the business layers.
At some point you might have to diverge, this should allow that to proceed without too much mess.
|
|
|
|
|
General question - general answer:
I mainly see different pros/cons than you:
Duplication: It's really bad when the different copies of the same code start to drift apart. It has to be made sure that whenever someone changes one copy of the code, the changes are copied to all other copies of the code. So everyone in the team has to know that there is copy/paste code, which might be a problem in large teams or teams with a lot of fluctuation. If you're a one-man team, then you don't have this problem. Unless your memory is bad and you can't remember what you did last year!
Complexity, or as I would call it, "clean code": It takes a lot more time to avoid copy/paste code, and the return on this investment is not visible on the surface. There are cases where it's more efficient to not make this investment. So the decision depends on whether you're working on a one-shot project or on a product you're going to have to maintain for decades. For long-term software, the clean-code approach usually pays off in the long term. The *very* long term! Which is something that project managers usually don't like to hear and thus software developers have to take care of themselves.
|
|
|
|
|
i would first go with duplication and time/experience will show what is for reuse. so it will end hybrid.
i am working with people who like to overuse (reuse) and sometimes that creates dependencies.
|
|
|
|
|
Sometimes elements that appear to be common at first are not really common. Say for example, both forms have a name field. One might jump to the conclusion that the name field is common to both forms and factor it out for reuse. Then down the track one of the forms needs the name field to be changed to say nick name. Now we realise in hindsight that just because the code was identical between the forms in the first instance they were not really common code and more refactoring is now required. When you factor out common code try to make sure the cut is in areas that are unlikely to change if requirements change.
|
|
|
|
|
Meyer-Briggs can't report verbatim. (8)
Software rusts. Simon Stephenson, ca 1994. So does this signature. me, 2012
|
|
|
|