Workaround solution to avoid getters in Golang interface - go

Thank you for taking some time to read this question!
I'm new to Golang and I've been developing a simple social media API to practice the language in general. In this project I'm using a struct to represent the Model of a Post published by an user, as follows:
// models/post.go
package models
import "time"
type Post struct {
ID uint64
Title string
Content string
AuthorID uint64
Likes uint64
CreatedAt time.Time
}
func (p *Post) ValidateFields() error {
// validate fields
}
This post can be saved to the database with the help of a method that is inside a repository:
// repositories/posts.go
import (
"database/sql"
"models"
)
type PostsRepository struct {
db *sql.DB
}
func NewPostsRepository(db *sql.DB) *PostsRepository {
return &PostsRepository{db}
}
func (r *PostsRepository) Save(models.Post) (uint64, error) {
// Passing the model as a parameter
}
As you can see, the model is being passed as a parameter and that feels like a problem for two reasons:
I only need three fields to save the post to database (Title,
Content and AuthorID) because everything else will be generated
automatically
If I write an unit test to the Save function it will
rely on the model to work, therefore any problems with the model
would impact the test
So with that in mind I thought about changing the parameter from a model to an interface, but since interfaces only accept method signatures and in that specific case I only need attributes to save data on the database, I assume it would need a few getters such as:
type PostInterface interface {
GetTitle() string
GetContent() string
GetAuthorID() uint64
}
(I know it is not idiomatic to call a getter "GetAttribute", but it's just to give you an idea)
Due to that, I'd have to implement these three methods on my Post Model, which would look like
func (p Post) GetTitle() string {
return p.Title
}
func (p Post) GetContent() string {
return p.Content
}
func (p Post) GetAuthorID() uint64 {
return p.AuthorID
}
That doesn't look so good, but it gets worse when we go to the test.
Like I said, I do not want to use the model in the test so I would have to create a struct to serve as a stub or something that has only the three needed fields for the Save to work (which sounds good). However, I'd have to implement these three methods again so that the struct can be accepted as an interface by the Save function (which sounds bad)
It sounds like a lot of unecessary work, Is there any way to work around this? I'm not sure if I'm missing something conceptual about Go or if there are any changes on my architecture that could address to this issue, but I'm having trouble finding alternatives to this
Thank you!

Using a struct in the save function is perfectly fine and considered idiomatic. If this is just a data container I don't see any issues in testing this functionality. You could however opt for a slimmer version of the struct with just the respective fields you require when storing the content in the database.
For instance:
type Content struct {
Title string
Content string
AuthorID uint64
}
If you still want to decouple with an interface you can create a method on the Post model and return the Content struct, personally I don't see the need for this since it will not improve the testability and only increases complexity by using another layer of abstraction.
In your tests you can just create an instance of the Content struct and pass that to the Save function.

Related

Control over unexported struct fields

So this is my first question in stackoverflow. :)
We have defined a struct in org package like below:
type Employee struct {
FirstName, LastName string
salary int
}
and then in main.go file, we are initializing the struct like below:
func main() {
ross := Employee {
FirstName: "Ross",
LastName: "Geller",
}
fmt.Println(ross)
}
The output will be like below:
{Ross Geller 0}
As salary field is not exported from the Employee struct type, so it's displaying the zero value of int. An end-user will assume that the salary of this employee is 0.
So is there any way to control the unexported fields?
What is the best approach to deal with such a problem in a real-time scenario?
Is this really a problem?
If you're really worried about it, you can override the .String of Employee:
https://play.golang.org/p/PncEOGVP2HP
func (e Employee) String() string {
return fmt.Sprintf("%v", struct{
FirstName string
LastName string
}{e.FirstName, e.LastName})
}
But in reality, are they going to be seeing the output from the console of your program? Most likely this is a non-issue.
Well, If you want to initialize the field you can always write an exported function or method to do that such as
func New(first,last,salary string) Employee{
//...
}
The reason why you can have unexported types is to be able to create something called an opaque type.
You can have methods on your data setters and getters and do complex things without worrying about user braking the internal state of your data.
Imagine you are writing a drawing app and you have a painter Struct which keeps track of cursor and current color and stuff. You really would not want your user to be able to mess with your painter manually. that would break everything.
So the user creates the painter through an initializer and passes it around as a Painter type and using methods such as moveTo,lineTo which updates the state internally.

How to omit some parameters of structure Gin gonic

