Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I am writing a game in Cocos2D-x and I am struggling with feeling like my OO is sloppy. I can't shake the feeling and I can place m finger on why.
Game Scene class
In This a Layer is created
Layer Class
responsible for creating itself
Also calls HUDS when needed
contains std::vectors of objects on the layer
Object Class
hold everything about itself
has a sprite member variable that is on the layer
HUD1
called when the user taps the layer and the touch even occurs in the Object
is a Menu of things that you can do to the Object
When you click a menu item it needs to change values in Object
When you click a menu item it actually runs code in Object (object::doSomething())
What feels sloppy I think is that there is a lot of dependency on these classes together.
I feel like I should abstract this out and create a class that controls all of this happening instead of some code in Object, Layer, HUD, etc.
Can anyone talk to me about how this is laid out and if I am making an OO mistake?
As it turns out graphics and games do not fit into OO designs very well despite being an example in many OO texts. Your instinct is right with respect to decupling the control from the data. A popular design pattern for games these days is to have components, entities, and systems instead of a rigid OO hierarchy.
The idea is that you have Entities or GameObjects that are just collections of components and perhaps some messaging infrastructure. Components store data about the Entity they are attached to, for example you might have a Transform component and a velocity component. Now one approach is to have a messaging system that components can hook into and use that to update their data. For example a Velocity component might hook into the Update message and in the Update handler it could get the transform of the object and move it. By using messages for all communication between components you can decouple them to a large degree.
Systems are a different way to handle updating component data. The idea with Systems is that you have a process that can say "I operate on entities with these components" and then it gets a list of all of the relevant entities when it runs. This decouples data from function even more and can make it easier to manage threading and dependencies
Essentially object oriented design is about capturing "what things are" in the real world, but with a game you don't really want that, all you care about is what things look like and you would like to be able to change the individual facets of something's behavior without pain.
Good resources for Entity-component systems:
http://piemaster.net/2011/07/entity-component-primer/
http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
Have a think about what you are trying to achieve before trying to dive in to code (even though the urge to do this is very strong!)
Try to decouple your classes by using Dependency Injection. This may involve adding a bunch of extra classes and complexity now, but trust me, it will make your life much easier later on when you will inevitably need to refactor certain parts of your game. Avoid using 'gum and duct tape' solutions as the technical debt you will incur by doing this will come back and bite you later!
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
Despite beeing written in C++, the famous vulkan tutorial stick everything in one class with functions using class members like global objects. I understand why such a tutorial don't enforce an object oriented workflow to focus on the API mechanics and let engine programmers setup their own workflow. But even CLion complains that an 600 lines file is too complex to analyse.
So my questions are, is an object oriented layout suitable for the Vulkan boilerplate ? Maybe once you have all the component setup this better to hide them in a file and only use higher level stuff like Meshes and Materials.
If so, are there classic layouts that are more or less used across implementations ?
So far I was able to put functions regarding Device (picking, logical device and swap chain creation, surface format and swap (present mode and extent) choice, queue families and memory finding, and other device related functions) in a separate file, but not in a class, validation layers have also their own file. Finally I made a Buffer class from which inherits Index, Vertex, Staging and Uniform buffers.
I found this repo from what I understand, at the level where I am (uniform buffers) the workflow is split in Buffer, Debug, Device, FrameBuffer, Initialisers and SwapChain. Is this a classic workflow or are there other ways ?
Vulkan has pro and cons versus OpenGL, it is not a replacement. Both libraries are in active development by Khronos, and will continue to do so.
Cons are obvious: Vulkan is much more wordy to do even basic things. From resizing a window requiring reconstructing all (most) your objects, to extremely limited number of active handles (thus requiring buffer packing), manual synchronization of multiple queues per device (with special code for single-queue devices), everything is very painstakingly done, with no safety nets. It is very easy to corrupt your buffers with too little synchronization, or completely kill performance with too much.
Pros now. Why use Vulkan over OpenGL? Well, you use Vulkan because you can construct and use exactly what you need. Don't need a depth buffer? Don't create one. Don't need a stencil buffer? Don't create one. Don't need to handle resizing windows? Don't pay the cost to handle them. Don't want runtime updateable buffers? Create static buffers and don't pay the cost to make updating them even possible.
Vulkan is strongly pushing you towards creating exactly the kind of engine you need, not something generic that handles everything. Pushing it to that extent, you'll just build OpenGL on top of Vulkan, and gain none of its performance benefits while inheriting all the difficulty in using it.
So that's your answer. OOP shouldn't really enter the equation here, you build a monolithic rendering engine that does exactly what you need it to do and nothing more.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
(for a custom engine) Just a simple question, I was wondering if there was an advantage adding a child this way:
`myNode.transform.parent = newParent` // unity like
instead of this:
`myNode.transform.AddChild(newChild)`
Or is it just a matter of preference.
For my part I find it weird that a setter will do background stuff for example deleting himself from its previous parent children conteiner.
Thanks !
They may be using an AddChild method in the C++ backend to make the addition.
Unity's core engine is written in C++, C# is merely the scripting layer that they use. Unity registers their backend methods to front end methods and properties. When somebody uses that property or method, the backend implementation is called instead. This isn't the case for all of Unity's stuff, Unity's UI is predominantly C#, and it's open source to, in case you're curious:
https://bitbucket.org/Unity-Technologies/ui/overview.
Here's an article that may clear up some aspects of which would be best to choose, although in practice, it usually comes down to preference:
https://msdn.microsoft.com/en-us/library/ms229054(v=vs.100).aspx
In general though:
methods represent an action, properties represent data.
Another user asked a similar question: Properties vs Methods
Take a peak if my answer doesn't clear it up.
Also, in case you're curious about how Unity calls its backend methods, this may clear it up: https://github.com/mono/mono/tree/master/samples/embed
Hopefully this'll help.
The other answer is really good but I just wanted to add a little bit of an explanation to why you would use addChild(...) or .parent = ....
It basically comes down to how you build your code, if you do the parent instance then when it is drawing its location, it can just get its parent and then draw it relative to that parent.
Where as if you did the addChild(...) system then the parent has to tell the child where its location is (or you have to have a link anyway to the parent) to draw it relative.
That is just one reason and I'm sure there is plenty, but it does mostly come down to preference.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I parse/process data coming from many different streams (with different formats) and the number of different sources for data keeps growing in my system. I have a factory class which based on a config file specifying the source will give me the appropriate parser/processor pair (abiding to a small common interface) requested in something like this:
static Foo* FooFactory::createFoo(source c, /*couple flags*/)
{
switch (c)
{
case SOURCE_A:
{
//3 or 4 lines to put together a parser for A, and something to process stuff from the parser
return new FooA(/*args*/);
}
break;
//too many more cases which has started to worry me
default:
return NULL;
};
}
the problem is as the number of sources has grown I am facing two issues. First, when I build, I find myself pulling in all the FooA, FooB, FooC, FooD, FooE... relevant code - even if I was only interested in perhaps building a binary in which I'll only request FooA lets say. So how to go about modularizing that. A secondary issue is, right now in the case of SOURCE_A, I am returning FooA, but what if I am interested in SOURCE_A but I have different ways of parsing it and perhaps I want FooA_simple and FooA_careful but with the ability to plug and play as well?
For some reason, one thing that came to mind was the -u option to the linker when building a binary...it somehow suggests to me the notion of plug and play but I'm not sure what a good approach to the problem would be.
Well, you just create a factory interface and divide the logic among subtypes of that factory. So there might be a sub-factory (type/instance) for libFooA, and another for libFooB. Then you can simply create a composite factory depending on the subfactories/libraries you want to support in a particular scenario/program. Then you could even further subdivide the factories. You could also create factory enumerators for your composite types and do away with all that switch logic. Then you might say to your libFooA factory instance to enable careful mode or simple mode at that higher level. So your graph of FooFactory instances and subtypes could easily vary, and the class structure could be like a tree. Libraries are one way to approach it to minimize dependencies, but there may be more logical ways to divide the specialized sub-factories.
I'm not sure if you can get around importing FooA,FooB... because at any given moment any one of them might be instantiated. As for modularizing it, I'd recommend creating helper functions that gets called inside the switch statement.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've tried wedging my clojure diagrams into what's available in UML, using class-blocks as the file-level namespaces and dependency links to show relationships, but it's awkward and tends to discourage functional patterns. I've also tried developing ad-hoc solutions, but I can't discover a solution that works as well as UML with, say, Java (simple directed graphs seem to work in a vague manner, but this the results aren't detailed enough). Furthermore, I'm not finding anything on the web about this.
Just to be clear, I'm not trying to do anything fancy like code generation; I'm just talking about pen-and-paper diagrams mostly for my own benefit. I'm assuming I'm not the first person to have ever considered this for a lisp language.
What solutions have been proposed? Are there any commonly-used standards? What do you recommend? What tools do you use?
It depends on what you want to describe in your program.
Dependencies
Use class diagrams to model the dependencies between namespaces; in this case, it's more clear if you use packages instead of classes in a diagram.
You can also use class diagrams to model dependencies between actors
Data flow
You can also use Communication Diagrams to model the flow of data in your program. In this case, depict each namespace as an entity and each function as a method of that entity.
Or, in the case of actors, depict each actor as an entity and each message as a method.
In any case, it's not useful to try and describe the algorithm of your program in UML. In my experience, they are better described in comments in the source file.
I think its less about the language and more about your conceptual model. If you are taking a "stream processing" approach then a data-flow network diagram might be the right approach as in some of the Scheme diagrams in SICP. If you are taking a more object oriented approach (which is well supported in Lisp) then UML activity diagrams might make more sense.
My personal thought is to model the flow of the data and not the structure of the code because from what i'v seen of large(not really that large) Clojure projects the code layout tends to be really boring, with a huge pile of composeable utilities and one class that threads them together with map, redure, and STM transactions.
Clojure is very flexible in the model you choose and so you may want to go the other way around this. make the diagram first then choose the parts and patterns of the language that cleanly express the model you built.
Well, UML is deeply rooted in OO design (with C++!), so it will be very difficult to map a functional approach with UML. I don't know Clojure that well but you may be able to represent the things that resemble Java classes and interfaces (protocols?), for all the others it will be really hard.
FP is more like a series of transformations from input to output, there's no clear UML diagram for that (maybe activity diagrams?). The most common diagrams are for the static structure and the interaction between objects, but they aren't really useful for the FP paradigm.
Depending on your goal the component and deployment diagrams can be applicable.
I don't think something like UML would be a good fit for Clojure - UML is rather focused on the object oriented paradigm which is usually discouraged in Clojure.
When I'm doing functional programming I tend to think much more in terms of data and functions:
What data structures do I need? In Clojure this usually boils down to defining a map structure for each important entity I am dealing with. A simple list of fields is often enough in simple cases. In more complex cases with many different entities you will probably want to draw a tree showing the structure of your data (where each node in the tree represents a map or record type)
How do these data structures flow through different transformation functions to get the right result? Ideally these are pure functions that take an immutable value as input and produce an immutable value as output. Typically I sketch these as a pipeline / flowchart.
If you've thought through the above well enough, then converting to Clojure code is pretty easy.
Define one or more constructor functions for your data structures, and a write a couple of tests to prove they are working
Write the transformation functions bottom up (i.e. get the most basic operations working and tested first, then compose these together to define the larger functions). Write tests for every function.
If you need utility functions for GUI or IO etc., write them on demand as they are needed.
Glue it all together, testing at the REPL to make sure everything is working.
Note that you source files will typically also be structured in the sequence listed above, with more elementary functions at the top and the higher level composed functions towards the bottom. You shouldn't need any circular dependencies (that's a bad design smell in Clojure). Tests are critical - IMHO much more important in a dynamic language like Clojure than in a statically typed OOP language.
The overall logic of my code is usually the last few lines of my main source code file.
I have been wrestling with this as well. I find flow charts work great for basic functions and data. It's easy to show the data and data flow that way. Conditionals and recursion are straightforward. UML sequence/collaboration diagrams can capture some of the same info pretty well.
However, once you start using HOF, this does not work well at all.
Normal UML diagrams for packages work ok for namespaces, not that that does much.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
Let's say I'm starting a new project, quality is a top priority.
I plan on doing extensive unit testing, what's important to keep in mind when I'm working on the architecture to ease and empower further unit testing?
edit : I read an article some times ago (I can't find it now) talking about how decoupling instantiation code from classes behaviors could be be helpful when unit testing. That's the kind of design tips I'm seeking here.
Ease of testing comes through being able to replace as many of the dependencies your method has with test code (mocks, fakes, etc.) The currently recommended way to accomplish this is through dependency inversion, aka the Hollywood Principle: "Don't call us, we'll call you." In other words your code should "ask for things, don't look for things."
Once you start thinking this way you'll find code can easily have dependencies on many things. Not only do you have dependencies on other objects, but databases, files, environment variables, OS APIs, globals, singletons, etc. By adhering to a good architecture, you minimize most of these dependencies by providing them via the appropriate layers. So when it comes time to test, you don't need a working database full of test data, you can simply replace the data object with a mock data object.
This also means you have to carefully sort out your object construction from your object execution. The "new" statement placed in a constructor generates a dependency that is very hard to replace with a test mock. It's better to pass those dependencies in via constructor arguments.
Also, keep the Law of Demeter in mind. Don't dig more than one layer deep into an object, or else you create hidden dependencies. Calling Flintstones.Wilma.addChild(pebbles); means what you thought was a dependence on "Flintstones" really is a dependence on both "Flintstones" and "Wilma".
Make sure that your code is testable by making it highly cohesive, lowly decoupled. And make sure you know how to use mocking tools to mock out the dependencies during unit tests.
I recommend you to get familiar with the SOLID principle, so that you can write a more testable code.
You might also want to check out these two SO questions:
Unit Test Adoption
What Should Be A Unit
Some random thoughts:
Define your interfaces: decouple the functional modules from each other, and decide how they will communicate with each other. The interface is the “contract” between the developers of different modules. Then, if your tests operate on the interfaces, you're ensuring that the teams can treat each other's modules as black boxes, and therefore work independently.
Build and test at least the basic functionality of the UI first. Once your project can “talk” to you, it can tell you what's working and what's not ... but only if it's not lying to you. (Bonus: if your developers have no choice but to use the UI, you'll quickly identify any shortcomings in ease-of-use, work flow, etc.)
Test at the lowest practical level: the more confident you are that the little pieces work, the easier it will be to combine them into a working whole.
Write at least one test for each feature, based on the specifications, before you start coding. After all, the features are the reason your customers will buy your product. Be sure it's designed to do what it's supposed to do!
Don't be satisfied when it does what it's supposed to do; ensure it doesn't do what it's not supposed to do! Feed it bad data, use it in an illogical way, disconnect the network cable during data transfer, run it alongside conflicting applications. Your customers will.
Good luck!
Your tests will only ever be as good as your requirements. They can be requirements that you come up with up front all at once, they can be requirements that you come up with one at a time as you add features, or they can be requirements that you come up with after you ship it and people start reporting a boat load of bugs, but you can't write a good test if no one can or will document exactly what the thing is supposed to do.