I have big structure with more than 50 params
type Application struct {
Id int64 `json:"id"`
FullName string `json:"fullName,omitempty"`
ActualAddress string `json:"actualAddress,omitempty"`
.....
}
I use gin-gonic and when I return application I need to omit some params I've created a function which makes empty some params (playLink) and then gin returns me correct json (without unnecessary values). I heard that reflection isn't fast operation so in our case we can use a lot of ugly if-else or switch-cases. Is there any other solutions faster than reflecting and more beautiful than if-elses?
The thing is that structure params have non-empty values, so they wont by omitted by gin. That's why I've created function to make some params empty before return
The thing is, if you only want to zero a few fields, it's more readable to do it without a function, e.g.
app := Application{}
app.FullName, app.ActualAddress = "", ""
If you want to create a function for it, at least use variadic parameter, so it's easier to call it:
func zeroFields(application *Application, fields ...string) {
// ...
}
So then calling it:
zeroFields(&app, "FullName", "ActualAddress")
Yes, this will have to use reflection, so it's slower than it could be, and error prone (mistyped names can only be detected at runtime). If you want to avoid using reflection, pass the address of the fields:
func zeroFields(ps ...*string) {
for _, p := range ps {
*p = ""
}
}
This way you have compile-time guarantee that you type field names correctly, and that they have string type.
Calling it:
zeroFields(&application.FullName, &application.ActualAddress)
Try it on the Go Playground.
If I understand correctly: you want to return some values from your struct but not all of them? Perhaps a nested struct?
type Application struct {
ID struct {
ID int64 `json:"id"`
} `json:"id"`
Person struct {
Fullname string `json:"Fullname"
} `json:"person"
}
That should let you filter out the fields you want to use.

Golang proper use of interfaces

I am new to Go and am running into a situation that I am unsure how to solve. I am working on some code that takes a DNS packet in raw bytes and returns a struct called DNSPacket.
The struct looks like the following
type DNSPacket struct {
...some fields
Questions []Question
Answers []Answer
...some more fields
}
The issue I am having is with the Answers type which looks like this.
type Answer struct {
Name string
Type int
Class int
TTL uint32
RdLength int
Data []byte
}
Depending on the type of Answer the Data field must be decoded differently. For example if the Answer is an A record (Type 1) the data is simply an ipv4 address. However if the Answer is an SRV record (Type 33) then the data is contains port, priority, weight and target encoded in the byte slice.
I thought it would be great if I could have a method on Answer called DecodeData() that returns the correct data depending on the type, however since there is no overriding or inheritance in Go I am unsure how to solve this. I tried using an interface to solve this, but it would not compile. I tried something like
type DNSRecordType interface {
Decode(data []byte)
}
type RecordTypeSRV struct {
target string
...more fields
}
//to 'implement' the DNSRecordType interface
func (record *RecordTypeSRV) Decode(data []byte) {
//do the work to decode appropriately and set
//the fields on the record
}
Then in the Answer method
func (a *Answer) DecodeData() DNSRecordType {
if a.Type === SRVType {
record := RecordTypeSRV{}
record.Decode(a.Data)
return record
}
//do something similar for other record types
}
What would be the correct Go way of having a single Answer type, but be able to return different types of Answer Data depending on their type?
Sorry, if this is a completely beginner question as I am still very new to Go.
Thanks!
Let me summarize your question.
You have a DNS Packet with the list of Answers. Based on the type of answer you have to process the data in the answer.
type DNSPacket struct {
...some fields
Questions []Question
Answers []Answer
...some more fields
}
type Answer struct {
Name string
Type int
Class int
TTL uint32
RdLength int
Data []byte
}
Answer
Let's create an interface that should be implemented to process data.
type PacketProcessor interface {
Process(Answer)
}
Let SRV implements the PacketProcessor
type SRV struct {
...
}
func (s *SRV) Process(a Answer) {
...
}
Your processing logic should be as follows
func (a *Answer) Process() {
var p PacketProcessor
switch a.Type {
case SRVType:
p = &SRV{}
...
//other cases
}
//finally
p.Process(*a)
}
Hope it helps :).
There is a Gurgaon based golang community that is always ready to help developers with their problems.
You can join the community via slack
As I know, to return different types, the return param must be an interface. So you can simply declare the function like this:
func (a *Answer) DecodeData() (mode modeType, value interface{}) {}
mode means the value is A record or SRV record, and you can return anything you want with the value field.
The function caller can handle the value depending on mode
If you want the code be more elegant, you can define different value structs for each mode. Then the caller may act as below:
type modeType int
const (
ARecord modeType = 1
SRVRecord modeType = 2
)
switch mode {
case ARecord:
// do something
case SRVRecord:
// do something
}

Subtypes Supertypes in go

Coming from OOP paradigms and porting a code from an OOP language, I come across a problem now which is solved in OOP via abstraction so I'm wondering how can I approach the following problem in Go which follows composition instead of inheritance.
In this scenario my ValueObjects (DTO, POJO etc.) are composed of other ValueObjects. I'm populating them through web service calls that returns json so basically my functions/method calls are common for all types and subtypes.
My super type EntityVO
type EntityVO struct {
EntityName string
EntityType string
PublicationId string
Version string
}
A subtype 1 composed with EntityVO
type ArticleVO struct {
EntityVO
ContentSize string
Created string
}
subtype 2 composed with EntityVO with it's own unique set of fields
type CollectionVO struct {
EntityVO
ProductId string
Position string
}
I'm calling web services to retrieve data and populate these VOs.
Earlier I had one function to call the web service and populate the data but now I'm duplicating the code for each VO.
type Article struct{}
func (a *Article) RequestList(articleVO *valueObject.ArticleVO) (*valueObject.ArticleVO, error) {
// some code
}
Duplicating the same code but changing the signature.
type Collection struct{}
func (c * Collection) RequestList(collectionVO *valueObject.CollectionVO) (*valueObject.ArticleVO, error) {
// some code - duplicate same as above except method signature
}
and I've several entities and just because my VO's are different I'm forced to duplicate the code and cater to each type of VO I've. In OOP sub types can be passed to a function accepting super types but not in go, so wondering how it should be done so I don't end up duplicated code that's different in signature only?
Any advice for a better approach in this kind of scenario?
This is where golang interfaces can shine.
It's worth noting, however, that it's difficult to write subclass/inheritance code in golang. We'd prefer thinking of it as composition.
type EntityVO interface {
GetName() string
SetName(string) error
GetType() string
...
}
type EntityVOImpl struct {
EntityName string
EntityType string
PublicationId string
Version string
}
func (e EntityVOImpl) GetName() string {
return e.EntityName
}
...
type ArticleVOImpl struct {
EntityVOImpl
ContentSize string
Created string
}
type CollectionVOImpl struct {
EntityVO
ProductId string
Position string
}
// CODE
func (e *Entity) RequestList(entityVO valueObject.EntityVO) (valueObject.EntityVO, error) {
// some code
}
In addition, as long as your interface files are shared, I don't think there should by any problem sending/marshalling/unmarshalling the structs over the wire.
The second parameter of json.Unmarshal is a "universal" interface{} type. I think similar approach is applicable to your case.
Define data type for storing web service properties which may differ for each entity, e.g.
type ServiceDescriptor struct {
URI string
//other field/properties...
}
Function for populating the entity may look like
func RequestList(desc *ServiceDescriptor, v interface{}) error {
//Retrieve json data from web service
//some code
return json.Unmarshal(data, v)
}
You can call the function to populate different type of entities, e.g.
desc := &ServiceDescriptor{}
article := ArticleVO{}
desc.URI = "article.uri"
//...
//You must pass pointer to entity for 2nd param
RequestList(desc, &article)
collection := CollectionVO{}
desc.URI = "collection.uri"
//...
//You must pass pointer to entity for 2nd param
RequestList(desc, &collection)

When avoiding global vars (/state), i find myself linking objects backwards to its parent. Am I doing this right? if not explain why? and how-else?

Note: Im just picking the current struct/example to explain the problem.
type MsgBoxFactory struct{
db *dbSql //contains conn-pool and other DB related settings/flags
}
func (f *MsgBoxFactory) NewMsgBox(userId string) {
return MsgBox{userId, f.db} //f.db link is inevitable
}
type MsgBox struct {
ownerId string
db *dbSql
}
func (m *MsgBox) NewMessage(content string) *Message {
return Message{content, *m.dbSql} //m.dbSql link is inevitable
}
type Message struct {
content string
//other fields such as recipents, isRead, created time etc.
db *dbSql
}
func (m *Message) Send(to string) {
message.to = to //just imagine this saves the message to database.
m.db.Save(message)
}
I tend to call this "backward-referencing"[i don't know actual name]... Is this the only way? Previously i was "backward-referencing" entire parent objects. Now i find myself "backward-referencing" objects such as config/dbconn etc...
Is this a good way? what is better?
Oh i have also tried closure to get rid of it atleast from view.
type Message Struct{
content string
Send func(string) error // the problem is `json:"-"` needs to be added. Else the objects are not json compatible
}
func (m *MsgBox) NewMsg(content string) *Message {
msg := &Message{ content }
msg.Send = func(to string) error {
return m.db.Save(msg)
}
}
Basically the code looks almost equally cluttered with unnecessary complexity/code
EDIT: The question is not specific to go. Just posted it because i use go. Any tag suggestion is appreciated to open the question for wider community.
I usually implement a model helper relationship.
Where MsgBox is your model which has all the data specific elements (No DB related elements).
The MsgBoxHelper does all your database related work.
(i.e.
err := MsgBoxHelper.Save(MsgBox)
msgBox, err := MsgBoxHelper.Load(Key)
)
Edit:
The advantage with this method is it decouples your Model from the datastore, which should inturn make it easier should you wish to change your underlying technology (Which doesn't often happen). In practice it's more useful should you start doing things like caching.
If generically you are referencing other structures within your model i.e.
type MsgBox struct {
Colour *MsgBoxColour
...
}
type MsgBoxColor struct {
ID int
...
}
then when you load the Model in your MsgBoxHelper you call the MsgBoxColourHelper with the ID you stored in the MsgBoxColour table, this then returns your MsgBoxColour that you then associate with the returning MsgBox.

Resources